C++ primer讀書筆記10-繼承,primer10-

來源:互聯網
上載者:User

C++ primer讀書筆記10-繼承,primer10-
封裝,繼承,多態是C++的三大基本概念,這裡著重總結一下繼承相關的東西


1 類衍生的資料行表
類衍生的資料行表指定衍生類別要繼承的基類,衍生的資料行表中有一個或者多個基類如:
class B : public A1,protected A2,private A3
但是單繼承時最常見的,多繼承不多見


2 衍生類別的定義
衍生類別繼承時,會包含父類的所有成員,即便私人成員不能被訪問。父類中的虛函數,在衍生類別中一般也要定義,如


果不定義的話,衍生類別將繼承基類的虛函數


3 基類必須是已經定義的
一個僅僅聲明的類,是不能出現在衍生類別的類衍生的資料行表中。因此衍生類別很可能要訪問基類的列表,但是如果基類還沒


被定義,所以這樣做是錯誤的。


4 衍生類別的聲明
衍生類別的列表不能出現在衍生類別的列表中,如:
class B : public A; //error
正確的聲明應是:
Class B;
Class A;


5 繼承修飾符
C++中的繼承方式有三種,public,protected,private繼承(簡稱3p)。不管是何種繼承方式,基類中的private成員


都不能被派生的使用者代碼和成員定義代碼訪問。接下來具體說說三種繼承方式:
<1>private繼承,基類的所有成員在衍生類別中都是private成員,但是基類的private成員依舊不能被訪問
<2>protected繼承,基類的public,protected成員變成子類的protected成員,基類的private成員依舊不能被訪問
<3>public繼承,基類的public變成衍生類別的public,protected變成衍生類別的protected,基類的private不能被訪問


6 protected 修飾符
當protected修飾類成員的時候,類成員可以被類自身成員定義所使用,但是不能被使用者代碼使用,這點類似private
其次,protected修飾的成員可以被子類訪問到,這點類似public,但是不用於private。


7 不能被繼承的成員
建構函式,複製控製成員(複製建構函式,賦值操作符,解構函式)這是不能被繼承的函數


8 衍生類別的建構函式
衍生類別建構函式一般格式:
DeriveClass(xxx):baseClass(xxx),x1(x),x2(x)....
<1> 衍生類別的建構函式除了要初始化自己新定義的成員外,還要初始化基類的成員,順序是先調用基類的建構函式初始化基類的成員,然後再初始化自己的新成員(順序是聲明的順序)
<2> 如果沒有自己定義建構函式,編譯器會合成一個預設的建構函式,先調用基類的預設建構函式,然後就再去初始化其他新的成員。
<3> 這裡需要注意的是:如果基類沒有預設建構函式,那麼編譯器就不能合成預設建構函式,如果這個時候再不去定義衍生類別的預設建構函式,那樣就會出錯。諸如--“error C2512: “Derive”: 沒有合適的預設建構函式可用。”
<4> 如果不在衍生類別建構函式的初始化列表中指定基類的建構函式,則會調用基類的預設建構函式
<5> 衍生類別建構函式的預設實參衍生類別可以將建構函式的所有參數都設定為預設參數,可以使用0-n個預設參數

9 衍生類別中的複製控制
複製控制包括複製建構函式,賦值操作符,解構函式
<1>沒有定義複製建構函式,編譯器會自己合成一個複製建構函式,它會調用基類的複製建構函式
<2>自訂複製建構函式,一般要調用基類的複製建構函式,否則會出意外
<3>沒有定義賦值操作符,編譯會自動合成一個賦值操作符,它會調用基類的複製操作符
<4>自訂賦值操作符要提防自身賦值,一般都是這麼做

