4

私はコードを書きましたが、その出力と混同しています。

#include <iostream>

using namespace std;

class B{
public:
    virtual void foo() {cout << "B::foo" << endl;}
};

class D:public B{
public:
    virtual void foo() {cout << "D::foo" << endl;}
    void disp() {cout << "D::disp" << endl;}
};

void func(B *pb){
    D *pd1 = static_cast<D*>(pb);
    pd1->foo();
    pd1->disp();
}

int main(int argc, char *argv[])
{

    B* pb = new B();
    func(pb); 

    return 0;
}

出力は次のとおりです。

B::foo
D::disp

しかし、私が知る限り、pbタイプBを指しています。それに名前の付いた関数はありませdisp()んか?では、なぜdisp()クラスDの関数にアクセスできるのでしょうか。

4

5 に答える 5

4

クラスのどのメンバーにもアクセスしないためdisp()、原則として、クラスではなくグローバル名前空間で宣言された場合と同じです。したがって、インスタンスがそうでなくても、呼び出すことによる悪影響はありません。適切なクラスの。

基本クラスのポインターを、そのように初期化されていなくても、派生クラスのポインターにダウンキャストしています。に含まれているが含まれていないdisp()クラスメンバーにアクセスしようとすると、おそらくsegfaultに遭遇します。DB

static_cast結論:ポインタが実際に派生クラスのインスタンスを指していることが絶対に確実でない限り、ダウンキャストには使用しないでください。よくわからない場合はdynamic_cast、不一致が発生した場合に失敗するものを使用できます(ただし、RTTIのオーバーヘッドがあるため、可能であれば回避してください)。

dynamic_castnullptrキャストが正しくない場合は戻り、std::bad_cast 参照をキャストする場合は例外をスローするため、メモリ破損のバグの可能性ではなく、失敗する理由が確実にわかります。

于 2012-09-02T21:16:29.133 に答える
2

この線:

D *pd1 = static_cast<D*>(pb);

ソースポインタがまたはであるB*かどうかに関係なく、キャストを作成しますD*。あなたの場合、結果は間違ったタイプのオブジェクトを指すポインタになります。メソッドdispは、クラスのデータメンバーまたは仮想関数を使用していないため、機能しDます。より複雑なケースでは、これは不安定な動作またはクラッシュにつながります。

あなたのオブジェクトはポリモーフィックです。dynamic_cast代わりに使用する必要があります。

于 2012-09-02T21:18:39.863 に答える
1

このコンテキストで重要なのは、メンバー関数disp()が型のすべてのオブジェクト内に隠れているわけではないということDです。これは、1つの場所に存在する単一の機能です。また、オブジェクトが呼び出しを呼び出そうとするかどうかdisp()は、コードによって決まります。

渡すポインタに関係なくstatic_cast、コンパイラがポインタと見なすものを生成します。そして、へのポインタを取得すると、コンパイラは。を呼び出そうとします。D Ddisp()

別の言い方をstatic_castすれば、ポインタを誤ってキャストすることからあなたを保護することはありません。

于 2012-09-02T21:21:55.417 に答える
1

B派生クラスへのポインタとして割り当てられたオブジェクトへのポインタをキャストすると、非常に悪いことが起こりましたD。これが標準が言っていることです、私の強調:

5.2.9静的キャスト

タイプ「pointertocv1B」の右辺値が、実際にはタイプDのオブジェクトのサブオブジェクトであるBを指している場合、結果のポインターはタイプDの囲んでいるオブジェクトを指します。それ以外の場合、キャストの結果は未定義です。 。

それを行うことで未定義動作を呼び出しましたstatic_cast。コンパイラーとランタイムは何でも実行でき、プログラムが未定義の動作を呼び出した場合でも準拠します。

于 2012-09-02T21:29:45.957 に答える
0

さまざまなタイプのC++キャストの違いを理解する必要があります。

ここでは静的キャストを使用しています。これは、「実際にそのタイプであるかどうかは関係ありません。最善を尽くしてください」と言っているのと同じです。

この場合、ポインタが実際にキャスト先の派生型であるかどうかを知りたいと思います。dynamic_castを使用する必要があります。このキャストは、ポインターが正しいタイプである場合にのみ成功します。つまり、失敗した場合、NULLポインタが返されます。

あなたが見ている振る舞いは、あなたがその仕事に正しいキャストを使わないときに起こることです。それはあなたがそれを説明しようとすることはできますが、それは未定義の振る舞いの領域にあるのであなたが本当に避けるべきものです。つまり、コンパイラ間で同じ副作用が発生したり、同じコンパイラのバージョンが異なる場合でも、同じ副作用が発生することはありません。言い換えれば、それを避けてください。

于 2012-09-02T21:33:34.693 に答える