仮想関数の再定義と使用の違いは何ですか?それらは同じ目的を果たしませんか?どちらの場合も、派生クラスのオブジェクトが同じ名前で関数の独自のバージョンを呼び出すことを許可しています。違いはどこにありますか?
3 に答える
例はそれを最もよく言います:
#include <iostream>
using namespace std;
class A {
public:
virtual void f1() { cout << "Class A" << endl; }
void f2() { cout << "Class A" << endl; }
virtual ~A(){}
};
class B : public A {
public:
virtual void f1() { cout << "Class B" << endl; }
void f2() { cout << "Class B" << endl; }
virtual ~B(){}
};
int main()
{
A *a = new B;
a->f1();
a->f2();
}
..。
$ ./override
Class B
Class A
Bのインスタンスを参照すると、f1()
まだB
'sバージョンを呼び出しますが、'sf2()
を呼び出していることがわかりますA
。
関数virtualを宣言するとき、それを呼び出すときは、vtableを使用して、呼び出す関数の正しいバージョンを検索する必要があると言っています。したがって、参照する場合でも、関数の最も派生したバージョンを常に取得できます。祖先型として。仮想がない場合は、参照しているタイプの定義を使用するだけです。
違いは、基本クラスへの参照またはポインタがある場合です。仮想関数を呼び出すと、最も派生したバージョンが呼び出され、通常の関数を呼び出すと、基本クラスのバージョンが呼び出されます。
変数を直接使用している場合、または最も派生したクラスへの参照またはポインターを使用している場合、実際的な違いはありません。
TL; DR
C ++のポリモーフィズムを利用する唯一の方法は、仮想関数とポインター(および参照)を使用することです。virtualキーワードは、子クラスの動的型を持つ基本クラスへのポインターを処理するときに呼び出す仮想関数のバージョンを決定するときに、どこを探すかを仮想関数テーブルに割り当てるようにコンパイラーに指示します。
C++でポリモーフィズムはどのように機能しますか
簡単な例を見てみましょう。
class A { public: virtual void eat() { std::cout << "Class A" << std::endl; }
class B : public A {};
class C : public B { virtual void eat() { std::cout << "Class C" << std::endl; }
注:最初の関数/メソッド定義の後で、virtualキーワードを省略できます。
以下:
A a; B b; C c;
A* ptrA = &a; A* ptrB = &b; A* ptrC = &c;
ptrA->eat();
ptrB->eat();
ptrC->eat();
印刷されます:
Class A
Class A
Class C
関数virtualを宣言しなかった場合eat
、出力は単純に次のようになります。
Class A
Class A
Class A