一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++繼承模式詳解

C++繼承模式詳解

2022-03-09 14:27_End丶斷弦 C/C++

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

繼承

繼承的概念

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

繼承的定義

C++繼承模式詳解

上面的基類也可以叫父類,派生類也可以叫子類。

繼承關系和訪限定符

C++繼承模式詳解

繼承方式

C++繼承模式詳解

接下來用代碼測試上面的繼承方式

class Person
{
public :
void Print ()
{
cout<<_name <<endl;
}
protected :
string _name = "張三" ; // 姓名
private :
int _age = 18 ; // 年齡
};

class Student : public Person
{
protected :
int _stunum = 22; // 學號
};

public繼承

上面是給的缺省值來測試沒寫構造函數

C++繼承模式詳解

s就繼承了Person的name,age,基類中private的age在物理上繼承了但在語法上但是不能訪問的。

C++繼承模式詳解

也可以調用基類的成員函數,但是不能直接訪問基類中private的成員,prootected可以在派生類中訪問,不能再在類外訪問

C++繼承模式詳解

protected繼承

C++繼承模式詳解

protected繼承,在類外連基類的public成員函數都不能用了,只能在派生類的類里面使用。

C++繼承模式詳解

同樣基類中私有的不能訪問

private繼承就都是私有的了。

總結:

  • 1.基類private成員在派生類中無論以什么方式繼承都是不可見的。這里的不可見是指基類的私有成員還是被繼承到了派生類對象中,但是語法上限制派生類對象不管在類里面還是類外面都不能去訪問它。
  • 2.基類private成員在派生類中是不能被訪問,如果基類成員不想在類外直接被訪問,但需要在派生類中能訪問,就定義為protected??梢钥闯霰Wo成員限定符是因繼承才出現的.
  • 3.基類的私有成員在子類中都是不可見的,其他成員在子類中等于權限最小的那個
  • 4.class的默認繼承方式是private,struct默認的繼承方式是public,最好顯示的寫出繼承方式
  • 5.在實際應用一般使用public繼承,很少使用protected和private。

父類和子類對象賦值轉化

class Person
{
protected:
	string _name; // 姓名
	string _sex; // 性別
	int _age; // 年齡
};
class Student : public Person
{
public:
	int _No; // 學號
};

C++繼承模式詳解

子類可以給父類,父類不能給子類,不僅可以是子類的對象,也可以是指針和引用

	Student s;
	Person p;
	p = s;
	Person *ptr = &s;//子類賦給父類指針
	Person &ref = s;//子類賦給父類引用

C++繼承模式詳解

C++繼承模式詳解

C++繼承模式詳解

派生類對象 可以賦值給 基類的對象 / 基類的指針 / 基類的引用。這里有個形象的說法叫切片或者切割。寓意把派生類中父類那部分切來賦值過去。

基類對象不能賦值給派生類對象

基類的指針可以通過強制類型轉換賦值給派生類的指針。但是必須是基類的指針是指向派生類對象時才是安全的。等到子類中的默認函數就會用到切片

 

繼承中的作用域

class Person
{
protected:
	string _name = "法外狂徒"; // 姓名
	int _num = 11; // 身份證號
};
class Student : public Person
{
public:
	void Print()
	{
		cout << " 姓名:" << _name << endl;
		cout << " 身份證號:" << _num << endl;
		cout << " 學號:" << _num << endl;
	}
protected:
	int _num = 2; // 學號
};

C++繼承模式詳解

還有成員函數的隱藏

class A {
public:
	void fun(double x)
	{
		cout << "fun()->x"<< x << endl;
	}
};
class B : public A {
public:
	void fun(int i)
	{
		cout << "fun()->" << i << endl;
	}
};

int main()
{
	B b;
	b.fun(10);
	b.A::fun(11.1);//加作用域
	return 0;
}

父類和子類函數名相同不是重載而是隱藏,函數重載是在同一作用域,不同的作用域是隱藏

在子類成員函數中,可以使用 基類::基類成員 顯示訪問

在寫代碼中最好不要定義同名的成員

 

子類的默認成員函數

在類和對象的時候講了6個默認的成員函數,現在子類中講4個,構造,拷貝構造,賦值和析構

C++繼承模式詳解

class Person //父類
{
public:
	Person(const char* name = "李四")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};
