in C++, how to use a singleton to ensure that each

2019-02-24 06:20发布

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 way 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!

6条回答
在下西门庆
2楼-- · 2019-02-24 06:48

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?

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-02-24 06:50

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.

查看更多
Deceive 欺骗
4楼-- · 2019-02-24 06:55

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?

查看更多
姐就是有狂的资本
5楼-- · 2019-02-24 06:56

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();
    }
};
查看更多
够拽才男人
6楼-- · 2019-02-24 06:57

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.

查看更多
够拽才男人
7楼-- · 2019-02-24 07:07

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> {
  // ...
};
查看更多
登录 后发表回答