2

Having class TaskBase, each derived class of it must have name and unique id.

The TaskBase is something like below:

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
    }
};

My try was :

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;
    }
};

I already read this, but i need the ability to have base pointer to each derived classes, something line below:

class MyTask1 : public TaskBase
{
};

MyTask1 myTask1, myTask2;
TaskBase *base = &myTask1;
Community
  • 1
  • 1
masoud
  • 55,379
  • 16
  • 141
  • 208

3 Answers3

3
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()) {}
};

Usage:

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;

Which outputs this (with gcc 4.6):

Name: 7MyTask1  Id:0x401228
Name: 7MyTask2  Id:0x4011c0
KoKuToru
  • 4,055
  • 2
  • 20
  • 21
  • Thanks for answer, but where is `static methods`? How can i have `MyTask2::id()` without object instancing ? – masoud Oct 07 '11 at 19:32
  • Uhm why would you need this?If you want to be able to check for `name()` and `id()`, from `TaskBase`, we need to have it `virtual` But you can do this: `TaskProxy().id()` or you add a `static` function with different name, because we can't have it `vitual`&`static` (who knows why..) – KoKuToru Oct 07 '11 at 19:36
  • yea, you are **very** close to my intended solution, but i'm wondering if there is a pattern with `static` methods? – masoud Oct 07 '11 at 19:40
  • @Masoud: You can give the `TaskProxy` class some static methods [which the non-static versions can simply call], but they don't belong in `TaskBase` like you initially showed. – Dennis Zickefoose Oct 07 '11 at 19:41
  • There is a linking problem when i write the body of static methods in `.cpp` file: `undefined reference to 'TaskProxy::name()'`. Do i have to write the body of them in `.h` ? – masoud Oct 07 '11 at 21:42
  • You can't do this because of the template! It must be in the header. Yeah the functions of the class, with template, must be in the `.h` -> the whole `class TaskProxy` must be in the `.h`. – KoKuToru Oct 07 '11 at 22:08
-1

If you are following strictly standard C++, you may need to just bite the bullet and do some additional bookkeeping. Make an enum somewhere that stores all the classnames:

enum ClassID {
    MYTASK1_CLASS,
    MYTASK2_CLASS
};

It doesn't take that long to add a new classId when you make a new class.

I've done this before. It's sufficient for uniqueness to do what I describe above. But... if the enum values are set with a clever enough macro, you can encode the hierarchy of the classes, and implement dynamic cast and instanceof solely from the ClassID and a bitwise mask!

VoidStar
  • 5,241
  • 1
  • 31
  • 45
  • There are other ways to do it, but this is a valid approach (and approaches like `typeid` require that the classes in question have virtual member functions, which rules out a lot of classes). – Max Lybbert Oct 12 '11 at 22:36
-1

I suggest implementing pure virtual methods for obtaining the class name and ID in the base class. The descendants would need to provide the unique names and IDs.

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

I took @VoidStar's suggest a step further and put the names into a (single) common class:

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

class Task1: public TaskBase, public TaskNames
{
//...
};
Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154