Question

Say B and C are derived from A. I want to be able to test whether any two instances of classes derived from A are instances of the same class, that is, whether A* foo and A* bar both point to B instances, without using RTTI. My current solution is something like this:

class A {
protected:

    typedef uintptr_t Code;
    virtual Code code() const = 0;

}; // class A


class B : public A {
protected:

    virtual Code code() const { return Code(&identity); }

private:

    static int identity;

}; // class B


class C : public A {
protected:

    virtual Code code() const { return Code(&identity); }

private:

    static int identity;

}; // class C

Using this method, operator== can simply test first.code() == second.code(). I'd like to remove the literal identity from the derived classes and have the code found automatically by A, so that not all of the derived classes have to repeat this idiom. Again, I would strongly prefer not to use RTTI. Is there any way to do this?

Note: I have seen recent questions [1] and [2], and this is not a duplicate. Those posters want to test the contents of their derived classes; I merely want to test the identities.

Was it helpful?

Solution

You should just use RTTI instead of reinventing the wheel.

If you insist on not using RTTI, you could use CRTP and a function-local static variable to avoid having to write the function to every derived class. Adapt from this example code I wrote for Wikipedia: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Polymorphic_copy_construction

Another alternative is reading the vtable pointer (via this and pointer arithmetics), but that would depend on both the compiler and the platform, so it is not portable.

OTHER TIPS

Your idea is on the right track; maybe you can eliminate some boilerplate with a template:

class TypeTagged {
public:
  virtual Code code() const = 0;
}

template <class T>
class TypeTaggedImpl: public virtual TypeTagged {
public:
  virtual Code code() const { return Code(&id); }
private:
  static int id;
}

Then your client classes just need to be declared like this:

class A: public TypeTaggedImpl<A> { ... }

class B: public A, public TypeTaggedImpl<B> { ... }

The different instantiations of TypeTagged mean that the types have different id fields and hence different IDs; the virtual base type means that the code for the most derived type gets returned.

You can have the Base class to take id as a constructor parameter and implement the identity() function in base class itself. Then there is no need to repeat the code in derived classes. In the derived class constructor, you can do something like derived::derived(): base(0) Sample Code:

class A
{
public:
    A(int n) : m_id(n)
    {
    }
    virtual ~A(){}

    virtual int id() const 
    {
        return m_id;
    }

private:
    int m_id;
};

class B : public A
{
public:
    B() : A(0)
    {
    }
};

you can use the both macro __FILE__ __LINE__ as your code
this will avoid the collision problem
you can map this values to an int

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top