沒有學不會的C++:public, protected 和 private 關鍵字

C++ 中的繼承有 3 種方式,分別是 public、protected 和 private,這三種方式分別對應不一樣的父類成員的訪問權限,總結以下:java

  1. public、protected 和 private 子類都不能訪問父類的 private 成員
  2. public 做用域下,父類的 public 成員會被繼承爲 public,父類的 protected 成員會被繼承爲 protected
  3. protected 做用域下,父類的 public 和 protected 成員會被繼承爲 protected 成員
  4. private 做用域下,父類的 public 和 protected 成員會被繼承爲 private 成員

這 4 條規則實際上只有第 2 條是經常使用的,下面說下這 3 種做用域的使用場景。ios

public 繼承是一種 is-a 關係

咱們常常會將子對象強制轉換(casting)爲父對象,而 public 繼承在這種強制轉換的場景下是無障礙的,這種狀況下,子類對象能夠理解爲一種特殊的父類對象,即它們是一種 is-a 的關係;除此以外,其餘的由 protected 或 private 做用域繼承而來的對象就不具有這樣的關係,下面是一個簡單的例子:spa

#include <iostream>
using namespace std;

class B {
private:
    int val_;
public:
    B(int val) : val_(val) {}
    void print_val() { cout << "val_ = " << val_ << endl; }
};

class D_pub : public B {
public:
    D_pub(int val)
    : B(val)
    {}
};

class D_pro : protected B {
public:
    D_pro(int val)
    : B(val)
    {}
};

int main() {
    D_pub pub(1);
    B* b = &pub;
    b->print_val();
  	
  	D_pro dpro(1);
  	B* b2 = &dpro; // error: 'B' is an inaccessible base of 'D_pro'
}
複製代碼

上面例子中,類 B 是一個基類,D_pub 是一個使用 public 做用域的子類,而 D_pro 是使用 protected 做用域的子類,咱們在 main 中分別建立 D_pub 的對象 pub 和 D_pro 的對象 dpro,並分別賦值給父類指針,能夠看到,將 D_pro 對象賦值給父類指針的語句報編譯錯誤,緣由在於類 B 中的可訪問成員在 D_pro 中變成了不可訪問成員,即 D_pro 對象再也不是一個特殊意義的 B 對象,它們之間不具有 is-a 關係。以此類推,private 繼承的子類和父類也沒有 is-a 關係。指針

protected 和 private 繼承是一種 has-a 關係

protected 和 private 繼承相似於組合模式(composition),它是一種 has-a 關係,咱們看一個組合模式的例子:code

class hat {
public:
    void wear() {}
};

class child {
    hat h_;
public:
    void hat_wear() { h_.wear(); }
};
複製代碼

上面的代碼中,child 類是以將 hat 組合進來的方式實現的,即讓 child 類也具有 hat 的方法,一種很好的辦法是將 hat 做爲 child 的一個成員,從語義上,child 和 hat 具有 has-a 的關係。下面咱們看使用 protected 或 private 繼承如何實現 has-a 的關係:對象

class child : private hat {
public:
    using hat::wear; // 此時 child 對象就能夠調用 hat::wear 方法了
};

int main() {
  child c;
  c.wear();
}
複製代碼

咱們將 child 以 private 的方式繼承自 hat,並將 hat::wear 方法放置在 child 的 public 做用域中,這樣 child 就「擁有了 hat 的能力」,它們之間也是一種 has-a 關係。繼承

雖然不一樣的實現達到了相同的效果,但依然不建議使用 private 或 protected 的方式實現 has-a 的關係,而建議更多的使用組合模式,一是由於組合模式更爲直觀,其二是由於組合模式將組合的多個對象解耦(它們沒有多一層繼承關係),其三是組合模式更爲靈活,試想一個類有多個組合對象的狀況。作用域

總結

以上,咱們介紹了 C++ 中繼承的三種做用域,此時咱們須要記住 4 個規則:get

  1. public, protected 和 private 子類都不能訪問父類的 private 成員
  2. public 做用域下,父類的 public 成員會被繼承爲 public,父類的 protected 成員會被繼承爲 protected
  3. protected 做用域下,父類的 public 和 protected 成員會被繼承爲 protected 成員
  4. private 做用域下,父類的 public 和 protected 成員會被繼承爲 private 成員

以及 2 個使用場景:it

  1. public 繼承是一種 is-a 的關係
  2. private 或 protected 繼承是 has-a 關係;但咱們通常不使用這種方式實現 has-a 需求,通常會使用組合模式

參考:Advanced C++: Inheritance - Public, Protected, and Private

相關文章
相關標籤/搜索