仮想関数
仮想関数は派生クラスで再定義とするメンバー関数です。ポインターを使用すると派生クラスのオブジェクトの基本クラスへの参照を参照する場合そのオブジェクトの仮想関数を呼び出すと派生クラスの関数のバージョンを実行できます。
仮想関数は正しい関数がオブジェクトに呼び出すことになります関数呼び出しに使用する式に関係なく。
基本クラスが 仮想 として宣言された関数が含まれており派生クラスで同じ機能を定義するとします。派生クラスの関数は派生クラスのオブジェクトの基本クラスへのポインターまたは参照を使用して呼び出された場合開始されます。次の例では PrintBalance の関数および 2 の派生クラスを実装する基本クラスを示しています。
// deriv_VirtualFunctions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Account {
public:
Account( double d ) { _balance = d; }
virtual double GetBalance() { return _balance; }
virtual void PrintBalance() { cerr << "Error. Balance not available for base type." << endl; }
private:
double _balance;
};
class CheckingAccount : public Account {
public:
CheckingAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Checking account balance: " << GetBalance() << endl; }
};
class SavingsAccount : public Account {
public:
SavingsAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Savings account balance: " << GetBalance(); }
};
int main() {
// Create objects of type CheckingAccount and SavingsAccount.
CheckingAccount *pChecking = new CheckingAccount( 100.00 ) ;
SavingsAccount *pSavings = new SavingsAccount( 1000.00 );
// Call PrintBalance using a pointer to Account.
Account *pAccount = pChecking;
pAccount->PrintBalance();
// Call PrintBalance using a pointer to Account.
pAccount = pSavings;
pAccount->PrintBalance();
}
このコードではPrintBalance の呼び出しはオブジェクトの pAccount の点を除きと同じです。PrintBalance が仮想であるため各オブジェクトに対して定義されている関数のバージョンが呼び出されます。派生クラス CheckingAccount と SavingsAccount の PrintBalance の関数は基本クラスの Account 「関数をオーバーライドします。
PrintBalance の関数のオーバーライドを実装するクラスを宣言すると基本クラス Account の既定の実装が使用されます。
派生クラスの関数では型が同じである場合は基本クラスの仮想関数をオーバーライドします。派生クラスの関数の戻り値の型の基本クラスの仮想関数と区別できません ; 引数リストは異なっている必要があります。
関数のポインターまたは参照を使用して呼び出すと次の規則が適用されます :
仮想関数の呼び出しはというオブジェクトの基になる型に応じて解決されます。
仮想関数の呼び出しはポインターまたは参照の種類によって解決されます。
ポインターを通じて呼び出されたときに仮想と仮想関数の動作を次の例に示します。:
// deriv_VirtualFunctions2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Base {
public:
virtual void NameOf(); // Virtual function.
void InvokingClass(); // Nonvirtual function.
};
// Implement the two functions.
void Base::NameOf() {
cout << "Base::NameOf\n";
}
void Base::InvokingClass() {
cout << "Invoked by Base\n";
}
class Derived : public Base {
public:
void NameOf(); // Virtual function.
void InvokingClass(); // Nonvirtual function.
};
// Implement the two functions.
void Derived::NameOf() {
cout << "Derived::NameOf\n";
}
void Derived::InvokingClass() {
cout << "Invoked by Derived\n";
}
int main() {
// Declare an object of type Derived.
Derived aDerived;
// Declare two pointers, one of type Derived * and the other
// of type Base *, and initialize them to point to aDerived.
Derived *pDerived = &aDerived;
Base *pBase = &aDerived;
// Call the functions.
pBase->NameOf(); // Call virtual function.
pBase->InvokingClass(); // Call nonvirtual function.
pDerived->NameOf(); // Call virtual function.
pDerived->InvokingClass(); // Call nonvirtual function.
}
出力
Derived::NameOf
Invoked by Base
Derived::NameOf
Invoked by Derived
NameOf の関数が Base へのポインターまたは Derived へのポインターを介して呼び出されるかどうかに関係なくというします Derived の関数を注意してください。これは NameOf が仮想関数である型 Derived のオブジェクトへの pBase と pDerived の両方を呼び出してための関数を Derived。
仮想関数がクラス型のオブジェクトに対してのみ呼び出されるため 仮想 としてグローバル変数または静的関数を宣言できません。
仮想 のキーワードは派生クラスでオーバーライド関数を宣言するときに使用できますがこれは不要です。; 仮想関数の仮想関数は常にです。
基本クラスの仮想関数が 純粋指定子 を使用して宣言する定義する必要があります。(純粋仮想関数の詳細については抽象クラス を参照してください)。
仮想関数呼び出しの機能はスコープ解決演算子 ():: を使用して明示的に関数名を完全修飾することで抑制できます。Account のクラスを含む前の例について考えます。基本クラスの PrintBalance を呼び出すには次のようなコードを使用する :
CheckingAccount *pChecking = new CheckingAccount( 100.00 );
pChecking->Account::PrintBalance(); // Explicit qualification.
Account *pAccount = pChecking; // Call Account::PrintBalance
pAccount->Account::PrintBalance(); // Explicit qualification.
前の例の PrintBalance の呼び出しでも仮想呼び出しの機能が表示されないようにします。