天天看點

c++primer plus 6 讀書筆記 第十三章 類繼承

  1. 類繼承

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.構造函數

  構造函數不能是虛函數。

  1. 析構函數

  析構函數應該是虛函數,/*(即使類不當基類,也可以給它虛析構函數,這樣僅僅會影響一點效率),。*/

  1. 友元

  友元不能是虛函數,因為友元不是類成員。

  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)
{
}