2011-02-07 8 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であるかどうかを伝えることができるようにしたいです。それがnull等しかった場合、私は ComplexInstruction* cInstr = static_cast<ComplexInstruction*>(current); とチェックを使用してみましたが、問題はキャストが常に成功するということである、とcInstrがnullに等しいことはありません

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

:私はそうのようなComplexInstructionsを作成します。

これを行うには適切な方法はありますか?

+1

基本クラスは多態性ですか? (つまり、仮想メンバーの機能はありますか?) –

+0

残念ながら、 – Megatron

答えて

4

私は2つのアプローチを考えることができます。まず、複雑な命令の各コンストラクタにそのアドレスをセットに格納させ、キャストする前にこれをチェックします。第2に、すべてのオブジェクトに対して独自のアロケータを定義し、オブジェクトの前に必要なタグフィールドを格納できる場合です。私は両方のアプローチが生産コードで非常にうまく使用されているのを見ました。

は、ここで設定したアプローチです:

#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; 
    } 
+0

誰かが私を間違えたと私が "絶対に方法"を書いている時、私は知っていました。よくやった! –

3

simple_instrに仮想メソッドがない場合、これを行う方法はまったくありません。そうであれば、ComplexInstruction * cInstr = dynamic_cast<ComplexInstruction *>(current)は派生型でなければNULLを返します。

+0

ダーニー..ありがとうございました – Megatron

5

これは悪い状況です。一つは、通常、仮想デストラクタを持たないクラスから派生したくないということです。間違ったことをするのは簡単すぎる。

オブジェクトのタイプをチェックする組み込みの方法は、そのタイプにdynamic_castを試して、それが成功するかどうかを確認することです。基本クラスはポリモフィックではないため(仮想メンバー関数はありません)、これを行うことはできません。

少なくともいくつかのオプションがあります。ためにはより良いから悪い方へ:継承するのではなく、使用組成物をまたは基本クラスを変更するには、いくつかの方法を見つける:理想的

  • 、あなたのデザインを変更する必要があります。あなたはComplexInstruction*ComplexInstruction&を持っていることを確認し、それがComplexInstructionであるという事実に依存する必要がどこに:

  • オブジェクトがComplexInstructionであるという事実のトラックを失うことはありません。

  • simple_instrオブジェクトのサブオブジェクトであるComplexInstructionをすべて追跡します。すべてのComplexInstructionコンストラクタで、グローバルリストにそのsimple_instrベースサブオブジェクトへのポインタを保存し、デストラクタでポインタをリストから削除します。次に、simple_instrがリストに含まれているかどうかをチェックする関数bool IsComplexInstruction(const simple_instr*)を指定できます(概念的にはリストという意味で、オブジェクトの数によってはstd::vectorまたはstd::setが理想的でしょう)。

関連する問題