c++中多态类型的区分

Discerning between polymorphic types in C++

本文关键字:类型 多态 c++      更新时间:2023-10-16

代码如下:

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

这会产生期望的结果,但是看起来很混乱。有没有更好的方法来找出我正在处理的是哪一种类型?

首先,您使用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();
}