-3

このプログラムの実行中に「セグメンテーション違反」が発生します。以下の2つのプログラムを区別してください

class xxx{
        public: virtual void f(){cout<<"f in xxx"<<endl;}    //virtual function
                virtual void g(){cout<<"g in xxx"<<endl;}    //virtual function
};
class yyy{           //yyy has no relation with xxx at this context
        public: virtual void f(){cout<<"f in yyy"<<endl;}  //virtual function but no relation with xxx class
                void g(){cout<<"g in yyy"<<endl;}
};
int main(int argc, char *argv[])
{
        xxx x1,*x;
        yyy y1;
        x=&x1;
        x->f();
        x->g();
        x=(xxx*) &y1;        //one class pointer containing another class object address
        x->f();
        x->g();
}

-出力

f in xxx
g in xxx
f in yyy
Segmentation fault

しかし、同じ問題を持つポリモーフィズムの概念によると

class xxx{
        public: virtual void f(){cout<<"f in xxx"<<endl;}     //virtual function
                virtual void g(){cout<<"g in xxx"<<endl;}     //virtual function
};
class yyy:public xxx{             //yyy is derived from xxx
        public: virtual void f(){cout<<"f in yyy"<<endl;}
                void g(){cout<<"g in yyy"<<endl;}
};
int main(int argc, char *argv[])
{
        xxx x1,*x;
        yyy y1;
        x=&x1;
        x->f();
        x->g();
        x=(xxx*) &y1;        //parent class pointer having derived class address
        x->f();
        x->g();
}

-出力

f in xxx
g in xxx
f in yyy
g in yyy
4

2 に答える 2

2

最初のケースでは、キャストはガベージを生成します。これは、コンパイラーが指していないときに&y1指されているかのように動作するように指示しているためです。xxx2 番目のケースでは、 ayyy であるため、 aへのポインターを an へのxxxポインターにキャストしても安全ですyyyxxx

トラックへのポインターがある場合、トラックは車両であるため、車両へのポインターとして扱うことができます。しかし、花へのポインターがあり、それを乗り物へのポインターとして扱う場合、それは本質的にガベージ ポインターであり、逆参照は未定義の動作です。

ただし、C スタイルのキャストではなく、C++ スタイルのキャストを使用する必要があります。意図したセマンティクスを表現しなければならない場合は、この種の間違いを見つける可能性が高くなります。(最初のコードを書いたプログラマーは、それが として機能すると考えていたのstatic_castでしょうか? それとも、 として機能すると考えていたのでしょうreinterpret_castか? 1 つを選択するか、キャストなしで操作を実行するという余分な考えにより、エラーを回避できた可能性があります。)

于 2013-03-14T19:09:30.930 に答える
0

最初の例では:

    x=(xxx*) &y1;        //one class pointer containing another class object address
    x->f();
    x->g();

変数は、実際にはクラスとは関係のないxクラスを指しています。両方で宣言され、唯一の仮想関数であるという事実により、それが機能するようになります。はクラス内の仮想関数ですが、内の仮想関数ではないため、コンパイラは、仮想関数のテーブル(別名)の後にあるものからガベージを使用して仮想関数を呼び出すコードを生成します。実装はもちろん実装の詳細ですが、クラスごとにどこかに格納されている関数のある種の「テーブル」があることを期待するのは当然です]。yyyxxxf()g()xxxyyyg()f()vtable

yyyあなたがこのように宣言された場合、それはあなたにさらに興味深い結果を与えるでしょう:

class yyy{           //yyy has no relation with xxx at this context
        public: virtual void g(){cout<<"g in yyy"<<endl;}  //virtual function but no relation with xxx class
                void f(){cout<<"f in yyy"<<endl;}
};

を呼び出した結果、「g in yyy」になり、呼び出しにf()失敗したことがg()わかります...仮想関数の動作方法は、名前に基づいて呼び出されるのではなく、クラスの「order」[これも実装の詳細であり、「未定義動作」を扱っているため、コンパイラは「答えは42」を画面に赤いテキストで点滅させることもできます。または、緊急電話の救急車のように聞こえますが、これは、一般的なC++コンパイラの実装で説明したものよりも発生する可能性が低くなります]。

2番目のケースでは、virtualofxxxがに継承されてyyyいるため、関数g()は仮想でyyyもあり、「期待どおりに機能します」。これは、実行していることが正確に実行することになっているためです。

この種の間違いを避けるのに役立つC++スタイルのキャストがあることにも注意してください-間違った場合、コンパイル時にエラーメッセージが表示されます(static_cast)、またはdynamic_castコンパイラが判断できない場所で使用する場合コンパイル時に入力するnullptrと、結果として表示されます。これは、間違っていることを示す明らかな指標です。

于 2013-03-14T19:19:41.703 に答える