//子類
class Student : public Person
{
public:
	//構造函數
	Student(const char* name, int num)
		: Person(name)//調用父類的構造函數初始化父類的成員
		, _num(num)//初始化子類的成員
	{
		cout << "Student()" << endl;
	}
	//拷貝構造
	Student(const Student& s)
		: Person(s)//這里就用到了切片,切父類的成員類拷貝
		, _num(s._num)//拷貝子類的
	{
		cout << "Student(const Student& s)" << endl;
	}

	Student& operator = (const Student& s)
	{
		cout << "Student& operator= (const Student& s)" << endl;
		if (this != &s)
		{
			Person::operator =(s);//調用父類的賦值
			_num = s._num;//賦值子類自己的
		}
		return *this;
	}

	~Student()
	{
		//子類的析構函數完成清理后會自動調用父類的析構函數
		cout << "~Student()" << endl;
	}
protected:
	int _num; //學號
};

總結:

  • 派生類的構造函數必須調用基類的構造函數初始化基類的那一部分成員。如果基類沒有默認的構造函數,則必須在派生類構造函數的初始化列表階段顯示調用。
  • 派生類的拷貝構造函數必須調用基類的拷貝構造完成基類的拷貝初始化。
  • 派生類的operator=必須要調用基類的operator=完成基類的復制。
  • 派生類的析構函數會在被調用完成后自動調用基類的析構函數清理基類成員。因為這樣才能保證派生類對象先清理派生類成員再清理基類成員的順序。
  • 派生類對象初始化先調用基類構造再調派生類構造。
  • 派生類對象析構清理先調用派生類析構再調基類的析構。

 

繼承與友元

友元關系不能繼承,父類友元不能訪問子類私有和保護成員

class Student;
class Person
{
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name; // 姓名
};
class Student : public Person
{
public:
	friend void Display(const Person& p, const Student& s);
protected:
	int _stuNum; // 學號
};
void Display(const Person& p, const Student& s) {
	cout << p._name << endl;//可以訪問
	cout << s._stuNum << endl;//要在子類中加上友元才能訪問,不加會報錯
}
int main()
{
	Person p;
	Student s;
	Display(p, s);
	return 0;
}

繼承與靜態成員

基類定義了static靜態成員,則整個繼承體系里面只有一個這樣的成員。無論派生出多少個子類,都只有一個static成員實例 。

class Person
{
public:
	Person() { ++_count; }
protected:
	string _name; // 姓名
public:
	static int _count; // 統計人的個數。
};
int Person::_count = 0;
class Student : public Person
{
protected:
	int _id; // 學號
};
class Graduate : public Student
{
protected:
	string _Course; // 科目
};

int main()
{
	Student s1;
	Student s2;
	Student s3;
	Graduate s4;
	cout << " 人數 :" << Person::_count << endl;
	cout << " 人數 :" << Student::_count << endl;
	cout << " 人數 :" << &Person::_count << endl;
	cout << " 人數 :" << &Student::_count << endl;
	return 0;
}

C++繼承模式詳解

再加上count的地址可以看出是同一個的count。計算出子類實例化了多少個對象就可以在父類中定義個count自加。

 

復雜的菱形繼承

單繼承:一個子類只有一個直接父類時稱這個繼承關系為單繼承

C++繼承模式詳解

多繼承:一個子類有兩個或以上直接父類時稱這個繼承關系為多繼承

C++繼承模式詳解

菱形繼承:菱形繼承是多繼承的一種特殊情況。

C++繼承模式詳解

菱形繼承的問題:從下面的對象成員模型構造,可以看出菱形繼承有數據冗余和二義性的問題。在Assistant的對象中Person成員會有兩份。

class Person
{
public:
	string _name; // 姓名
};
class Student : public Person
{
protected:
	int _num; //學號
};
class Teacher : public Person
{
protected:
	int _id; // 編號
};
class Assistant : public Student, public Teacher
{
protected:
	string _Course; // 課程
};
int main()
{
	// 這樣會有二義性無法明確知道訪問的是哪一個
	Assistant a;
	//a._name = "peter";

	// 顯示的調用解決了二義性,但數據冗余了
	a.Student::_name = "蓋倫";
	a.Teacher::_name = "亞索";
	return 0;
}

C++繼承模式詳解

虛繼承

虛擬繼承可以解決菱形繼承的二義性和數據冗余的問題。如上面的繼承關系,在Student和Teacher的繼承Person時使用虛擬繼承,即可解決問題。需要注意的是,虛擬繼承不要在其他地方去使用。

