- 先看如下例子:
class Person {…};
class BankAccount
{
public:
BankAccount(const Person *primaryOwner, const Person *jointOwner);
virtual ~BankAccount();
virtual void makeDeposit(double amount)= 0;
virtual void makeWithdrawal(doubleamount) = 0;
virtual double balance() const = 0;
…
};
class SavingsAccount : public BankAccount
{
public:
SavingsAccount(constPerson *primaryOwner, const Person *jointOwner);
~SavingsAccount();
void creditInterest(); //給賬戶增加利息
…
};
假設爲所有賬戶維持一個列表,通過list類模板實現。
list<BankAccount*>allAccount; //銀行中所有賬戶
現在準備寫一段代碼來遍歷所有賬戶,爲每個賬戶計算利息。如下所示代碼:
for(list<BankAccount*>::iterator p = allAccount.begin(); p != allAccounts.end();++p)
(*p)->creditInterest(); //錯誤
因爲creditInterest只是爲SavingsAccount對象聲明的,而不是BankAccount。
- 向下轉換:從一個基類指針到一個派生類指針。向下轉換了繼承的層次結構。
- 通過向下轉換可以得到通過編譯,並正常運行。(static_cast<SavingsAccount *>(*p)->creditInterest();)但是對以後的擴充類難以維護。向下轉換難看、容易導致錯誤,而且使得代碼難於理解、升級和維護。
- 向下轉換可以通過如下兩種方法消除:
- 最好的方法是將這種轉換用虛函數調用來代替,同時,它可能對有些類不適用,所以要使這些類的每個虛函數成爲一個空操作。
- 加強類型約束,使得指針的聲明類型和你所知道的真的指針類型之間沒有出入。
- 當不得不進行向下轉換時,可以採用比原始轉換更好的辦法。這種方法稱爲“安全的向下轉換”,通過dynamic_cast運算符來實現。當對一個指針使用dynamic_cast時,先嚐試轉換,如果成功(即指針的動態類型和正被轉換的類型一致),就返回新類型的合法指針;如果dynamic_cast失敗,返回空指針。