C++中類的繼承關係梳理

人生苟且了很長時間,須要再繼續努力了。面試

總結了C++的繼承方面的關係:編程

  朋友在面試的時候被問過一個問題,說類的繼承重要的一點是什麼,他沒有答到點子上,後來面試官提到的是代碼的複用,不用每次都從新寫相同的代碼,仍是有道理的。框架

類的聲明:函數

class TableTennisPlayer
{
private:
  string firstname;
  string lastname;
  bool hashTable;設計

public:
  TableTennisPlayer(const string &fn = "none", const string &ln = "none", bool ht=false);
  void Name() const; //只讀的一個函數
  bool HashTable() const {return hashTable;};
  bool ResetTable (bool v) { hashTable = v;};指針

};對象

初始化:繼承

TableTennisPlayer play1("zhang", "jingle", true);內存

 string firstname;
 string lastname;
 bool   hashTable;字符串

原型是這樣的

TableTennisPlayer(const string &fn = "none", const string &ln = "none", bool ht=false);

由此引伸出來的一點,寫字符串的過程當中的賦值過程,應該是調用了 string 類的 以const char *做爲參數的構造函數。若是是以string 類爲參數的話,則會調用 

等等,有一點沒有想明白,形參爲const string &, 若是傳遞的參數類型的是string 的話,調用的構造函數是幾回?,若是傳入的參數類型是const char*的話,調用的構造參數又是幾回?

我感受這方面仍是沒有理清楚??

在派生一個類中,以下所示,增長了一個成員變量,對於

class RatedPlayer: public TableTennisPlayer
{
private:
  unsigned int rating;
public:
  //想起來了,是基本的構造函數
  RatedPlayer(unsigned int r = 0, const string &fn = "none", const string &ln = "none", bool ht = false);

  //是複製構造函數
  RatedPlayer(unsigned int r, const TableTennisPlayer &tp);

  unsigned int Rating() const {return rating;};
  void Reseat (unsigned int r){rating = r;};  
};

派生類的構造函數,

一、首先建立基類對象

二、派生類的構造函數經過成員初始化列表將基類的信息傳遞給基類構造函數。(這個分狀況,可能調用基類的構造函數,默認構造函數和複製構造函數)

三、派生類的構造函數應初始化派生類新增的數據成員。

 

基類的私有部分也是派生類的一部分,可是隻能經過基類的公有和保護方法來進行訪問。訪問權限也是很重要的。

 

基類和派生類的關係:

一、派生類可使用基類的方法,這個方法不能是私有的。

二、基類指針能夠在不進行顯示轉換的狀況下指向派生類,基類引用能夠在不顯示轉換的狀況下,引用派生類對象(向上強制轉換,不能將派生類的指針指向派生類)

可是上面基類的指針卻只能調用基類的方法。

例子:

class base

{

};

class bigger::public base

{

}

bigger hh;

base &rt = hh;

base *rt2 = &hh;

就是這麼簡單。

基類指針若是想要調用派生類的方法

一、虛函數

virtual void test()

{

 printf("test.....");

};

若是隻是虛函數的話,在基類中是要實現的。

在派生類中能夠不用從新實現這個類,若是在派生類中沒有實現,則調用基類的方法。若是在派生類從新實現了該方法,則調用的時候使用派生類的方法。

二、純虛函數

純虛函數 virtual  test() = 0;

這個是須要在派生類中必需要實現的,帶有純虛函數的基類是不能直接使用的,只是做爲一個框架在使用,目的就是讓別人繼承實現多態。

class base

{

public:

  virtual dddd() = 0;

};

base aaa; 這樣是不能夠的。

class bigger ::public base

{

public:

  dddd()

  {

     xxxxxxxxxx;

  }

};

 bigger bbbb ;這樣是能夠的。

 

C++中,多態的這種機制纔是精華,訪問權限的控制。

若是基類中的數據和方法是privated:

在派生類中,只能調用 基類的方法來訪問基類的訪問權限

虛函數的幾種狀況,

一、基類中爲虛函數

基類中對虛函數有定義,有實現。

想驗證一下那種是錯誤的寫法:

1.1 派生類 中 對虛函數有定義,帶virtual  無實現

不能夠。

1.2派生類中對虛函數有定義,帶virtual 有實現

調用派生類中的方法。

1.3派生類中對虛函數有定義,不帶virtual 無實現

不能夠

1.4 派生類中對虛函數有定義,不帶virtual 有實現

調用派生類中方法。

1.4 派生類中對虛函數無定義,不實現。

結果是調用基類的方法。這個是最基本的。

總結一下就是想要在派生類中修改就必定要有定義和實現,感受本身寫的是廢話,可是定義帶不帶virtual 是否是同樣呢??

本身糾結了這麼長時間的問題,百度了一下就知道了,不是必須的,可是爲了代碼的清晰易讀,仍是加上吧,爲了讓孫子類知道,這個是虛函數,呵呵

 

二、基類中爲純虛函數。

基類中不須要實現,可是在派生類中必需要實現。

三、 當虛函數趕上重載。

簡單

class dwelling

{

public:    

  virtual void showperks() const ;    

  virtual void showperks(int a)const ;

};

class hovel:public dwelling

{

public:     

  virtual void showperks() const;

     virtual void showperks(int a)const ;//若是此方法註釋的話,也不能調用基類中的該方法,基類中其餘版本被隱藏了。

};

當重載趕上虛函數時,想要在派生類中對基類中的函數想要修改的話,就必須在派生類中進行所有從新定義,所有實現。

具體見:/learnCpluseplus/inherit/brass/test1.cpp 。

多態的是實現有兩種方式:

一、一種就是派生類中從新定義基類方法。

二、使用虛函數。 

在 上面的例子中 用基類指針指向派生類,若是在基類中定義了一個虛函數,而且在派生類中實現的話(派生類中無論實現的爲virtual 仍是非virtual ),用基類指針調用該函數,則會調用到派生類中的方法。

看的C++中總結的術語:

  若是方法是經過引用或者指針而不是對象調用的,它將肯定使用哪一種方法,若是沒有使用關鍵字virtual ,程序將只用引用類型或者是指針類型選擇方法,若是使用了virtual,程序將根據引用或指針指向的對象的類型來選擇方法。

 

class

派生類中國訪問權限的控制:

C++中的權限分爲public、protected、private,繼承的方式也有三種,分別是public、protected、private這三種方式

通俗講,派生類中某個屬性或者方法的權限,就是基類中的訪問權限與繼承訪問權限的較小集。(也就是數學中的交集)

 

在C++中,編譯器對於方法,是靜態聯編仍是動態聯編,是跟方法是否認義爲虛函數有關係的,編譯器對非虛方法使用的是靜態聯編,對於虛方法是使用動態聯編。

 

虛函數的工做原理:
對每個對象都保存一個隱藏的指針,隱藏的指針指向虛函數表。

若是派生類中對基類中的虛函數進行了從新實現,則派生類的虛函數表保存新的函數的地址,

若是派生類中沒有對基類中的虛函數實現,則派生類的虛函數表扔保存基類中的地址。

class base

{

public:

  virtual void printA();

  virtual void printB()

}

class ::public base

{

  void printB();

  virtual void printC();

};

總結一點,虛函數實現機制比較好,可是內存和執行速度會有必定的成本。

 

抽象基類:

這個是一種很高深的能力,在設計基類的時候應該先構建出出編程中所須要的類,以及他們之間的關係,抽象基類更清晰、複雜度更低,在基於組件的編程模型中很常見。

 

繼承和內存中的分配,這個剛開始沒有搞清楚,固然如今也沒有搞清楚。

抽象能力。

相關文章
相關標籤/搜索