- 類繼承
C++提供了更高層次的重用性。類繼承--從已有的類派生出新類。
繼承通常:
在已有的類上面添加功能。
給類添加資料。
修改類方法的行為。
13.1 一個簡單的基類
class Player{...}
13.1.1 派生一個類
使用派生的聲明:
class RatedPlayer : public Player //public 為公有派生
{...}
使用公有派生,基類的public會成為派生類的public,
基類的private成為派生類的一部分,但是隻能 通過基類的public或protected方法通路。
派生類需要自己的構造函數
根據需要添加額外的資料成員和成員函數。
13.1.2 構造函數:通路權限的考慮
建立派生類對象時,首先會建立基類對象,
C++使用初始化清單完成基類建立。
13.1.3 使用派生類
13.1.4 派生類和基類之間的特殊關系
派生類對象可以使用基類的方法(除了private)。
基類指針可以指向派生類,
基類引用可以引用派生類對象,
然而基類指針隻能用于調用基類方法。
13.2 繼承:is-a 關系
C+有三種繼承方式:公有繼承(public)、保護繼承(protected)和私有繼承(private)。
公有繼承(public)是最常用的方式,它是一種is-a關系(是一種。),派生類對象也是一個基類對象。
13.3 多态公有繼承
希望同一個方法在派生類和基類的行為不同,需要多态繼承。
兩種重要的機制可實作多态公有繼承:
1.派生類中重新定義方法。
2.使用虛方法(virtual)
方法1容易了解,難點是方法2(虛方法(virtual))。
虛方法使用字首 virtual 來表明該方法是虛方法,虛方法将根據引用或指針 指向的對象類型 來選擇方法。
通常在基類中将派生類會重新定義的方法聲明為虛方法。
方法在基類聲明為虛的後,在派生類中也将自動成為虛方法。(也可在派生類中手動virtual 指明為虛函數)
13.4 靜态聯編和動态聯編
将源代碼中的函數調用解釋為特定的函數代碼塊被成為函數名聯編(binding)。
13.4.1 指針和引用的相容性
13.4.2 虛成員函數和動态聯編
編譯器為非虛方法使用靜态聯編(程式執行前)
虛方法使用動态聯編(程式執行時)
13.4.3 有關虛函數注意事項
1.構造函數
構造函數不能是虛函數。
- 析構函數
析構函數應該是虛函數,/*(即使類不當基類,也可以給它虛析構函數,這樣僅僅會影響一點效率),。*/
- 友元
友元不能是虛函數,因為友元不是類成員。
- 沒有重新定義
如果派生類沒有重新定義函數,則使用基類的函數。如果派生類位于派生鍊中,将使用最新的虛函數版本。
13.5 通路控制: protected
protected 與 private 相似:
在類外隻能用公有類成員來通路protected成員,
protected 與 private 的差別隻在派生類中: 派生類成員可以直接通路基類的protected成員,但是不能直接通路基類的private成員。
總結:對外部來說,protected 相當于private
對派生類來說,protected相當于public
13.6 抽象基類(abstract base class , ABC)
有時候is-a 規則很複雜,例如:圓(Circle)和橢圓(Ellipse),顯然圓 是一種 橢圓,但是用橢圓來派生圓是笨拙的(資訊備援)。
是以,考慮另一種方法,抽象基類:将它們的共性放到一個抽象基類(ABC)中,然後從ABC派生出圓和橢圓。
C++通過純虛函數提供為實作的函數,結尾加上=0.
如:
virtual double Area() const =0;
類聲明中含有純虛函數時,則不能建立該類的對象。
使其隻做一個ABC。
13.6.1 應用ABC概念
13.6.2 ABC理念
13.7 繼承和動态記憶體配置設定
13.7.1 第一種情況:派生類不使用new
13.7.2 第二種情況:派生類使用new
13.7.3 使用動态記憶體配置設定和友元的繼承示例
13.8 類設計回顧
13.8.1 編譯器生成的成員函數
13.8.2 其他的類方法
13.8.3 公有繼承的考慮因素
13.8.4 類函數小結
13.9 總結
補充:
#pragma once
#include<string>
using std::string;
//基類
class TableTennisPlayer
{
private:
string name;
bool hasTable;
public:
TableTennisPlayer(const string&name = "none", bool ht = false);
void Name() const;
bool HasTable() const { return hasTable; }
void ResetTable(bool v) { hasTable = v; }
};
//public方式從基類繼承的派生類
class RatedPlayer : public TableTennisPlayer
{
private:
unsigned int rating;
public:
RatedPlayer( int r = 0, const string&name = "none", bool ht = false);
RatedPlayer( int r, const TableTennisPlayer& tp);
int Rating() { return rating; }
void ResetRating(int r) { rating = r; }
};
#include"tabtenn0.h"
#include<iostream>
TableTennisPlayer::TableTennisPlayer(const string & name, bool ht):name(name),hasTable(ht){}
void TableTennisPlayer::Name() const
{
std::cout << name;
}
RatedPlayer::RatedPlayer(int r, const string & name,
bool ht):TableTennisPlayer(name,ht),rating(r)
{}
RatedPlayer::RatedPlayer(int r, const TableTennisPlayer & tp)
:TableTennisPlayer(tp),rating(r)
{
}