2016-04-29 18 views
4

の参照にC++はstatic_castは、これはC++ 11Cスタイルキャストやポインタ

私はMicrosoftの CMapStringToOb::GetNextAssoc、の3番目のパラメータに興味以下ました定義はありません私はテストのための簡単なコードを持っている:2つの良いケースと1つのケースは、コンパイラのエラーです。

class CMyObject : public CObject //in order to use CMapStringToOb 
{ 
public: 
    CMyObject(CString name_) 
     :name(name_) 
    { 
    } 

    void SayHello() 
    { 
     TRACE(_T("hello") + name); 
    } 
    CString name; 
}; 

void main() 
{ 
    CMapStringToOb myMap; 
    myMap.SetAt(_T("a"), new CMyObject(_T("aaa"))); 
    myMap.SetAt(_T("b"), new CMyObject(_T("bbb"))); 
    myMap.SetAt(_T("c"), new CMyObject(_T("ccc"))); 

    //good case 1 
    POSITION pos = myMap.GetStartPosition(); 
    while (pos) 
    { 
     CString s; 
     CMyObject* pMine = NULL; 
     myMap.GetNextAssoc(pos, s, (CObject*&)pMine); 
     if(pMine) 
     { 
      pMine->SayHello(); 
     } 
    } 

    //good case 2 
    pos = myMap.GetStartPosition(); 
    while (pos) 
    { 
     CString s; 
     CObject* pObject = NULL; 
     myMap.GetNextAssoc(pos, s, pObject); 
     if(pObject) 
     { 
      CMyObject* pMine = static_cast<CMyObject*>(pObject); 
      pMine->SayHello(); 
     } 
    } 

    //bad case: 
    //can not compile 
    // error C2440: 'static_cast' : cannot convert from 'CMyObject *' to 'CObject *&'  
    //  static_cast and safe_cast to reference can only be used for valid initializations or for lvalue casts between related classes 

    pos = myMap.GetStartPosition(); 
    while (pos) 
    { 
     CString s; 
     CMyObject* pMine = NULL; 
     myMap.GetNextAssoc(pos, s, static_cast<CObject*&>(pMine)); //compile error 
     if(pMine) 
     { 
      pMine->SayHello(); 
     } 
    } 
} 

私がしようとしていたのは、Cスタイルのキャストをこの場合のC++スタイルのキャストに置き換える適切な方法を見つけることでした。

thisから読み出し、それを挙げる:

Cキャストは、(型)オブジェクトまたはタイプ(オブジェクト)を使用してキャストしています。 をキャストC-スタイルは成功し、次の最初のように定義されます。

const_cast 
static_cast (though ignoring access restrictions) 
static_cast (see above), then const_cast 
reinterpret_cast 
reinterpret_cast, then const_cast 

Q1:(例えば右辺値のために)何かを欠落している上記のリストは、ましたか?

Q2:Cスタイルのキャストをこの場合のC++スタイルのキャストに変換する適切な方法は何ですか? (良いケース2は動作しますが、より簡潔なものがあります)

Q3:rValueのCスタイルキャストはどのように行われますか? (換言すれば、なぜ良いケース1が働くのか説明してください)

+0

リファレンスとポインタの型に 'reinterpret_cast'を使う必要があります。 – paddy

+0

@paddy: "参照とポインタ"は "*&"を意味しますか?言い換えれば、次の2つのステートメントは正しいか? S1: "参照タイプにreinterpret_castを使用する必要があります。" S2: "ポインタ型にreinterpret_castを使う必要があります。" – milesma

+0

はい。あなたが持っているのは、ポインタ型への参照です。私は 'reinterpret_cast'を使う必要があることを指摘しました。 – paddy

答えて

3

static_castは、「無関係の型」への参照(またはポインタ)の間にできません。 static_castCMyObject*からCObject*になりますが、これはあなたがここでやっていることではありません。ここでは、ポインタへの参照を別のポインタへの参照にキャストしようとしています。また、2つのポインタ型には継承関係がありません。

