gpt4 book ai didi

c++ - 在不牺牲内存的情况下获取数据成员的 'parent' 或 'host' 类

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:36:17 24 4
gpt4 key购买 nike

假设我有一个 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com