In C ++, how to use singleton to ensure that each class has a unique integral identifier?

I have a bunch of C ++ classes.

I want each class to have something like:

static int unique_id; 

All instances of the same class must have the same unique_id; different classes must have different unique_id.

The simplest way to do this is apparently to slice a singleton through classes.

However, I do not know what caused when for the static members of the class / things that happen before the main.

(1) if you have a solution that is not related to using singleton, this is also very good.

(2) if you have a solution that gives me:

 int unique_id(); 

it is also good.

Thanks!

+4
source share
6 answers

You have a class that increments its identifier for each creation. Then use this class as a static field in each object that must have an identifier.

 class ID { int id; public: ID() { static int counter = 0; id = counter++; } int get_id() { return id; } }; class MyClass { static ID id; public: static int get_id() { return id.get_id(); } }; 
+9
source

Based on the Kornel solution :

 class id_impl { private: id_impl() {} static int get_next_id() { static int counter = 0; return ++counter; } template< class T > friend class id_base; }; template< class T > class id_base : private id_impl { public: static int get_id() { return id; } private: static int id; }; template< class T > int id_base<T>::id id = get_next_id(); 

Use it as follows:

 class my_class : public id_base<my_class> { // ... }; 
+4
source

This is actually very similar to RTTI. To achieve (2), you can use C ++ buildin RTTI. Call typeid on *this and enter the address of type info as a unique identifier.

Cons: a) Identifiers are not fixed (recompilation will change them), and b) information is available only with an instance of the class, c) it is ugly.

Why do you need this?

+3
source

First, why? In any case, you can easily set the identifiers manually:

 template <int id> struct base { enum { unique_id = id }; }; class foo: public base<5> { ... }; class bar: public base<10> { ... }; 

Then

 foo x; bar y; assert(x.unique_id == 5); assert(y.unique_id == 10); 

Of course, you will have to manually track the identifiers for each class; at the moment, I will ask the original question: why?

+1
source

C ++ is already built in.

You can use the typeid operator to return the type_info class. type_info:name() will return the (unique) name of the class.

+1
source

I recently found the sbi version Kornel solution to be very useful. Thank you for the answers provided. However, I wanted to expand the solution so that it would be possible to easily create several types of identifiers without creating a separate pair of id_impl and id_base classes for each new type.

To do this, I configured the id_impl template and added another id_base argument. The result is encapsulated in a header file, which is included anywhere where you want to add a new identifier type:

 //idtemplates.h template< class T > class GeneralID { private: GeneralID() {} static int GetNextID() { static int counter = 0; return ++counter; } template< class T, class U > friend class GeneralIDbase; }; template< class T, class U > class GeneralIDbase : private GeneralID < T > { public: static int GetID() { return ID; } private: static int ID; }; template< class T, class U > int GeneralIDbase<T, U>::ID = GetNextID(); 

For my application, I wanted several abstract base classes to have an identifier type associated with them. Therefore, for each instance of the GeneralIDbase template, the indicated types are: the abstract base class of the declared derived class and the declared derived class.

The following is an example of main.cpp:

 //main.cpp #include<iostream> #include<idtemplates.h> using namespace std; class MyBaseClassA {}; class MyBaseClassB {}; class MyClassA1 :public MyBaseClassA, public GeneralIDbase<MyBaseClassA, MyClassA1> {}; class MyClassA2 :public MyBaseClassA, public GeneralIDbase<MyBaseClassA, MyClassA2> {}; class MyClassB1 :public MyBaseClassB, public GeneralIDbase<MyBaseClassB, MyClassB1> {}; class MyClassB2 :public MyBaseClassB, public GeneralIDbase<MyBaseClassB, MyClassB2> {}; int main() { MyClassA1 objA1; MyClassA2 objA2; cout << "objA1.GetID() = " << objA1.GetID() << endl; cout << "objA2.GetID() = " << objA2.GetID() << endl; MyClassB1 objB1; MyClassB2 objB2; cout << "objB1.GetID() = " << objB1.GetID() << endl; cout << "objB2.GetID() = " << objB2.GetID() << endl; cin.get(); return 0; } 

The output of this code

 /* objA1.GetID() = 1 objA2.GetID() = 2 objB1.GetID() = 1 objB2.GetID() = 2 */ 

Hope this helps! Please let me know about any problems.

+1
source

Source: https://habr.com/ru/post/1299890/


All Articles