C++繼承模式詳解

在菱形的腰部加上virtual關鍵字可以解決冗余。那虛繼承是怎么解決的呢?先來看看不用虛繼承的

class A {
public:
	int _a;
};

class B :  public A {
public:
	int _b;
};

class C :  public A {
public:
	int _c;
};
class D : public B, public C {
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

我們可以通過內存窗口來觀察對象成員的模型

C++繼承模式詳解

菱形繼承帶來了二義性和數據冗余。

再來看看虛繼承的

C++繼承模式詳解

虛繼承就解決了數據冗余和二義性,B和C中多了地址,在用內存窗口看看這里的地址

C++繼承模式詳解

2個指針叫虛基表指針指向虛基表,可以通過偏移量找到公共虛基類,此時A是在下面那為什么要找呢?

	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	B b = d;//把d賦給b,把d切過去那此時要怎么找到A呢?,所以就要用虛基表找

B類中各個成員在內存中的分布:

C++繼承模式詳解

通過偏移量找到虛基類。

還是不要用菱形繼承出現問題,虛繼承使得對象模型很復雜,并且會有效率的影響。

 

繼承的總結

  • C++語法復雜,其實多繼承就是一個體現。有了多繼承,就存在菱形繼承,有了菱形繼承就有菱形虛擬繼承,底層實現就很復雜。所以一般不建議設計出多繼承,一定不要設計出菱形繼承。否則在復雜度及性能上都有問題。
  • 多繼承可以認為是C++的缺陷之一.

組合

繼承是建立了父類與子類的關系,是一種“是”的關系,例如白貓是貓,組合是“有”的關系實際盡量多去用組合。組合的耦合度低,代碼維護性好。不過繼承也有用武之地的,有些關系就適合繼承那就用繼承,另外要實現多態,也必須要繼承。類之間的關系可以用繼承,可以用組合就用組合。

面試題

  • 什么是菱形繼承?菱形繼承的問題是什么?
    菱形繼承是多繼承的一種特殊繼承,兩個子類繼承同一個父類,而又有子類同時繼承這兩個子類??梢钥闯隽庑卫^承有數據冗余和二義性的問題。
  • 什么是菱形虛擬繼承?如何解決數據冗余和二義性的
    在菱形繼承的腰部加上virtual,通過虛基表指針和虛基表中的偏移量可以找到虛基類,只存1份
  • 繼承和組合的區別?什么時候用繼承?什么時候用組合?
    繼承是一種"是",組合是"有"的關系,父類和子類是的關系用繼承,是有的關系用組合。

以上就是C++繼承,由于作者水平有限,如有問題還請指出!

到此這篇關于C++繼承模式詳解的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/weixin_45599288/article/details/121706542?

延伸 · 閱讀

精彩推薦
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
主站蜘蛛池模板: 美日韩一区二区三区 | 亚洲色图综合网 | 国产伦精一区二区三区视频 | gay 男同志被捆绑茎 | 99热精品国产麻豆 | 日本人啪啪 | 变态 另类 人妖小说 | 校花在公车上被内射好舒服 | 91你懂的 | 日日日操 | 91视频www | 国产伦精品一区二区三区免费迷 | 欧美胖逼| 色老太bbbbb 色老妇 | 亚洲欧美一区二区三区在饯 | 好吊色永久免费视频大全 | 国产欧美精品一区二区三区–老狼 | 99久久国产综合精品网成人影院 | 亚洲天堂精品视频 | 亚洲欧美日韩国产精品影院 | ysav67| 99视频观看 | 美女禁区视频免费观看精选 | 好女孩韩剧免费观看 | 天美传媒果冻传媒星空传媒 | 男人操美女逼视频 | 天天做日日做 | 热久久99精品这里有精品 | 亚洲欧美一区二区三区在线观看 | 亚洲高清国产拍精品动图 | 精品国产免费观看一区高清 | 夫承子液by免费阅读 | 国产成人青草视频 | 特黄特黄aaaa级毛片免费看 | 国产九九在线 | 国产午夜永久福利视频在线观看 | 向日葵视频app下载18岁以下勿看 | 日本高清中文字幕 | 暖暖视频免费观看视频中国.韩剧 | 91混血大战上海双胞胎 | 亚洲国产高清一区二区三区 |