私はあなたの「良いケース2」コードが好きです。私はそれを実行します。あなたのポインタ型の非関連性の詳細については

は、こちらを参照してください。そのコードを書くためのstatic_cast and reference to pointers

+0

素晴らしい!私は*&署名に惑わされて、**でこれをもう一度見ましたが、それはかなり明らかになっています。ところで、私はこれを説明するために、この質問への回答を投稿しました。ありがとう! – milesma

+0

ダウンキャストを実行する前にポインタが特定のタイプを指していることをアサートすることは、通常は良い考えです。 MFCの「CObject」は、[CObject :: IsKindOf](https://msdn.microsoft.com/en-us/library/b7tsah76.aspx)機能を実装しています。 'static_cast'の前に' ASSERT(pObject-> IsKindOf(RUNTIME_CLASS(CMyObject));)を追加すると、これを実現する一つの方法です。 – IInspectable

1

適切な方法は、std::map<>を使用することです。既存のコードを主に保持することを主張しても、GetNextAssoc()のインターフェイスを修正してポインタを返すことを検討してください。そのためには、あなたは、単にその関数のオーバーロードを追加することができます。

CObject* GetNextAssoc(
    POSITION& rNextPosition, 
    CString& rKey, 
) const { 
    CObject* res = 0; 
    GetNextAssoc(rNextPosition, rKey, res); 
    return res; 
} 

はさらに、あなたは、その機能をテンプレートとそこにターゲット型への変換を行うことができます。また、dynamic_castを使用することもできます。正式にはコンテナにはCObjectsが格納されていて、さまざまな種類のものがある可能性があります。

なぜ、私はあなたの質問を部分的に無視したのですか?その理由は、MFCは現代のコーディングスタイルに従わず、場合によっては、単に眉をひそめるものを行うだけです。その動作には正当な理由がありますが、まずは年齢(適切ではない、適切なテンプレートサポートがない)と互換性に関する懸念(今は変更できません)です。これらの間違いを繰り返す理由ではありません。ジョンZwinckに触発

+1

GetNextAssocのラッパー関数の考え方は悪くありません。 CObject * – milesma

+0

を返すことで署名を修正する必要があるかもしれません。@milesmaさん、ありがとう、returntypeが修正されました。 –

1

、私は別の角度から見ていきます:タイプ「CMyObjectは」タイプから「のCObject」を一般化するので

static_cast<CObject*>(pMine) 

を成功します。実際には、これは暗に行われます。タイプ "CMyObjectは、" タイプ "のCObject" から一般化するので

static_cast<CMyObject*>(pObject) 

を成功します。

static_cast<CObject**>(&pMine) 

ますFAILタイプ "CMyObject *は、" タイプ "のCObjectの*" から一般化していないため。

reinterpret_cast<CObject**>(&pMine) 

ため "reinterpret_castは" のコンパイル時にが成功します。 実行時間はどうですか?で、この関数を呼び出すと

void CMapStringToOb::GetNextAssoc(
     POSITION& rNextPosition, 
     CString& rKey, 
     CObject** ppValue) 
{ 
    *ppValue = (the pointer at the current position, point to an instance of "CMyObject"); 
} 

ので:

のが可能な新しい実装の仮定を作ろう「pMineは」 "のインスタンスを指していることを

GetNextAssoc(pos, s, reinterpret_cast<CObject**>(&pMine)) 

結果はCMyObject ";

実行時間はですので、SAFEです。

我々は(注:CYourObjectはCMyObjectへの一般化の関係を持っていない)で、キーと値を挿入する場合は、

myMap.SetAt(_T("a"), new CYourObject(_T("aaa"))); 

GetNextAssoc(pos, s, reinterpret_cast<CObject**>(&pMine)); 

でそれを取得コンパイル時には、まだ成功します、しかし、pMineは現在 "CYourObject"を指しています。実行時にはUNDEFINED BEHAVIORになります。 (static_castにも同じ問題があります)