【问题标题】:Does extra inheritance make any difference on object structure or instantiation?额外的继承对对象结构或实例化有什么影响吗?
【发布时间】:2011-12-03 20:54:59
【问题描述】:

在代码中有一些特殊的类,也有一些普通的类。我想将它们区分开来,因为特殊课程需要给予不同的待遇。所有这些特殊类都是基类(不是任何其他类的子类)

为了实现这一点,我在源代码中标记了特殊的classes,方法是使用空的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的孩子继承自多个类,那么typedefs就会有歧义。

问题:添加这样的接口,比如使用空class _special 继承,它会以任何方式伤害当前代码(例如对象结构、编译错误等)吗? ) ?

【问题讨论】:

    标签: c++ inheritance object-layout


    【解决方案1】:

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

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

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

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

    【讨论】:

      【解决方案2】:

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

      就个人而言,我会在外部实施这种分类。模板特化不会得到从 special 派生的类的期望结果,也间接被认为是特殊的。看起来您使用的是 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 )。您可以将该分类检查包装在帮助程序类模板中。

      【讨论】:

      • 很好的答案,但是我没有使用 C++11。
      • @iammilind:你仍然可以使用类型特征 :)
      • @iammilind:现在也包括 C++03 解决方案。
      【解决方案3】:

      不确定您对 hurtobject structuring 的含义(需要详细说明吗?),但应该没有编译器错误,类的实例化/构造函数源自_special 不会改变,因为 _special 有一个默认构造函数,并且编译器可能会应用空基类优化。

      话虽如此,使用 typedef 来标记类的选项可能是一个更好、更清晰、更可扩展的解决方案。就像 A 的孩子继承了多个其他类一样模棱两可,这些类都可能继承自 _special。

      【讨论】:

        猜你喜欢
        • 2020-04-16
        • 1970-01-01
        • 2014-08-02
        • 2015-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多