额外的继承是否会对对象结构或实例化产生任何影响?

时间:2011-10-09 08:07:38

标签: c++ inheritance object-layout

在代码中有一些特殊的类,并且有一些普通的类。我想区分它们,因为特殊的类需要给予不同的处理。所有这些特殊类都是基础(不是任何其他类的孩子)

为了实现这一点,我通过向空class插入一个继承来对源代码中的特殊struct进行标记:

struct _special {};  // empty class
class A : public _special {  // A becomes special
...
};
class B {  // 'B' remains normal
...
};
class D : public A {  // 'D' becomes special due to 'A'
...
};

无论何时需要,我都可以使用is_base_of<Base,Derived>找到隔离特殊类和普通类。另一种方法是在特殊类中使用typedef

class A {
  public: typedef something _special;
};

问题是如果A的孩子从多个班级继承,那么typedef会有歧义。

问题:通过使用空class _special添加类似继承的接口,是否会以任何方式伤害当前代码(例如,对象结构,编译错误)等)?

3 个答案:

答案 0 :(得分:3)

大多数(如果不是所有)正常的编译器都会针对简单情况实现空基优化(EBO),这意味着您的对象大小不会通过继承空基来增长。然而,当一个类以多种方式从空基继承时,由于需要为相同类型的不同空基提供不同的地址,所以优化可能是不可能的。为了防止这种情况,通常会将空基类作为模板,将派生类作为参数,但它会使is_base_of无法使用。

就个人而言,我会在外部实施这种分类。模板特化不会获得从特殊间接被认为是特殊的类派生的所需结果。看起来你正在使用C ++ 11所以我会这样做:

std::false_type is_special( ... );
std::true_type is_special( A const* );

is_base_of<T, _special>替换为decltype( is_special( static_cast<T*>(0) ) )。在C ++ 03中,通过使用分类函数返回不同大小的类型,可以使用sizeof技巧实现相同的目的:

typedef char no_type;
struct yes_type { no_type _[2]; };

no_type is_special( ... );
yes_type is_special( A const* );

is_base_of<T, _special>替换为sizeof( is_special( static_cast<T*>(0) ) ) == sizeof( yes_type )。您可以在辅助类模板中包装该分类检查。

答案 1 :(得分:3)

内存中对象的布局仅在C ++标准中有部分规定,但大多数编译器都使用某些约定。空类型会占用一点内存(因此它们将有一个内存地址,可以提供它们的指针标识)。这个额外的内存通常只有四个字节,大多数情况下无需担心。另一方面,如果从一个空类型继承它,它不应该增加对象的大小,因为对象的其余部分将占用空间,所以它无论如何都会有一个地址。

如果您正在使用单个继承对象,则将使用第一个内存布局布局,就像第一个基类一样,然后使用内存来保存链中后续类的成员。如果你有任何虚函数,那么虚拟指针也可能在一开始就有一个位置。如果从另一个类型派生一种类型,通常需要遵循“三规则”:虚拟析构函数,复制构造函数和复制赋值运算符。那么你将有一个虚拟指针,这可能是4个字节,不是什么大不了的事。

如果你进入多重继承,那么你的对象在结构上开始变得非常复杂。他们将有各种指针指向自己的不同部分,以便函数可以找到他们正在寻找的成员。

那就是说,考虑是否要使用继承对其进行建模。也许给对象一个bool成员变量是一个好主意。

答案 2 :(得分:0)

不确定你对伤害对象结构的意思(注意详细说明?),但是应该没有编译错误,类的实例化/构造函数派生自_special不会更改,因为_special具有默认构造函数,并且性能方面编译器可能会应用空基类优化。

话虽这么说,使用typedef标记类的选项可能是更好,更清晰和更可扩展的解决方案。就像A的孩子继承形式多个其他所有可能都从_special继承的类一样模棱两可。