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 t开发者_如何学运维here 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.) ?
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.
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:
std::false_type is_special( ... );
std::true_type is_special( A const* );
And replace is_base_of<T, _special>
with decltype( is_special( static_cast<T*>(0) ) )
. In C++03 the same can be achieved with the sizeof
trick by having the classification function return types of different sizes:
typedef char no_type;
struct yes_type { no_type _[2]; };
no_type is_special( ... );
yes_type is_special( A const* );
And replace is_base_of<T, _special>
with sizeof( is_special( static_cast<T*>(0) ) ) == sizeof( yes_type )
. You could wrap that classification check within a helper class template.
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.
精彩评论