in C++, how to use a singleton to ensure that each class has a unique integral ID?
I have a bunch of C++ classes.
I want each class to have something like:
static int unique_id;
All instances of a same class should have the same unique_id; different classes should have different unique_id's.
The simplest wa开发者_如何学编程y to do this appears to be threading a singleton through the classes.
However, I don't know what's called when for static class members / things that happen before main.
(1) if you have a solution that does not involve using singleton, that's fine too
(2) if you have a solution that gives me a :
int unique_id();
that is fine too.
Thanks!
Have a class that increments it's ID on each creation. Then use that class as a static field in each object that is supposed to have an ID.
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();
}
};
Building on Kornel's 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 like this:
class my_class : public id_base<my_class> {
// ...
};
Actually that's very similar to RTTI. To achieve (2), C++'s buildin RTTI can be exploited. Call typeid
on *this
, and take the address of the typeinfo as unique ID.
Conss: a) IDs aren't be fixed (recompile would change them), and b) the information is only available given an instance of the class, c) it's ugly.
Why do you want this?
C++ has this already built in.
You can use the typeid
operator to return a type_info
class. The type_info:name()
will return the (unique) name of the class.
First, why? In any case, you can manually set the IDs easily:
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'll have to manually keep track of the IDs for each class; at this point, I'll ask the original question: why?
I have recently found sbi's version of Kornel's solution to be very useful. Thank you both for providing your answers. However, I wanted to extend the solution further so that several types of IDs can be easily created without creating a separate pair of id_impl and id_base classes for each new type.
To do this I templated the id_impl class, and added another argument to the id_base. The result is encapsulated in a header file that is included anywhere one wants to add a new ID 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 ID type associated with them. So for each instance of the GeneralIDbase template the types specified are: the abstract base class of the derived class being declared, and the derived class being declared.
The following main.cpp is an example:
//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 is
/*
objA1.GetID() = 1
objA2.GetID() = 2
objB1.GetID() = 1
objB2.GetID() = 2
*/
I hope this helps! Please let me know of any issues.
精彩评论