2011-02-07 65 views
1

我有一個struct simple_instr,我無法修改。我創建一個從它派生類型爲這樣:如何判斷指針是否指向派生類型的實例?

struct ComplexInstruction : simple_instr 
{ 
    ComplexInstruction(const simple_instr& simple) : simple_instr(simple) 
    { 
    } 

    bool isHead; 
    bool isTail; 
    bool isPreHeader; 
}; 

我希望能夠告訴simple_instr的實例是否實際上是一個ComplexInstruction。我創建ComplexInstructions像這樣:

ComplexInstruction comInstr = *current; // current is a pointer to a simple_instr 
    ComplexInstruction* cInstr = &comInstr; 

我嘗試使用 ComplexInstruction* cInstr = static_cast<ComplexInstruction*>(current); 並檢查它是否等於空,但問題是,中投一直成功,cInstr是永遠等於空。

這樣做的正確方法是什麼?

+1

基類是多態的嗎? (即它是否有任何虛擬成員函數?) – 2011-02-07 04:51:43

+0

不,不幸的是 – Megatron 2011-02-07 04:55:11

回答

4

我可以想到兩種方法。首先,讓複雜指令的每個構造函數將其地址存儲在一個集合中,並在投射前檢查它。其次,如果您可以爲所有對象定義您自己的分配器,並將必要的標記字段存儲在對象之前。我已經看到兩種方法在生產代碼中都非常成功。

這裏的一套方法:

#include <assert.h> 
#include <set> 
// Can't be touched! 
struct simple_instr 
{ 
}; 

struct ComplexInstruction : simple_instr 
{ 
    ComplexInstruction(const simple_instr& simple) ; 
    ~ComplexInstruction(); 
    bool isHead; 
    bool isTail; 
    bool isPreHeader; 
}; 
std::set<simple_instr*> complexInstructions; 

ComplexInstruction::ComplexInstruction(const simple_instr& simple) : simple_instr(simple) 
    { 
     complexInstructions.insert(this); 
    } 
ComplexInstruction::~ComplexInstruction() 
    { 
     complexInstructions.erase(this); 
    } 
ComplexInstruction* tryCast(simple_instr* instr) 
{ 
    ComplexInstruction* ret = 0; 
    if (complexInstructions.find(instr) != complexInstructions.end()) 
     ret = static_cast<ComplexInstruction*>(instr); 
    return ret; 
} 


int test() 
{ 
    simple_instr si; 
    ComplexInstruction* siCast = tryCast(&si); 
    assert(!siCast); 
    ComplexInstruction ci(si); 
    ComplexInstruction* ciCast = tryCast(&ci); 
    assert(ciCast); 

    return 0; 
} 

的分配方法是在這些線路上:

enum InstructionType { eSimple, eComplex } ; 

simple_instr* createSimple() 
{ 
    // Highly naive - MUST make sure on alignment. 
    size_t storage = sizeof(InstructionType) + sizeof(simple_instr); 
    void* raw = malloc(storage); 
    InstructionType* header = reinterpret_cast<InstructionType*>(raw); 
    *header = eSimple; 
    simple_instr* ret = reinterpret_cast<simple_instr* >(header + 1); 
    return ret; 
} 

添加你自己的代碼的複雜,並確保添加相應的驅逐艦。

想到另一種可能的方法。也許太明顯了,你已經考慮過了,但是有沒有什麼價值可以用於simple_instr來標記它非常複雜?如果是這樣,你可以這樣寫:

ComplexInstruction* tryCast(simple_instr* instr) 
    { 
     ComplexInstruction* ret = 0; 
     if (hasComplexFlag(instr)) 
      ret = static_cast<ComplexInstruction*>(instr); 
     return ret; 
    } 
3

如果simple_instr沒有任何虛擬方法,那麼絕對沒有辦法做到這一點。如果是,那麼ComplexInstruction * cInstr = dynamic_cast<ComplexInstruction *>(current)如果不是派生類型,則會給出NULL。

+0

該死的..好吧謝謝 – Megatron 2011-02-07 05:04:01

5

這是一個糟糕的情況:一方面,你通常不希望從沒有虛擬析構函數的類派生;做錯事太容易了。

「檢查對象類型」的內置方法是嘗試使用該類型並查看是否成功。既然你的基類不是多態的(它沒有任何虛擬成員函數),你不能這樣做。

至少有幾個選項。從好到壞:

  • 理想情況下,你應該改變你的設計:使用組合而不是繼承或找到一些方法來改變基類。

  • 不要失去的事實,對象是ComplexInstruction軌跡:無論你需要依靠的事實,這是一個ComplexInstruction,確保你有一個ComplexInstruction*ComplexInstruction&

  • 跟蹤作爲ComplexInstruction對象的基本子對象的所有simple_instr對象。在每個ComplexInstruction構造函數中,在全局列表中保存一個指向simple_instr基本子對象的指針,並在析構函數中從列表中刪除指針。然後,您可以提供一個函數bool IsComplexInstruction(const simple_instr*)來檢查simple_instr是否在列表中(通過「列表」我的意思是概念上是一個列表; std::vectorstd::set可能是理想的,具體取決於您擁有多少個對象)。

相關問題