Derive& Derived::operator =(Derived& rh){if(this != &rh){Base::operator=(rh);//do whatever needed to clean up the old value//assign the members from the derived}}

這樣做的原因就是為了防止自身賦值,在自身賦值的時候,我們通常要先把動態開闢的記憶體clear掉,如果不加上if(this != &rh)的話,那麼在進行自身賦值的時候,就會把自己給廢了(clear掉自己)。
<5> 衍生類別解構函式
這個和前兩個不同,衍生類別的解構函式只負責自己新定義對象的析構,不負責基類對象的析構。在衍生類別對象析構的時候,編譯器會先調用衍生類別自己的解構函式,然後調用基類的解構函式。每個類不管基類還是衍生類別,都只負責清除自己的成員。
以上的複製控制範例程式碼如下所示:
#pragma once#include <iostream>using namespace std;class Base{public:Base(){ m = 10;cout<<"Base default constructor"<<endl;}Base(int x):m(x){}Base(Base& rh){cout<<"the base copy constructor"<<endl;};~Base(void){cout<<"Base destructor"<<endl;}Base& operator = (Base& base){ this->m = base.m;cout<<"the base operator ="<<endl;return *this;} private:int m;};class Derive :public Base{public:~Derive(void){cout<<"Derived destructor"<<endl;}private:int mx;};void main(){Derive X;cout<<"this is the separtor-----------------"<<endl;Derive Y = X;Y = X;}

執行結果:
Base default constructor
this is the separtor-----------------
the base copy constructor
the base operator =
Derived destructor
Base destructor
Derived destructor
Base destructor


10 衍生類別函數的調用
在繼承的情況下,衍生類別的範圍嵌套在基類的範圍中,如果不能再衍生類別中確定名字,就會在外圍的基類中朝趙名字的定義。
<1>衍生類別調用函數是這樣的原則:先在衍生類別中尋找名字,查到就停止;查不到的就在基類中尋找。
<2>靜態類型,動態類型
靜態類型:是指不需要考慮運算式的執行期語義,僅剖析器文本而決定的運算式類型。靜態類型僅依賴於包含運算式的程式文本的形式,而在程式運行時不會改變
動態類型:由一個左值運算式表示的左值所引用的最終派生對象的類型。一個右值運算式的動態類型,就是它的靜態類型。
<3>對象,引用或者指標的靜態類型決定了對象能夠執行的行為
因此引用或者指標不能執行衍生類別中新定義的成員名字。
<4>基類與衍生類別的名字發生衝突
基類與衍生類別中有相同的名字的時候,衍生類別會屏蔽基類中同名的成員。如果非要調用基類的成員,那麼就必須顯式的調用,如:Base::func();
<5>基類成員函數的屏蔽
基類和衍生類別有相同名字的函數,但是原型不一樣(參數),那麼衍生類別將不能直接調用基類的那個同名的函數。根據之前的原則,找到名字相同的就不再往基類找了,所以下面的程式是錯誤的。
class A{public:void fun(){};}class B : public A{public:void fun(int){};private int x;}B b;b.fun(11); //OKb.func();  //error

11 using
可以在衍生類別中使用using來改變繼承自基類中的成員的層級,前提是衍生類別對基類的成員具有存取權限。
//Base.h#pragma once#include <iostream>using namespace std;class Base{public:Base(void){ n = 100; };~Base(void){};size_t size()const{return n;}protected://private:size_t n;int fn(int x){return x;};int fn(){return 11;}};

//Derived.h#pragma once#include "base.h"class Derived :private Base{public:Derived(void){};~Derived(void){};using Base::size;using Base::fn;};

//main.cpp#include "Base.h"#include "Derived.h"#include <iostream>using namespace std;void main(){Derived XX;Base YY;cout<<XX.size()<<endl;cout<<XX.fn()<<endl;cout<<XX.fn(2)<<endl;system("pause");}

在這裡我們也可以看到如果基類的函數有重載的話,針對同一個using Base::XXX,可以使所用的名字為XXX的基類函數在衍生類別中得到聲明。真可可謂一次聲明,多個使用。


12 friend 跟繼承的關係
友元跟繼承沒有關係。基類的衍生類別不能被基類的衍生類別訪問。友元類的衍生類別對基類沒有存取權限。


13 引用轉換,轉換對象
引用轉換:衍生類別對象轉換為基類類型的引用
轉換對象:用衍生類別對象轉換為基類的對象,這個時候形參是固定的,編譯和運行時候的對象都是基類類型對象。衍生類別的基類部分被複製到形參中。
引用轉換:衍生類別對象轉換為基類的引用。但是如果賦值的話也是把衍生類別的基類部分賦值給基類對象,這和指標的切片效應一個道理。


14 基類和衍生類別的轉換
衍生類別轉對象賦給基類也是有條件才能行的,這個條件就是衍生類別是通過public來繼承的,這樣的話不論是在成員代碼還是在使用者代碼中,都能實現 
Derived d;Base b = d;

如果是通過protected繼承的,那麼只能在成員定義中使用這樣的代碼。


15 預設的繼承準則
類和結構體在預設的繼承準則方面剛好相反。
<1>類繼承的時候,如果不加限定符,那麼預設是private繼承,結構體不加限定符的時候,則是預設的public繼承。
<2>此外strut中從定義開始到內部的第一個限定符之間預設的是public修飾,但是class預設的是private修飾。

 
看完《C Primer Plus》後可以學習C++?

C和C++ 在編程邏輯上是一樣的,只是抒寫的語言不一樣,並且C++的好處就是它物件導向,用起來比較的方便,更類似於java。如果想學C++,建議還是結合一本專門講C++的書看看,“C++入門到精通.pdf”,從文法上開始學吧,多寫多練,才能掌握的更好。
 
讀了c++ primer plus還有必要讀c primer plus

從內容上看C Primer Plus比C++ Primer Plus稍加全面,但畢竟還是C,內容的多面性比C++ Primer Plus相差不少。。所以我建議隨便看看,花一個小時左右把書從頭看到尾就可以了。如果不看,可能你的知識不會太全面。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.