在编译时确定最大的派生类

Mat*_*t K 6 c++ inheritance

假设我有一个BaseN孩子的班级Derived0, Derived1, ... ,DerivedN.我正在尝试为继承的对象创建池分配器Base,并且实现依赖于知道最大子节点的大小Base,因为每个池都足够大以包含其中一个对象.这是一个简单的例子,包含琐碎的类和N = 2.实际上,N可能更大,而且Base孩子可能不是简单的POD课程.

class Base {
public:
    virtual ~Base() = 0;
};

class Derived0 : public Base {
    int a;
};

class Derived1 : public Base {
    int a, b;
};

class Derived2 : public Base {
    int a, b, c;
};
Run Code Online (Sandbox Code Playgroud)

所以我想说我想创建一个足够大的缓冲区来存储10个孩子.我一直在敲打这个问题一段时间,这就是我能想到的:

static const size_t NUMBER_OF_POOLS = 10;

static const size_t LARGEST_CHILD_SIZE =
    sizeof(Derived0) > sizeof(Derived1) ?
        sizeof(Derived0) > sizeof(Derived2) ?
            sizeof(Derived0) :
            sizeof(Derived2) :
        sizeof(Derived1) > sizeof(Derived2) ?
            sizeof(Derived1) :
            sizeof(Derived2);

char buffer[NUMBER_OF_POOLS * LARGEST_CHILD_SIZE];
Run Code Online (Sandbox Code Playgroud)

这很有效,但很容易看出随着N开始增长它会变得多么混乱.有没有任何可扩展的方法来实现这一点,你不需要手动构建一个嵌套的"一元树"(因为缺少一个更好的术语),随着增加而变成一个巨大的混乱N

以下是我正在使用的约束/环境:

  • 必须在编译时知道最大子项的大小.
  • C++ 03兼容性是必要的.为了好奇,我对任何建议(C++ 11欢迎!)感兴趣,但我最终会在没有C++ 11支持的编译器上构建它.我知道C++ 11增加了对非POD成员的联合的支持,所以我想你可能能够使用它来清理界面.
  • 这只能使用GCC构建,因此GCC扩展在技术上是一种选择.

任何帮助/建议表示赞赏.

Chr*_*phe 3

您可以考虑使用 aboost::variant并获取其大小:

    sizeof (boost::variant< Derived0, Derived1, Derived2 > )  
Run Code Online (Sandbox Code Playgroud)

这将返回最大元素的大小。

顺便说一句,它还可以简化缓冲区管理,方法是使其成为此变体的缓冲区,并直接索引正确的元素。好消息是 boost 可以满足对齐要求:

    typedef boost::variant< Derived0, Derived1, Derived2 > DerivedVar; 
    DerivedVar buffer[NUMBER_OF_POOLS];  
Run Code Online (Sandbox Code Playgroud)

  • 我在回复 @gomons 时提到了这一点,但如果类不是 POD 类型,则联合将无法在 C++03 中工作。我对在示例中使用 POD 类型感到愚蠢,但我也需要支持非 POD 类的方法。此简介来自 cppreference: _Unions 不能包含具有非平凡特殊成员函数(复制构造函数、复制赋值运算符或析构函数)的非静态数据成员。_ 这只提到了那些“特殊”函数,但任何联合成员根据 C++03 标准进行编译时,使用非默认构造函数将无法在 GCC 4.9.2 中进行编译。 (2认同)