C++的虛擬繼承(基礎)

作者:良知猶存

轉載授權以及圍觀->歡迎添加Wx:Allen-Iverson-me-LYN

前言:本文爲C++使用過程中的一些細節知識補充,碎片化的知識.其中有韋東山老師和其他博主一些知識筆記,在此謝謝韋老師以及各博主的文章博客,受益良多.

一、基類成員在派生類中的訪問控制屬性:

 

    首先派生類是C++中引入派生類,是爲了解決重複代碼的問題,通過使用派生類,程序員只需要在已經存在的類中進行繼承,只需要修改少量的代碼就產生新的類.

    但是繼承的時候,因爲類成員所屬的限定符不同,所以導致繼承的時候,訪問屬性不同.

    下面我們先來描述一下類的三種成員:

  • public (公共成員) ,顧名思義在public限定下的類成員可以被類裏面的成員函數引用,亦可以類之外的其他函數引用.所以在繼承類,public成員可以完整屬性的被繼承.

  • private(私有成員),特指在類中私用的成員,一般爲類的數據成員.這些數據成員一般會被在public的成員函數進行訪問.所以私有成員只能被定義的類的成員函數進行引用,其他類無法進行訪問,此處友員類或者友員函數除外.

  • protect(受保護的成員),此限制符下的成員訪問屬性介於public與private之間.protect標識成員不能被類外訪問,但可以通過繼承的派生類進行訪問.

 

類的幾種訪問限制符瞭解完,下面開始介紹繼承中我們繼承成員的具體訪問情況.

  • 第一種public繼承,由於public是公開的特性,類之外也可以被引用,所以當派生類繼承爲public,private或者protect,public下面的成員會隨着派生類的限定符進行劃歸,也就是繼承到public就是public成員,繼承到protect就是protect成員,繼承到private就是private成員.

  • 第二種protect繼承,由於繼承父類中該成員就是屬於protect所以派生的子類也會受到限制,該成員由於父類已經進行限制,所以繼承的子類到public是無法完整獲得任意訪問的屬性,所以如下圖,繼承到public中的protect成員依舊有protect的屬性限制,繼承到protect和private限制的時候,類成員按照子類的限制符進行訪問。

  • 第三種private繼承,由於private成員是最私密的限制,所以繼承之後全部爲private的權限。

綜上所述,我們發現,繼承的時候該成員是按照繼承的父類以及繼承到的子類的成員限制最大的類型進行繼承的。

    

    繼承示例:​​​​​​

class D{......};class B: public D{......};

注:繼承的時候如果不寫public默認就會私有繼承。

 二、虛擬繼承

    多重繼承容易出現多義,另外多重繼承中出現環繼承,也爲了節省內存空間,所以C++引入虛擬繼承。

多重繼承多義性的代碼片段,參考代碼韋東山C++

#include <iostream>#include <string.h>#include <unistd.h>/*多態*/
using namespace std;class Human{private:    int a;public:    void eating(void){        cout<<"use hand to eat"<<endl;    }};class Englishman : public Human{public:    void eating(void){        cout<<"use knife to eat"<<endl;    }};class Chinese : public Human{public:    void eating(void){        cout<<"use chopsticks to eat"<<endl;    }};void test_eating(Human &h){    h.eating();}int main(int argc,char **argv){    Human h;    Englishman e;    Chinese c;
    test_eating(h);    test_eating(e);    test_eating(c);
    cout<<"Humen       length:="<<sizeof(h)<<endl;    cout<<"Englishman  length:="<<sizeof(e)<<endl;    cout<<"Chinese     length:="<<sizeof(c)<<endl;    return 0;}

    多重繼承使得程序出現二義性,可以用virtual進行虛擬繼承來解決,但是由於多重繼承會使程序變得複雜,所以不建議使用多重繼承。

#include <iostream>#include <string.h>#include <unistd.h>/*多態*/
using namespace std;class Human{private:    int a;public:    virtual void eating(void){        cout<<"use hand to eat"<<endl;    }    ~Human(){        cout<<"~Human()"<<endl;    }};class Englishman : public Human{public:    void eating(void){        cout<<"use knife to eat"<<endl;    }    ~Englishman(){        cout<<"~Englishman()"<<endl;    }};class Chinese : public Human{public:    void eating(void){        cout<<"use chopsticks to eat"<<endl;    }    ~Chinese(){        cout<<"~Chinese()"<<endl;    }};void test_eating(Human &h){    h.eating();}int main(int argc,char **argv){    Human h;    Englishman e;    Chinese c;
    test_eating(h);    test_eating(e);    test_eating(c);
    cout<<"Humen       length:="<<sizeof(h)<<endl;    cout<<"Englishman  length:="<<sizeof(e)<<endl;    cout<<"Chinese     length:="<<sizeof(c)<<endl;       return 0;}

環裝繼承:

 

class A{......};class B: public A{......};class C: public A{......};class D: public B, public C{.....};
class Aclass B:public virtual A;class C:public virtual A;class D:public B,public C;

    降低內存使用的實際原理:虛擬基類中的構造函數只執行一次。並且構造的時候虛擬基類先執行。

using namespace std;class Human {private:  int a;public:  virtual void eating(void) { cout<<"use hand to eat"<<endl; }  virtual ~Human() { cout<<"~Human()"<<endl; }};class Englishman : public Human {public:  void eating(void) { cout<<"use knife to eat"<<endl; }  virtual ~Englishman() { cout<<"~Englishman()"<<endl; }};class Chinese : public Human {public:  void eating(void) { cout<<"use chopsticks to eat"<<endl; }  virtual ~Chinese() { cout<<"~Chinese()"<<endl; }/*析構函數也應該爲虛擬函數*/};void test_eating(Human h){  h.eating();}int main(int argc, char **argv){  Human* h = new Human;  Englishman* e = new Englishman;  Chinese* c = new Chinese;  Human *p[3] = {h, e, c};  int i;  for (i = 0; i < 3; i++)  {    p[i]->eating();    delete p[i];  }  return 0;}

 

 

————————END————————

長按關注,你會得到更多信息.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章