在C ++中,如何使用单例来确保每个类都有唯一的整数ID?

时间:2022-11-25 12:54:02

I have a bunch of C++ classes.

我有一堆C ++类。

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.

同一个类的所有实例应该具有相同的unique_id;不同的类应该有不同的unique_id。

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.

但是,我不知道什么时候静态类成员/事件发生在main之前。

(1) if you have a solution that does not involve using singleton, that's fine too

(1)如果你有一个不涉及使用单身的解决方案,那也没关系

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

(2)如果你有一个解决方案给我一个:

int unique_id(); 

that is fine too.

那很好。

Thanks!

6 个解决方案

#1


9  

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.

有一个类在每次创建时增加它的ID。然后将该类用作应该具有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();
    }
};

#2


4  

Building on Kornel's solution:

以Kornel的解决方案为基础:

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> {
  // ...
};

#3


3  

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.

实际上这与RTTI非常相似。为了实现(2),可以利用C ++的buildin RTTI。在* this上调用typeid,并将typeinfo的地址作为唯一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.

Conss:a)ID不是固定的(重新编译会改变它们),b)信息仅在给定类的实例时可用,c)它很难看。

Why do you want this?

你为什么要这个?

#4


1  

C++ has this already built in.

C ++已经内置了这个。

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

您可以使用typeid运算符返回type_info类。 type_info:name()将返回类的(唯一)名称。

#5


1  

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

首先,为什么?无论如何,您可以轻松地手动设置ID:

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?

当然,您必须手动跟踪每个类的ID;在这一点上,我会问原来的问题:为什么?

#6


1  

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.

我最近发现sbi版的Kornel解决方案非常有用。谢谢你们提供答案。但是,我想进一步扩展解决方案,以便可以轻松创建几种类型的ID,而无需为每种新类型创建单独的id_impl和id_base类。

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:

为此,我模板化了id_impl类,并在id_base中添加了另一个参数。结果封装在头文件中,该文件包含在想要添加新ID类型的任何位置:

//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.

对于我的应用程序,我希望有几个抽象基类具有与之关联的ID类型。因此,对于GeneralIDbase模板的每个实例,指定的类型是:声明的派生类的抽象基类,以及声明的派生类。

The following main.cpp is an example:

以下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 is

这段代码的输出是

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

I hope this helps! Please let me know of any issues.

我希望这有帮助!如有任何问题,请告诉我。

#1


9  

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.

有一个类在每次创建时增加它的ID。然后将该类用作应该具有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();
    }
};

#2


4  

Building on Kornel's solution:

以Kornel的解决方案为基础:

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> {
  // ...
};

#3


3  

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.

实际上这与RTTI非常相似。为了实现(2),可以利用C ++的buildin RTTI。在* this上调用typeid,并将typeinfo的地址作为唯一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.

Conss:a)ID不是固定的(重新编译会改变它们),b)信息仅在给定类的实例时可用,c)它很难看。

Why do you want this?

你为什么要这个?

#4


1  

C++ has this already built in.

C ++已经内置了这个。

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

您可以使用typeid运算符返回type_info类。 type_info:name()将返回类的(唯一)名称。

#5


1  

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

首先,为什么?无论如何,您可以轻松地手动设置ID:

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?

当然,您必须手动跟踪每个类的ID;在这一点上,我会问原来的问题:为什么?

#6


1  

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.

我最近发现sbi版的Kornel解决方案非常有用。谢谢你们提供答案。但是,我想进一步扩展解决方案,以便可以轻松创建几种类型的ID,而无需为每种新类型创建单独的id_impl和id_base类。

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:

为此,我模板化了id_impl类,并在id_base中添加了另一个参数。结果封装在头文件中,该文件包含在想要添加新ID类型的任何位置:

//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.

对于我的应用程序,我希望有几个抽象基类具有与之关联的ID类型。因此,对于GeneralIDbase模板的每个实例,指定的类型是:声明的派生类的抽象基类,以及声明的派生类。

The following main.cpp is an example:

以下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 is

这段代码的输出是

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

I hope this helps! Please let me know of any issues.

我希望这有帮助!如有任何问题,请告诉我。