【问题标题】:C++ unique static id and class name with base class带有基类的 C++ 唯一静态 ID 和类名
【发布时间】:2011-10-07 18:59:45
【问题描述】:

拥有类TaskBase,它的每个派生类都必须有名称和唯一ID。

TaskBase 如下所示:

class TaskBase
{
public:
    static const int id()
    {
        // return an unique id, for each object or derived class, HOW ??
    }

    static const string name()
    {
        // return class name for each derived class, HOW ??
        // for example : "TaskBase" for this class
    }
};

我的尝试是:

template <typename DERIVED>
class TaskBase
{
public:

    static const int id() 
    {
        static const int id = reinterpret_cast<int> (typeid (DERIVED).name());
        return id;
    }

    static const string name() 
    {
        static string n;

        if (!n.size())
        {
            int status;
            char *realname = abi::__cxa_demangle(typeid (DERIVED).name(), 0, 0, &status);
            n = realname;
            free(realname);
        }

        return n;
    }
};

我已经阅读了this,但我需要能够拥有指向每个派生类的基指针,如下所示:

class MyTask1 : public TaskBase
{
};

MyTask1 myTask1, myTask2;
TaskBase *base = &myTask1;

【问题讨论】:

  • 展示TaskBase::id和TaskBase::name的一些用例。

标签: c++ rtti


【解决方案1】:
class TaskBase
{
private:
    const void*  m_id;
    string m_name;

public:
    TaskBase(const void* m_id, string m_name): m_id(m_id), m_name(m_name)
    {
    }

    const void* id() const
    {
        return m_id;
    }

    string name() const
    {
         return m_name;
    };
};

template< typename DERIVED >
class TaskProxy: public TaskBase
{
public:   
    static const void* id()
    {
        //if you want to have for each object a unique id:
        //return reinterpret_cast<void*>(this);
        //just for each TaskProxy<????>:
        return reinterpret_cast<const void*>(typeid( DERIVED ).name());
    }

    static string name()
    {
        return typeid( DERIVED ).name();
    }

    TaskProxy(): TaskBase(id(), name()) {}
};

用法:

class MyTask1 : public TaskProxy< MyTask1 >
{
};

class MyTask2 : public TaskProxy< MyTask2 >
{
};

...

MyTask1 myTask1;
TaskBase *baseA = &myTask1;
MyTask2 myTask2;
TaskBase *baseB = &myTask2;

cout << "Name: " << baseA->name() << "  Id:" << baseA->id() << endl;
cout << "Name: " << baseB->name() << "  Id:" << baseB->id() << endl;

哪个输出这个(使用 gcc 4.6):

Name: 7MyTask1  Id:0x401228
Name: 7MyTask2  Id:0x4011c0

【讨论】:

  • 感谢您的回答,但static methods 在哪里?我如何在没有对象实例的情况下拥有MyTask2::id()
  • 嗯,你为什么需要这个?如果你想能够检查name()id(),来自TaskBase,我们需要它virtual但是你可以这样做:TaskProxy&lt;MyTask2&gt;().id() 或者你添加一个不同名称的static 函数,因为我们不能拥有它vitual&static(谁知道为什么......)
  • 是的,您非常接近我的预期解决方案,但我想知道static 方法是否存在模式?
  • @Masoud:你可以给TaskProxy类一些静态方法[非静态版本可以简单地调用],但它们不属于TaskBase,就像你最初展示的那样。
  • 当我在.cpp 文件:undefined reference to 'TaskProxy&lt;MyTask1&gt;::name()' 中编写静态方法的主体时出现链接问题。我必须在.h 中写他们的正文吗?
【解决方案2】:

我建议实现纯虚方法来获取基类中的类名和ID。后代需要提供唯一的名称和 ID。

class TaskBase
{
    public:
        virtual std::string  get_task_name(void) const = 0;
        virtual unsigned long get_task_id(void) const = 0;
};

我将@VoidStar 的建议更进一步,并将名称放入(单个)公共类中:

class TaskNames
{
  protected:
    static std::string get_tas1_name();
};

class Task1: public TaskBase, public TaskNames
{
//...
};

【讨论】:

    【解决方案3】:

    如果您严格遵循标准 C++,您可能需要硬着头皮做一些额外的记账。在某个地方创建一个枚举来存储所有类名:

    enum ClassID {
        MYTASK1_CLASS,
        MYTASK2_CLASS
    };
    

    当你创建一个新类时,添加一个新的 classId 并不需要那么长时间。

    我以前做过。做我上面描述的事情就足够了。但是……如果枚举值是用一个足够聪明的宏设置的,你可以对类的层次结构进行编码,并仅从 ClassID 和按位掩码实现动态转换和 instanceof!

    【讨论】:

    • 还有其他方法可以做到这一点,但这是一种有效的方法(像typeid 这样的方法要求所讨论的类具有虚拟成员函数,这排除了很多类)。
    猜你喜欢
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多