额外的继承对对象结构或实例化有什么影响吗?
代码中有一些特殊的类,也有一些普通的类。我想对他们进行区分,因为特殊的班级需要给予不同的待遇。所有这些特殊类都是基类(不是任何其他类的子类)
为了实现这一点,我通过使用空的结构体插入继承来标记源代码中的特殊类。 >:
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
。另一种方法是在特殊类中使用 typedef
:
class A {
public: typedef something _special;
};
问题是,如果 A
的子级继承自多个类,那么将会出现不明确的 typedef 。
问题:添加诸如带有空class _special
的继承之类的接口,是否会以任何方式伤害当前代码(例如对象结构、编译)错误等)?
In the code there are some special classes and there are some normal classes. I want to differentiate them because special classes needed to be given different treatment. All these special classes are base (not child of any other class)
To achieve that I am tokenizing special class
es in the source code by inserting an inheritance to them with an empty 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'
...
};
Whenever needed, I can find segregate special and normal classes using is_base_of<Base,Derived>
. The alternate way would have been of using typedef
inside the special classes:
class A {
public: typedef something _special;
};
The problem is that if A
's child are inheriting from multiple classes then there will be ambiguous typedef
s.
Question: With adding such interface like inheritance with empty class _special
, will it it hurt the current code in any way (e.g. object structuring, compilation error etc.) ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
C++ 标准中仅部分指定了内存中对象的布局,但大多数编译器都使用某些约定。空类型将占用一点内存(这样它们就有一个内存地址来标识它们的指针)。这个额外的内存位通常只有四个字节,对于大多数用途来说无需担心。另一方面,如果您从空类型继承,则它不应该增加对象的大小,因为对象的其余部分将占用空间,因此无论如何它都会有一个地址。
如果您使用单继承,对象将像第一个基类一样布置第一位内存,然后是用于保存链中后续类的成员的内存。如果您有任何虚拟函数,那么也可能会有一个位置(可能在开头)用于虚拟指针。如果要从一种类型派生另一种类型,通常需要遵循“三规则”:虚拟析构函数、复制构造函数和复制赋值运算符。那么你就会有一个虚拟指针,同样这可能是 4 个字节,没什么大不了的。
如果您进入多重继承,那么您的对象在结构上开始变得非常复杂。它们将有各种指向自身不同部分的指针,以便函数可以找到它们正在寻找的成员。
也就是说,请考虑是否要使用继承来对此进行建模。也许给对象一个 bool 成员变量是一个好主意。
The layout of objects in memory is only partially specified in the C++ standard however there are certain conventions that most compilers use. Empty types will take up a little bit of memory (so that they will have a memory address which will give their pointers identity). This extra bit of memory is generally just four bytes, nothing to worry about for most purposes. If you inherit from an empty type on the other hand it shouldn't increase the size of your object because the rest of the object will be taking up space so it will have an address anyway.
If you are using single inheritance objects will be laid out with the first bit of memory being laid out like the first base class, and then the memory to hold the members of later classes in the chain. If you have any virtual functions there will also be a place, probably at the beginning, for the virtual pointer. If you are deriving one type from another you will generally want to follow the "rule of three": a virtual destructor, copy constructor, and copy assignment operator. So then you will have a virtual pointer, again this is probably 4 bytes, not a big deal.
If you get into multiple inheritance then your objects start to get very complicated structurally. They will have various pointers to different parts of themselves so that functions can find the members that they are looking for.
That said, consider whether you want to use inheritance to model this at all. Perhaps giving the objects a bool member variable would be a good idea.
大多数(如果不是全部)好的编译器都会针对简单情况实现空基优化(EBO),这意味着您的对象大小不会通过从空基继承而增加。然而,当一个类以多种方式从空基继承时,由于同一类型的不同空基需要不同的地址,优化可能是不可能的。为了防止这种情况发生,通常将空基类作为模板,将派生类作为参数,但这会使 is_base_of 变得不可用。
就我个人而言,我会在外部实施这种分类。模板专业化也不会获得从特殊间接派生的类也被认为是特殊的所需结果。看起来您正在使用 C++11,所以我会这样做:
并将
is_base_of
替换为decltype( is_special( static_cast(0) ) )< /代码>。在 C++03 中,通过让分类函数返回不同大小的类型,可以使用
sizeof
技巧来实现相同的效果:并将
is_base_of
替换为sizeof( is_special( static_cast(0) ) ) == sizeof( yes_type )
。您可以将该分类检查包装在辅助类模板中。Most if not all decent compilers implement Empty Base Optimization (EBO) for simple cases, which means that your object sizes won't grow by inheriting from an empty base. However when a class inherits from an empty base in more than one way the optimization may be impossible due to the need to have different addresses for the different empty bases of the same type. To protect against that, one usually makes the empty base a template taking the derived class as an argument, but it would render
is_base_of
unusable.Personally, I would implement this classification externally. Template specialization won't get the desired result of classes derived from special indirectly being considered special as well. It looks like you are using C++11 so I would do:
And replace
is_base_of<T, _special>
withdecltype( is_special( static_cast<T*>(0) ) )
. In C++03 the same can be achieved with thesizeof
trick by having the classification function return types of different sizes:And replace
is_base_of<T, _special>
withsizeof( is_special( static_cast<T*>(0) ) ) == sizeof( yes_type )
. You could wrap that classification check within a helper class template.不确定你的意思是伤害或对象结构(想详细说明吗?),但不应该有编译器错误,从 _special 派生的类的实例化/构造函数不会由于 _special 有一个默认构造函数,并且从性能角度来看,编译器可能会应用空基类优化。
话虽这么说,使用 typedef 来标记类的选项可能是更好、更清晰且更可扩展的解决方案。就像 A 的子级继承多个其他类一样不明确,而这些类都可能继承自 _special。
not sure what you mean with hurt or object structuring (care to elaborate?), but there should be no compiler errors, instantiation/constructor of the classed deriving from _special does not change since _special has a default constructor and perfomance-wise the compiler might apply empty base class optimization.
That being said, the option of using typedefs to tag classes might be a better, clearer and more extendible solution. And just as ambiguous as A's children inheriting form multiple other classes that all might inherit from _special.