c++ - 通过使用虚拟继承避免内存开销

标签 c++ inheritance virtual-inheritance

以下代码旨在为我的库提供有关用户类派生自的基类的反射信息:

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 the data1 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/

相关文章:

c# - 如何通过 lpEnvironment 在 C# 中调用 CreateProcess()

c++ - C++11下C函数的错误代码?

c++ - 从 child 那里获取变量

c++ - 这是对具有 C++ 继承层次结构的 namespace 的合理使用吗?

c++ - 使用虚拟继承时强制调用基本构造函数,尽管它永远不会被调用?

c++ - MSVC 相当于 __attribute__ ((warn_unused_result))?

c++ - 未找到 boost/lexical_cast.hpp

c++ - 如何强制派生类比较

c++ - 构造函数尝试调用拷贝构造函数,虚继承

c++ - 解决 C++ 中不明确的 this 指针