- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
假设我有一个 MyClass 类,我想在其中添加某些“观察者”行为。然后我可以这样定义类:
class MyClass : public IObserver
{
...
};
现在假设这个“观察者”功能与类没有直接关系,但与存储在类中的数据成员有关。例如。数据成员指向另一个类 OtherClass,如果它引用的实例被删除,则需要将其设置为 NULL:
class PointerToOtherClass : public IObserver
{
...
};
class MyClass
{
private:
PointerToOtherClass m_ptr;
};
在这种情况下,我们甚至可以使用智能指针来编写更简单的代码。
现在假设如果 OtherClass 实例被删除,我们不只是将指针指向 NULL,我们还想删除 MyClass。因此,让 PointerToOtherClass 成为观察者已经不够了,MyClass 也应该成为观察者。但是,这意味着数据成员 m_ptr 不能自己实现全部功能(改变它的值),还需要在父类中放置一些功能。
解决方案可能是将指向 MyClass 的指针传递给 PointerToOtherClass 成员。如果 MyClass 然后实现观察者,则可以通过 PointerToOtherClass 实例轻松完成“注册”和“注销”MyClass 观察者的操作。
template <typename ParentType>
class PointerToOtherClass
{
public:
PointerToOtherClass(ParentType *parent) : m_parent(parent) {}
void setValue (OtherClass *c) { /* unregister/register m_parent */ }
private:
ParentType *m_parent;
};
class MyClass : public IObserver
{
public:
MyClass() : m_ptr(this) {}
private:
PointerToOtherClass m_ptr;
};
虽然这可以正常工作并且可以概括为一种智能指针,但我们牺牲了 4 个字节(32 位环境),因为数据成员需要指向其父级。这看起来并不多,但如果应用程序中有数百万个 MyClass 实例,并且 MyClass 有十个或更多这样的数据成员,这可能会很大。
因为 m_ptr 是 MyClass 的成员,看起来应该可以从指向 m_ptr 的指针开始获取指向 MyClass 的指针。或者,换句话说:PointerToOtherClass 中的方法应该能够通过减去 MyClass 中 m_ptr 的偏移量将其“this”指针转换为指向 MyClass 的指针。
这让我产生了以模板化方式编写此代码的想法。在以下代码中,模板化的 HostAwareField 模板类通过减去作为模板参数传递的偏移量来访问其父级:
#include <iostream>
typedef unsigned char Byte;
template <typename ParentType,size_t offset>
class HostAwareField
{
public:
ParentType *getParent() const {return (ParentType *)(((Byte *)this)-offset);}
void printParent() {std::cout << "Parent=" << getParent()->m_name << std::endl;}
};
class X
{
public:
X (char *name) : m_name(name) {}
char *m_name;
HostAwareField<X,offsetof(X,m_one)> m_one;
};
void main()
{
std::cout << "X::m_one: offset=" << offsetof(X,m_one) << std::endl;
X x1("Ross");
X x2("Chandler");
X x3("Joey");
x1.m_one.printParent();
x2.m_one.printParent();
x3.m_one.printParent();
}
但是,这不会编译。它报告以下错误:
test.cpp(18) : error C2027: use of undefined type 'X'
test.cpp(14) : see declaration of 'X'
test.cpp(18) : error C2227: left of '->m_one' must point to class/struct/union/generic type
test.cpp(16) : error C2512: 'HostAwareField' : no appropriate default constructor available
test.cpp(26) : error C2039: 'm_two' : is not a member of 'X'
test.cpp(14) : see declaration of 'X'
test.cpp(32) : error C2662: 'HostAwareField<ParentType,offset>::printParent' : cannot convert 'this' pointer from 'HostAwareField' to 'HostAwareField<ParentType,offset> &'
Reason: cannot convert from 'HostAwareField' to 'HostAwareField<ParentType,offset>'
Conversion requires a second user-defined-conversion operator or constructor
test.cpp(33) : error C2662: 'HostAwareField<ParentType,offset>::printParent' : cannot convert 'this' pointer from 'HostAwareField' to 'HostAwareField<ParentType,offset> &'
Reason: cannot convert from 'HostAwareField' to 'HostAwareField<ParentType,offset>'
Conversion requires a second user-defined-conversion operator or constructor
test.cpp(34) : error C2662: 'HostAwareField<ParentType,offset>::printParent' : cannot convert 'this' pointer from 'HostAwareField' to 'HostAwareField<ParentType,offset> &'
Reason: cannot convert from 'HostAwareField' to 'HostAwareField<ParentType,offset>'
Conversion requires a second user-defined-conversion operator or constructor
test.cpp(36) : error C2039: 'm_two' : is not a member of 'X'
test.cpp(14) : see declaration of 'X'
test.cpp(36) : error C2228: left of '.printParent' must have class/struct/union
test.cpp(37) : error C2039: 'm_two' : is not a member of 'X'
test.cpp(14) : see declaration of 'X'
test.cpp(37) : error C2228: left of '.printParent' must have class/struct/union
test.cpp(38) : error C2039: 'm_two' : is not a member of 'X'
test.cpp(14) : see declaration of 'X'
test.cpp(38) : error C2228: left of '.printParent' must have class/struct/union
如果我更改以下行:
HostAwareField<X,offsetof(X,m_one)> m_one;
到这一行:
HostAwareField<X,4> m_one;
然后这段代码可以正常工作,但需要我手动“计算”偏移量,如果添加、删除或重组数据成员可能会导致错误。
这意味着虽然我不能自动执行此操作,但我可以硬编码偏移量(如上面的值 4)并随后执行检查(以查看 4 是否真的是类中 m_one 的偏移量),但这需要额外的人工检查,使整个系统不防水。
有没有办法让上面的源代码正确编译?还是有其他技巧可以实现我想做的事情?
最佳答案
我认为必须在 offsetof
之前完全声明成员可用于确定其偏移量。这是有道理的,因为由于字节对齐规则,成员的类型会影响其偏移量。 (实际上可能也必须先声明整个类。)
在HostAwareField<X,offsetof(X,m_one)> m_one;
类型需要 offsetof
在它可以完全宣布之前工作。但是offsetof
需要声明类型才能工作。我认为没有任何方法可以进行编译。
顺便说一下,我想不出对这个设计有任何简单的修改,可以让它在每个成员不需要额外字节的情况下工作,这当然会破坏既定的目的。
也许您可以修改整体设计,使封闭类成为观察者。然后让它分派(dispatch)给适当的成员并检查某种返回值以确定它是否需要取消注册或对封闭类执行任何必要的操作。
关于c++ - 在不牺牲内存的情况下获取数据成员的 'parent' 或 'host' 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3759895/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!