полиморфизм — различение полиморфных типов в переполнении стека

Вот некоторый код:

#include <typeinfo>
#include <assert.h>
#include <vector>

class Super {};

class Sub1 : public Super {};

class Sub2 : public Super {};

int main() {
std::vector<Super*> vec;

vec.push_back(new Sub1);
vec.push_back(new Sub2);

assert(typeid(vec[0]) == typeid(vec[1]));
assert(typeid(vec[0]) != typeid(vec[1]));
}

К сожалению, первое утверждение проходит, а второе нет. Я не удивлен этим результатом, но было бы неплохо иметь возможность различать типы таким образом.

Мой (вроде хакский) обходной путь:

#include <typeinfo>
#include <assert.h>
#include <vector>

enum SubTypeEnum {
Sub1_T,
Sub2_T
};

class Super {
SubTypeEnum _type;
public:
Super(SubTypeEnum __type) : _type(__type) {}
SubTypeEnum type() { return _type; }
};

class Sub1 : public Super {
public:
Sub1() : Super(Sub1_T) {}
};

class Sub2 : public Super {
public:
Sub2() : Super(Sub2_T) {}
};

int main() {
std::vector<Super*> vec;

vec.push_back(new Sub1);
vec.push_back(new Sub2);

assert(vec[0]->type() != vec[1]->type());
assert(vec[0]->type() == vec[1]->type());
}

Это дает желаемый результат, но кажется грязным. Есть ли лучший способ узнать, с каким типом я имею дело?

0

Решение

Во-первых, вы используете typeinfo немного неправильно, когда применяется к указателю, он возвращает тип указателя, но при применении к разыменованному указателю он возвращает фактический тип объекта, на который указывает, если базовый тип имеет хотя бы одну виртуальную функцию (обычно это быть деструктором). Так что будет работать следующее:

class Super {
public:
virtual ~Super() {}
};

class Sub1 : public Super {};

class Sub2 : public Super {};

int main() {
std::vector<Super*> vec;

vec.push_back(new Sub1);
vec.push_back(new Sub2);

assert(typeid(vec[0])  == typeid(vec[1]));
assert(typeid(*vec[0]) != typeid(*vec[1]));
}

Во-вторых, такое переключение типов обычно считается признаком того, что вы делаете что-то не так. Например, вместо

void foo(Base* v) {
//Here SOMETHING and SOMETHING_ELSE are constants we calculate elsewhere.
if( typeid(*v)==SOMETHING ) { cout<<"Got a SOMETHING"<<endl; }
else if (typeid(*v)==SOMETHING_ELSE ) { cout<<"Got a SOMETHING ELSE"<<endl; }
}

или его примерно эквивалентно

void foo(Base* v) {
if( dynamic_cast<Something*>(v) ) { cout<<"Got a SOMETHING"<<:endl; }
else if ( dynamic_cast<SomethingElse*>(v) { cout<<"Got a SOMETHING ESLE"<<endl; }

обычно добавляют функциональность в базовый класс:

class Base
{
public:
virtual void printMessage()=0;
};

class Something : public Base
{
void printMessage() { cout<<"Got a SOMETHING"<<endl; }
}

class SomethingElse : public Base
{
void printMessage() { cout<<"Got a SOMETHING ELSE"<<endl; }
}

void foo(Base * v)
{
v->printMessage();
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]