以下代码旨在为我的库提供有关用户类派生自的基类的反射信息:
template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
class Base4_ = void>
struct ManagedNode;
// For classes that do not derive
template <> struct ManagedNode<void, void, void, void> {
using Base1 = void; using Base2 = void; using Base3 = void;
using Base4 = void;
};
// To avoid inaccessible base
// See http://stackoverflow.com/q/34255802/2725810
struct Inter0: public ManagedNode<>{};
// For classes that derive from a single base class
template <class Base1_>
struct ManagedNode<Base1_, void, void, void> : public Inter0,
public Base1_ {
using Base1 = Base1_;
};
// To avoid inaccessible base
template <class Base1_>
struct Inter1: public ManagedNode<Base1_>{};
// For classes that derive from two base classes
template <class Base1_, class Base2_>
struct ManagedNode<Base1_, Base2_, void, void> : public Inter1<Base1_>,
public Base2_ {
using Base2 = Base2_;
};
// We can continue in the same manner for 3 and 4 base classes
这是一个示例用户代码:
struct A : public ManagedNode<> {
int data1;
};
struct B : public ManagedNode<> {};
struct C : public ManagedNode<A, B> {};
int main() {
C c;
std::cout << sizeof(c) << std::endl;
return 0;
}
这段代码产生12的输出,这意味着c
包含三次data1
成员!
我考虑过使用虚拟继承来避免这种内存开销。如果我简单地在每个继承的 public
之前插入 virtual
这个词,那么我会收到关于基类变得不可访问的警告......如果我把这个词 virtual
在每个这样的地方除了 Inter0
的声明,然后我得到 16 的输出——比以前更糟!
如果您能解释一下我在这里使用虚拟继承时会发生什么,我将不胜感激。
编辑:为了完整起见,这里是插入了 virtual
的版本(注释指出需要删除哪个 virtual
才能使代码生效)编译):
template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
class Base4_ = void>
struct ManagedNode;
// For classes that do not derive
template <> struct ManagedNode<void, void, void, void> {
using Base1 = void; using Base2 = void; using Base3 = void;
using Base4 = void;
};
// To avoid inaccessible base
// See http://stackoverflow.com/q/34255802/2725810
struct Inter0: virtual public ManagedNode<>{}; // without the word virtual
// in this line, the code compiles
// For classes that derive from a single base class
template <class Base1_>
struct ManagedNode<Base1_, void, void, void> : virtual public Inter0,
virtual public Base1_ {
using Base1 = Base1_;
};
// To avoid inaccessible base
template <class Base1_>
struct Inter1: virtual public ManagedNode<Base1_>{};
// For classes that derive from two base classes
template <class Base1_, class Base2_>
struct ManagedNode<Base1_, Base2_, void, void> : virtual public Inter1<Base1_>,
virtual public Base2_ {
using Base2 = Base2_;
};
// Some user classes for testing the concept
struct A : public ManagedNode<> {
int data1;
};
struct B : public ManagedNode<> {};
struct C : public ManagedNode<A, B> {};
int main() {
C c;
std::cout << sizeof(c) << std::endl;
return 0;
}
这是编译器的输出:
temp.cpp: In instantiation of ‘struct ManagedNode<A, void, void, void>’:
temp.cpp:27:8: required from ‘struct Inter1<A>’
temp.cpp:31:8: required from ‘struct ManagedNode<A, B>’
temp.cpp:44:19: required from here
temp.cpp:21:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘ManagedNode<A, void, void, void>’ due to ambiguity [-Werror=extra]
struct ManagedNode<Base1_, void, void, void> : virtual public Inter0,
^
temp.cpp: In instantiation of ‘struct Inter1<A>’:
temp.cpp:31:8: required from ‘struct ManagedNode<A, B>’
temp.cpp:44:19: required from here
temp.cpp:27:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘Inter1<A>’ due to ambiguity [-Werror=extra]
struct Inter1: virtual public ManagedNode<Base1_>{};
^
temp.cpp: In instantiation of ‘struct ManagedNode<A, B>’:
temp.cpp:44:19: required from here
temp.cpp:31:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘ManagedNode<A, B>’ due to ambiguity [-Werror=extra]
struct ManagedNode<Base1_, Base2_, void, void> : virtual public Inter1<Base1_>,
^
temp.cpp:44:8: error: virtual base ‘ManagedNode<void, void, void, void>’ inaccessible in ‘C’ due to ambiguity [-Werror=extra]
struct C : public ManagedNode<A, B> {};
^
最佳答案
which means that
C
contains thedata1
member three times!
C
不是这个原因比预期的要大。
问题是你所有的类都继承自ManagedNode<>
因此,由于每个对象必须具有唯一的地址和类型组合,因此在最终结构中添加了一个偏移量。
布局 C:
- 0x00: ManagedNode<> // From Inter0
- 0x04: ManagedNode<> // From A
- 0x04: int // From A
- 0x08: ManagedNode<> // From B
备注:ManagedNode<>
是空的。
关于c++ - 通过使用虚拟继承避免内存开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34257082/