3

私は仮想関数について学んでいて、以下のプログラムの結果と非常に混乱しています。両方とも「hello from B」を返すことを望んでa1.virFun(b1)b1.virFun(b1)ましたが、プログラムは「hellofromA」を返します。これは私の理解に反しています。b1.sayHello()b1を引数として渡してb1.sayHello()仮想関数であるのに、なぜ呼び出されないのか説明してください。

#include<iostream>

using namespace std;

class A
{
 public:
 virtual void sayHello();
 void virFun(A obj);

 };

class B : public A
{
 public:
 void virFun(A obj);
 virtual void sayHello();

};

void A::sayHello()
 {
   cout << "hello from A" << endl;
 }

 void B::sayHello()
 {
   cout <<"hello from B" << endl;
 }

 void A::virFun(A obj)
 {
    obj.sayHello();
 }

 void B::virFun(A obj)
{
    obj.sayHello();
}

int main()
{
 A a1;
 B b1;

a1.virFun(b1);
b1.virFun(b1);

return 0;
}
4

2 に答える 2

6
void virFun(A obj);

仮想関数を機能させるには、参照またはポインターによってオブジェクトを渡し、常に元のオブジェクトを操作していることを確認する必要があります。

void virFun(const A &obj);
void virFun(const A *obj);

そうしないと、オブジェクトのコピーvirFun()を受け取り、オブジェクトを「スライス」して、派生クラスの情報を失うことになります。コピーには'vtableがあり、'の余分なフィールドがありません。これは通常、災害です。AB

原則として、プレーンではなく、T&またはを使用してオブジェクトを渡します。スライスの問題は別として、それはまたより効率的です。const T&T

于 2012-10-12T13:46:04.687 に答える
3

virFunに、値によるAオブジェクトではなく、参照を取得させます。

 void A::virFun(A& obj) { obj.sayHello(); }

理由Aby値を取得した場合、渡された値のコピーを作成することにより、パラメーターが初期化されます。Bを渡すと、その「A」部分がパラメータータイプ()の新しい変数にコピーされます。これはオブジェクトスライシングAと呼ばれます。パラメータは「be-a」インスタンスではなくなるため、インスタンスとして動作します。BA

どちらの場合も引数objを使用するため、クラスBのvirFunをオーバーライドする必要はありません。

実際、virFunは静的関数である可能性があります。virFun(仮想関数)でもないため、名前がわかりにくいです。これは、仮想関数を使用する通常の関数です。

#include<iostream>

using namespace std;

struct A     { virtual     void sayHello() { cout << "hello from A" << endl; } };
struct B : A { /*virtual*/ void sayHello() { cout << "hello from B" << endl; } };

static void virFun(A& obj)
{
    obj.sayHello();
}

int main()
{
    A a1;
    B b1;

    virFun(a1);
    virFun(b1);
}

http://liveworkspace.org/code/1624496ced29eb4683f5b19072f72f60でライブでご覧ください

hello from A
hello from B
于 2012-10-12T13:45:32.987 に答える