Как можно определить, является ли ptr указателем на класс A1 или A2 ?
P.S. На ассеблеме мне кажеться, что это можно сделать если сравнить v-table ptr и A1 и A2.
M>Как можно определить, является ли ptr указателем на класс A1 или A2 ? M>P.S. На ассеблеме мне кажеться, что это можно сделать если сравнить v-table ptr и A1 и A2.
Здравствуйте, maks1180, Вы писали:
M>class BASE; M>class A1 : BASE; M>class A2 : BASE;
M>Есть указатель M>BASE* ptr;
M>Как можно определить, является ли ptr указателем на класс A1 или A2 ? M>P.S. На ассеблеме мне кажеться, что это можно сделать если сравнить v-table ptr и A1 и A2.
#include <iostream>
#include <typeinfo>
using namespace std;
class BASE {virtual void vvfunc() {}};
class A1 : public BASE { };
class A2 : public BASE { };
int main() {
BASE *b1,*b2;
b1 = new A1;
b2 = new A2;
cout << typeid(*b1).name() << endl;
cout << typeid(*b2).name() << endl;
return 0;
}
MFC-RTTI reloaded
С той разницей, что твой код проверяет на строгое соответствие фактического типа формальному, а по-честному было бы — в соответствие с заветами Барбары Лисков — проверять наследие.
template<class T>
bool is_of_type<T>() const { return is_of_type(T::class_id()); }
bool is_of_type(ClassID id) const { return id==type_id() || __super::is_of_type(id); } // где __super вводится в макросе или компилятором
Либо без рекурсии, забегом по дереву метаданных. (Здесь метаданные примитивны — уникальное число-указатель; а могут быть весьма богатыми).
В общем-то, dynamic_cast делает примерно это же, только поддерживает все фичи языка — множественное, виртуальное, непубличное наследование.
Потому он и увесистый такой.
Получается сравнение с вызовом трех ф-ций.
Мне нужно очень быстро сравнивать, поэтому не приемлемое решение для меня.
Как сделать так
1) получить поинтер на v-table для A1, A2
2) получить поинтер на v-table для переменной ptr. Я подозреваю, что-то типо этого (void*)(*((int*)ptr)). Т.к. узазатель на v-table должен быть первым.
3) сравнить поинтеры на v-table.
Здравствуйте, maks1180, Вы писали:
M>Получается сравнение с вызовом трех ф-ций. M>Мне нужно очень быстро сравнивать, поэтому не приемлемое решение для меня.
Вариант: virtual int WhoAmI () { return какой-то-ИД-класса; }
Здравствуйте, warhast, Вы писали:
W>Вариант: virtual int WhoAmI () { return какой-то-ИД-класса; }
А зачем виртуальные функции и пр.?
Если уж можно "ломать" класс BASE, то завести в нем поле — идентификатор класса.
Каждый производный класс пишет туда свой ID в конструкторе.
Простой (невиртуальный) метод базового класса возвращает идентификатор.
RB>А зачем виртуальные функции и пр.?
RB>Если уж можно "ломать" класс BASE, то завести в нем поле — идентификатор класса. RB>Каждый производный класс пишет туда свой ID в конструкторе. RB>Простой (невиртуальный) метод базового класса возвращает идентификатор.
Судя по http://tinodidriksen.com/2010/04/14/cpp-dynamic-cast-performance/ — особой разницы нет, особенно если надо не только узнать тип объекта, но и что-то с этим объектом сделать. А там, возможно, даже скорости dynamic_cast окажется вполне достаточно, чтобы не думать об оптимизациях именно перекастовывания указателей.
Здравствуйте, maks1180, Вы писали:
M>Получается сравнение с вызовом трех ф-ций. M>Мне нужно очень быстро сравнивать, поэтому не приемлемое решение для меня. M>Как сделать так M>1) получить поинтер на v-table для A1, A2 M>2) получить поинтер на v-table для переменной ptr. Я подозреваю, что-то типо этого (void*)(*((int*)ptr)). Т.к. узазатель на v-table должен быть первым. M>3) сравнить поинтеры на v-table.
Пробовал. Обнаружил очень интересные факты про жизнь vtbl и оптимизацию пстроения оных в компайлерах.
Вплоть до того что вообще vtbl не строится в отдельных случаях.
Короче туда-не-ходи-снег-бащка-попадет.
M>Как сделать первый пункт ?
Нарисуй нечто простое типа:
struct base
{
int dummy;
virtual ~base() { dummy = 0; }
};
sizeof(base) и offsetof(dummy,base) дадут тебе полную картину где по отношению к адресу this лежит vtbl.
RB>Если уж можно "ломать" класс BASE, то завести в нем поле — идентификатор класса. RB>Каждый производный класс пишет туда свой ID в конструкторе. RB>Простой (невиртуальный) метод базового класса возвращает идентификатор.
Недостатки виртуальной ф-ции — скорость ниже
Недостатки переменной — память.
Интересно, как получить указатель на v-table для класса ?