TypeID for derived classes of a common base class

I am trying to implement some mechanism in C ++, in which all classes derived from a common base class are assigned a unique "class identifier". For example:

class BaseClass { //... public: unsigned int GetID( void ); //... }; class DerivedClass : public BaseClass { } 

The DerivedClass class and all other BaseClass child elements should be able to return unique identifiers without adding extra code to DerivedClass ... However, C ++ makes this pretty complicated for me. Any ideas would be appreciated.

Thanks in advance! --- Dan

+6
c ++ types
source share
4 answers

You do not indicate that you are familiar with typeid and dynamic_cast .

Most likely they will solve your problem.

If not, please describe the reason why not.

Cheers and hth.,

+2
source share

You should listen to Alf :) Here is my analysis: in a pure world, the identification of implementations threatens the polymorphism of virtual functions, it cannot and is not required.

In the dirty world of real programming, you may have some reasons for unique identification, such as marching data to disk, identifying diagnostic messages, monitoring control flow, collecting usage statistics, etc.

If your thoughts are clear, your design is wrong. Go away and find out why you cannot claim a unique identifier.

If your thoughts are distorted by reality, then you are ready to pay the price in performance and memory to meet your requirements, and then, according to the specification, using the built-in language features is worth paying, as this is largely the only way to achieve your goal of providing a non-invasive identification service. By non-invasive, I mean that you do not need to add anything to each derived class. Obviously, you need to add something, so if you do not want to do this, you have little choice but to accept what the compiler adds for you.

The main problem is that if you use dynamically loaded shared libraries (DLLS), RTTI may not work as expected. This not only affects typeid adversely, but it can also hinder the exception traps that you expect to receive (I was bitten!). Some help may be required to ensure that vtables and other RTTIs are uniquely created. This may mean, for example, that if the vtables binding to your destructor is not built-in, because in this case it can be generated in more than one place, which will destroy the uniqueness. Some hacks may be needed here in the absence of support for ISO standardization for dynamic loading.

+2
source share

As Alf says, this is not necessary. typeid already gives a unique class identifier, although the identifier is not an integer. Just for laughs, if I am allowed to soften the condition "common base class", then:

 inline unsigned int counter() { static unsigned int count = 0; return ++count; } struct BaseClass { virtual unsigned int GetID() = 0; virtual ~BaseClass() {} }; template <typename D> struct IntermediateClass : BaseClass { virtual unsigned int GetID() { static unsigned int thisid = counter(); return thisid; } }; // usage struct Derived : IntermediateClass<Derived> { ... }; 

You need to add thread safety to counter if it will be used in multi-threaded programs.

Obviously, the identifier is only unique within a given program run.

It gets a little hairy if the inheritance hierarchy is very deep, and if you have many constructors with different signatures for different classes, because you need to insert an IntermediateClass between each derived class and its direct base class. But you can always get rid of all this:

 inline unsigned int counter() { static unsigned int count = 0; return ++count; } struct BaseClass { virtual unsigned int GetID() = 0; virtual ~BaseClass() {} }; template <typename D> unsigned int ThisID(const D *) { static unsigned int thisid = counter(); return thisid; } // usage struct Derived : BaseClass { // this single line pasted in each derived class virtual unsigned int GetID() { return ThisID(this); } ... }; 

I assume that there is an “opportunity” for a new language function: a virtual function that is defined in the base class as a template function with one template parameter “typename” and which is automatically overridden in each derived class, using the template argument. Imaginary syntax as virtual template functions are illegal:

 struct BaseClass { template <typename Derived> virtual unsigned int GetID() { static unsigned int thisid = counter(); return thisid; } virtual ~BaseClass() {} }; 

It is difficult to justify a language attribute based on the desire to re-implement RTTI, um ...

+1
source share

This requires modification of derived classes, but if distrust of RTTI is the only reason to avoid a well-established route typeid, dynamic_cast, THEN

Something like this should be a good bet. It also returns "int" compared to "type_info" RTTI.

 class BaseClass{ //... public: virtual unsigned int GetID( void ); //... }; class DerivedClass : public BaseClass{ public: virtual unsigned int GetID( void ); }; 
0
source share

All Articles