Тестирование на равенство типов без RTTI - PullRequest
1 голос
/ 11 февраля 2010

Скажите B и C являются производными от A. Я хочу иметь возможность проверить, являются ли любые два экземпляра классов, производных от A, экземплярами одного и того же класса, то есть указывают ли A* foo и A* bar оба на B экземпляров, без использования RTTI. Мое текущее решение выглядит примерно так:

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

Используя этот метод, operator== может просто проверить first.code() == second.code(). Я хотел бы удалить литерал identity из производных классов и автоматически найти код с помощью A, чтобы не все производные классы повторяли эту идиому. Опять же, я бы сильно предпочел не использовать RTTI. Есть ли способ сделать это?

Примечание: Я видел последние вопросы [1] и [2] , и это не дубликат. Эти постеры хотят проверить содержание их производных классов; Я просто хочу проверить тождеств .

Ответы [ 4 ]

3 голосов
/ 11 февраля 2010

Вы должны просто использовать RTTI вместо того, чтобы заново изобретать колесо.

Если вы настаиваете на том, чтобы не использовать RTTI, вы можете использовать CRTP и локальную статическую переменную функции, чтобы избежать необходимости записи функции в каждый производный класс.,Адаптируйте из этого примера код, который я написал для Википедии: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Polymorphic_copy_construction

Другой альтернативой является чтение указателя vtable (через this и арифметику указателей), но это будет зависеть как от компилятора, так и от платформы, поэтомуне переносимо.

2 голосов
/ 11 февраля 2010

Ваша идея на правильном пути; может быть, вы можете устранить некоторые шаблоны с помощью шаблона:

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

Тогда ваши клиентские классы просто должны быть объявлены так:

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

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

Различные экземпляры TypeTagged означают, что типы имеют разные поля id и, следовательно, разные идентификаторы; виртуальный базовый тип означает, что возвращается code для самого производного типа.

0 голосов
/ 11 февраля 2010

вы можете использовать оба макроса __FILE__ __LINE__ в качестве кода
это позволит избежать проблемы столкновения
Вы можете сопоставить эти значения с int

0 голосов
/ 11 февраля 2010

У вас может быть базовый класс, принимающий id в качестве параметра конструктора и реализующий функцию identity() в самом базовом классе. Тогда нет необходимости повторять код в производных классах. В конструкторе производного класса вы можете сделать что-то вроде derived::derived(): base(0) Пример кода:

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