在代码中有一些特殊的类,并且有一些普通的类。我想区分它们,因为特殊的类需要给予不同的处理。所有这些特殊类都是基础(不是任何其他类的孩子)
为了实现这一点,我通过向空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
添加类似继承的接口,是否会以任何方式伤害当前代码(例如,对象结构,编译错误)等)?
答案 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继承的类一样模棱两可。