2013-04-08 39 views
0

這裏之間拘泥是一些代碼:++多態類型用C

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

不幸的是,第一斷言通過,和第二不。我對這一結果並不感到驚訝,但能夠以這種方式辨別類型本來就不錯。

我(有點hackish的)解決方法:

#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

我以爲你失蹤了'*'對第二個斷言的兩個論點? – 2013-04-08 03:57:22

回答

1

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

有趣的是,我嘗試瞭解引用,但是沒有使用任何虛擬方法,它沒有工作。爲什麼虛擬方法有所作爲? – anthropomorphic 2013-04-08 04:00:35

+0

「愚蠢」的答案是因爲標準指定它是這樣的。實際上原因是動態'typeinfo'存儲在vtable中(如果存在的話)。如果vtable不存在,那麼在類實例內部就沒有類型信息的合理位置了......唯一可以使vtable存在的方法是添加虛擬函數。 – 2013-04-08 04:08:40

+0

太棒了。謝謝。我試過了,它確實有效。 – anthropomorphic 2013-04-08 04:09:38