程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> c++三大特性之繼承

c++三大特性之繼承

編輯:關於C++

1、概念:

繼承(inheritance)機制是面向對象程序設計使代碼可以復用的最重要的手段,它允許程序員在保持原有類特性的基礎上進行擴展,增加功能。這樣產生新的類,稱派生類。繼承呈現了面向對象程序設計的層次結構,體現了由簡單到復雜的認知過程。

一個新類從已有的類中獲得其已有的特性稱為繼承,被繼承的稱為父類(Base class)或基類,新產生的類稱為派生類或子類。

2、繼承的方式:

繼承權限規則表

繼承方式

基類的public成員

基類的protected成員

基類的private成員

繼承引起的訪問控制變化

Public

Public

Protected

不可見

基類成員在派生類中訪問權限不變

Protected

Protected

Protected

不可見

基類的非私有成員成為子類的保護成員

Private

Private

Private

不可見

基類的所有成員成為子類的私有成員

class Base

{

public:

Base()

{

_pri = 1;

_pro = 2;

_pub = 3;

}

private:

int _pri;

protected:

int _pro;

public:

int _pub;

};

class Derived1 :public Base

{

public:

Derived1()

{

_d1_pri = 4;

_d1_pro = 5;

_d1_pub = 6;

}

void showd()

{

_pub = 0; // 仍為public成員

_pro = 2; // 仍為protected成員

//_pri = 3; // 父類私有成員對子類 不可見

}

private:

int _d1_pri;

protected:

int _d1_pro;

public:

int _d1_pub;

};

void TestPublic()

{

Base b;

b._pub = 1;

//b._pro = 2; // 父類對象不可訪問父類保護成員

//b._pri = 3; // 父類對象不可訪問父類私有成員

Derived1 d1;

d1._pub = 1; // 子類對象可以訪問父類公有成員

//d1._pro = 2; //子類對象不可訪問父類保護成員

//d1._pri = 3; // 子類對象不可訪問父類私有成員

d1._d1_pub = 4;

}

// protected 保護繼承

class Derived2 :protected Base

{

public:

Derived2()

{

_d2_pri = 4;

_d2_pro = 5;

_d2_pub = 6;

}

void showd()

{

_pub = 1; // 變為子類的protected成員

_pro = 2; // 仍為protected成員

//_pri = 3; // 父類私有成員對子類不可見

}

private:

int _d2_pri;

protected:

int _d2_pro;

public:

int _d2_pub;

};

void TestProtected()

{

Base b;

b._pub = 1;

//b._pro = 2; // 父類對象不可訪問父類保護成員

//b._pri = 3; // 父類對象不可訪問父類私有成員

Derived2 d2;

//d2._pub = 1; // 父類的public成員權限被修改為protected,子類對象不可訪問

//d2._pro = 2; //子類對象不可訪問父類保護成員

//d2._pri = 3; // 子類對象不可訪問父類私有成員

d2._d2_pub = 4;

}

// private私有繼承

class Derived3 :private Base

{

public:

Derived3()

{

_d3_pri = 4;

_d3_pro = 5;

_d3_pub = 6;

}

void showd()

{

_pub = 1; // 變為子類的privite成員

_pro = 2; // 變為子類的privite成員

//_pri = 3; // 父類私有成員對子類不可見

}

private:

int _d3_pri;

protected:

int _d3_pro;

public:

int _d3_pub;

};

void TestPrivate()

{

Base b;

b._pub = 1;

//b._pro = 2; // 父類對象不可訪問父類保護成員

//b._pri = 3; // 父類對象不可訪問父類私有成員

Derived3 d3;

//d3._pub = 1; // 父類的public成員權限被修改為private,子類對象不可訪問

//d3._pro = 2; // 父類的protected成員權限被修改為private,子類對象不可訪問

//d3._pri = 3; // 子類對象不可訪問父類私有成員

d3._d3_pub = 4;

}

3、繼承又可以分為單繼承,多繼承,鑽石繼承(又叫菱形繼承),現在來談論下三種情況下派生類的布局:

(1)單繼承:

#include

using namespace std ;

class Base

{

public:

Base(int a= 0, int b= 1):_a(a),_b(b)

{

cout << "我是基類的構造函數" <

 

\

 

為啥子類對象賦值給父類對象可以,父類對象賦值給子類對象不可以?

原因就是子類對象賦值給父類對象時,子類對象發生對象切片,將子類對象的父類部分賦值給父類對象,但是父類對象賦值給子類對象時,沒有辦法對子類自己的成員賦值,所以父類對象賦值給子類對象不可以。

(2)多繼承

#include

using namespace std ;

class Base1

{

public:

Base1(int a= 0, int b= 1):_a(a),_b(b)

{

cout << "我是基類的構造函數" <從結果我們能分析,先調用base2的構造函數,在調用base1的構造函數,最後調用自己的構造函數,析構函數相反,這就說明先繼承誰先調用誰的構造函數,子類的成員布局如下:

 

\

 

(3) 菱形繼承:#include

using namespace std ;

class Base1

{

public:

Base1(int a= 0, int b= 1):_a(a),_b(b)

{

cout << "我是基類的構造函數" <

 

\

 

派生類Derived對象d成員布局如下:

 

\

 

從派生類對象成員布局可以看出,派生類對象繼承了兩份Base類成員,所以d._a訪問不明確,因此虛繼承的語法出現了。#include

using namespace std ;

class Base1

{

public:

Base1(int a= 0, int b= 1):_a(a),_b(b)

{

cout << "我是基類的構造函數" <

 

\

 

從結果分析我們能看出只是繼承了一份基類,但是對象的大小變成了28,說明派生類中有8個字節是系統給我們自動加上的。

 

\

 

從圖中我們可以看出確實只是繼承了一份繼承,但是基類的布局和原來的布局不一樣,現在基類在最低下,Derived1中插入一個指針,指向一個表,表中存放了Deriverd1相對於基類的偏移量,Derived2也存放一個指針,同樣指向一個表,這個表中同樣存放了Derived2相對於基類的偏移量。從圖中我們看出虛繼承內存不一樣的機制解決了變量的二義性問題。4.繼承綜合案例:#include

using namespace std ;

namespace

{

class Base

{

public:

Base(int a):_a(a)

{

cout << "我是基類的構造函數" <

 

\

 

5.繼承注意點:(1)父類的構造、析構、拷貝構造、重載賦值運算符,友元函數不能繼承。(2)基類沒有缺省構造函數,派生類必須要在初始化列表中顯式給出基類名和參數列表。

(3)基類沒有定義構造函數,則派生類也可以不用定義,全部使用缺省構造函數。

(4)、基類定義了帶有形參表構造函數,派生類就一定定義構造函數 (無參或者帶參)

(5)繼承時,先調用父類的構造函數,再調用組合對象的構造函數,最後調用自己的構造函數,析構時相反。

(6) public繼承是is-a關系,private繼承和組合對象是has-a關系。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved