最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++繼承的賦值轉(zhuǎn)換與菱形虛擬繼承深入詳解

 更新時間:2022年08月03日 10:31:11   作者:Rookiep  
今天我要給大家介紹C++中更深入的內(nèi)容了,C++繼承的賦值轉(zhuǎn)換與菱形虛擬繼承。C++這門語言為了使代碼不冗余,做了些什么操作呢?C++的繼承就很好地實現(xiàn)了類層次的代碼復(fù)用,今天我就要來和大家好好聊一聊它了

一、繼承的概念及定義

繼承是面向?qū)ο笕筇匦灾弧?/p>

1.1、繼承的概念

繼承(inheritance)機制是面向?qū)ο蟪绦蛟O(shè)計使代碼可以復(fù)用的最重要的手段,它允許程序員在保持原有類特性的基礎(chǔ)上進(jìn)行擴展,增加功能,這樣產(chǎn)生新的類,稱派生類。繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計的層次結(jié)構(gòu),體現(xiàn)了由簡單到復(fù)雜的認(rèn)知過程。以前我們接觸的復(fù)用都是函數(shù)復(fù)用。繼承是類設(shè)計層次的復(fù)用。

1.2、繼承的定義

繼承的語法:class 子類 : 繼承方式 父類

繼承方式:

  • 共有繼承
  • 私有繼承
  • 保護繼承

基類private成員在派生類中無論以什么方式繼承都是不可見的。這里的不可見是指基類的私有成員還是被繼承到了派生類對象中,但是語法上限制派生類對象不管在類里面還是類外面都不能去訪問它。

二、基類和派生類對象賦值轉(zhuǎn)換

  • 派生類對象可以賦值給基類的對象/基類的指針/基類的引用。這里有個形象的說法叫切片或者切割。寓意把派生類中父類那部分切來賦值過去。
  • 基類對象不能賦值給派生類對象。
  • 基類的指針或者引用可以通過強制類型轉(zhuǎn)換賦值給派生類的指針或者引用。但是必須是基類的指針是指向派生類對象時才是安全的。

class person{
protected:
	string _name;
	int _age;
};
class student :public person
{
public:
	int _No;
};
void test01()
{
	student sobj;
	//1.子類對象可以賦值給父類對象/指針/引用
	person pobj = sobj;
	person* pp = &sobj;
	person& rp = sobj;
	//2.基類對象不可以賦值給派生類對象
	//sobj = pobj;
	//3.基類的指針可以通過強制類型轉(zhuǎn)換賦值給派生類的指針
	pp = &sobj;
	student* ps1 = (student*)pp;//這種情況是可以的
	ps1->_No = 10;
	pp = &pobj;
	student* ps2 = (student*)pp;//這種情況轉(zhuǎn)換時雖然可以,但存在越界訪問的問題
	ps2->_No = 10;
}

三、繼承中的作用域

3.1、繼承同名成員處理方式

??問題:當(dāng)子類與父類出現(xiàn)同名的成員,如何通過子類對象,訪問到子類或父類中同名的數(shù)據(jù)呢?

class Base {
public:
	Base(){
		m_A = 100;
	}
	void func(){
		cout << "Base - func()調(diào)用" << endl;
	}
	void func(int a){
		cout << "Base - func(int a)調(diào)用" << endl;
	}
public:
	int m_A;
};
class Son : public Base {
public:
	Son(){
		m_A = 200;
	}
	//當(dāng)子類與父類擁有同名的成員函數(shù),子類會隱藏父類中所有版本的同名成員函數(shù)
	//如果想訪問父類中被隱藏的同名成員函數(shù),需要加父類的作用域
	void func()
	{
		cout << "Son - func()調(diào)用" << endl;
	}
public:
	int m_A;
};
void test01()
{
	Son s;
	cout << "Son下的m_A = " << s.m_A << endl;
	cout << "Base下的m_A = " << s.Base::m_A << endl;
	s.func();
	s.Base::func();
	s.Base::func(10);
}

??????總結(jié):

  • 子類對象可以直接訪問到子類中同名成員
  • 子類對象加作用域可以訪問到父類同名成員
  • 當(dāng)子類與父類擁有同名的成員函數(shù),子類會隱藏父類中同名成員函數(shù),加作用域可以訪問到父類中同名函數(shù)。
  • 當(dāng)然父類對象隨便調(diào)用父類成員。

注:子類和父類中有同名成員時構(gòu)成隱藏關(guān)系,也叫重定義。需要注意的是,如果是成員函數(shù)的隱藏,只需要函數(shù)名相同就構(gòu)成隱藏。

3.2、繼承同名靜態(tài)成員處理方式

??:問題:繼承中同名的靜態(tài)成員在子類對象上如何進(jìn)行訪問?

靜態(tài)成員和非靜態(tài)成員出現(xiàn)同名,處理方式一致:

  • 子類對象訪問子類同名成員 直接訪問即可
  • 子類對象訪問父類同名成員 需要加作用域
class Base {
public:
	static void func()
	{
		cout << "Base - static void func()" << endl;
	}
	static void func(int a)
	{
		cout << "Base - static void func(int a)" << endl;
	}
	static int m_A;
};
int Base::m_A = 100;
class Son : public Base {
public:
	static void func()
	{
		cout << "Son - static void func()" << endl;
	}
	static int m_A;
};
int Son::m_A = 200;
//同名成員屬性
void test01()
{
	//通過對象訪問
	cout << "通過對象訪問: " << endl;
	Son s;
	cout << "Son  下 m_A = " << s.m_A << endl;
	cout << "Base 下 m_A = " << s.Base::m_A << endl;
	//通過類名訪問
	cout << "通過類名訪問: " << endl;
	cout << "Son  下 m_A = " << Son::m_A << endl;
	cout << "Base 下 m_A = " << Son::Base::m_A << endl;
}
//同名成員函數(shù)
void test02()
{
	//通過對象訪問
	cout << "通過對象訪問: " << endl;
	Son s;
	s.func();
	s.Base::func();
	cout << "通過類名訪問: " << endl;
	Son::func();
	Son::Base::func();
	//出現(xiàn)同名,子類會隱藏掉父類中所有同名成員函數(shù),需要加作作用域訪問
	Son::Base::func(100);
}

總結(jié):同名靜態(tài)成員處理方式和非靜態(tài)處理方式一樣,只不過有兩種訪問的方式(通過對象 和 通過類名)

3.3、繼承與友元

友元關(guān)系不可以繼承,也就是說基類的友元不要可以訪問子類的私有成員和保護成員。

(就好比說爸爸的朋友不一定是我的朋友)

3.4、繼承與靜態(tài)成員

基類定義了static靜態(tài)成員,則整個繼承體系只有這一個成員(我們知道靜態(tài)成員是整個類共享的),無論派生出多少個子類,都只有這么一個static成員。

class person
{
public:
	person()
	{
		_count++;
	}
protected:
	string _name;
public:
	static int _count;//統(tǒng)計人數(shù)
};
int person::_count = 0;
class student:public person
{
protected:
	int _stuNum;
};
class graduate :public student
{
protected:
	string course;
};
void test()
{
	student s1;
	student s2;
	student s3;
	graduate s4;
	cout << "人數(shù)" << person::_count << endl;
	student::_count = 0;
	cout << "人數(shù)" << person::_count << endl;
}

人數(shù)4
人數(shù)0
請按任意鍵繼續(xù). .

代碼解釋:因為子類對象構(gòu)造是會調(diào)用基類的構(gòu)造函數(shù),所以每實例化一個子類對象都會調(diào)用一次基類構(gòu)造,從而_count++,并且靜態(tài)成員是整個類共享的,所以無論哪個子類都可修改!?。?/p>

四、派生類的默認(rèn)成員函數(shù)

6個默認(rèn)成員函數(shù),“默認(rèn)"的意思就是指我們不寫,編譯器會變我們自動生成一個,那么在派生類中,這幾個成員函數(shù)是如何生成的呢?

  1. 派生類的構(gòu)造函數(shù)必須調(diào)用基類的構(gòu)造函數(shù)初始化基類的那一部分成員。如果基類沒有默認(rèn)的構(gòu)造函數(shù),則必須在派生類構(gòu)造函數(shù)的初始化列表階段顯示調(diào)用。
  2. 派生類的拷貝構(gòu)造函數(shù)必須調(diào)用基類的拷貝構(gòu)造完成基類的拷貝初始化。
  3. 派生類的operator=必須要調(diào)用基類的operator=完成基類的復(fù)制。
  4. 派生類的析構(gòu)函數(shù)會在被調(diào)用完成后自動調(diào)用基類的析構(gòu)函數(shù)清理基類成員。因為這樣才能保證派生類對象先清理派生類成員再清理基類成員的順序。
  5. 派生類對象初始化先調(diào)用基類構(gòu)造再調(diào)派生類構(gòu)造。
  6. 派生類對象析構(gòu)清理先調(diào)用派生類析構(gòu)再調(diào)基類的析構(gòu)。
class person
{
public:
	person(const char* name = "pxl")
		:_name(name)
	{}
	person(const person& p)
		:_name(p._name)
	{}
	person& operator=(const person& p)
	{
		if (this != *p){
			_name = p._name;
		}
		return *this;
	}
	~person()
	{}
protected:
	string _name;
};
class student :public person
{
public:
	student(const char* name, int num)
		:person(name)//顯示調(diào)用基類的構(gòu)造函數(shù)初始化基類成員
		, _num(num)
	{}
	student(const student& s)
		:person(s)//注意這里有個隱式的切片操作 person& p = s;
		, _num(s._num)
	{}
	student& operator=(const student& s)
	{
		if (this != &s){
			person::operator=(s);//調(diào)用基類的operator=完成基類的賦值
			_num = s._num;
		}
		return *this;
	}
	~student()
	{
		cout << "~student()" << endl;
		//注意這里會自動調(diào)用父類析構(gòu)
	}
protected:
	int _num;
};
void test()
{
	student s1("ppp", 20);
	student s2(s1);
	student s3("xxx", 30);
	s1 = s3;
}

??留意代碼中注釋部分!

五、復(fù)雜菱形繼承及菱形虛擬繼承

5.1、繼承分類

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

多繼承:一個子類有兩個或者兩個以上直接父類時稱這個繼承關(guān)系為多繼承

菱形繼承:兩個派生類繼承同一個基類,又有某個類同時繼承者兩個派生類。菱形繼承帶來的主要問題是子類繼承兩份相同的數(shù)據(jù),導(dǎo)致資源浪費以及毫無意義。

利用虛繼承可以解決菱形繼承問題

????????????????????????????????????????????????????????

對于菱形繼承的二義性問題,我們可以在訪問的時候加上類域,這樣是可以解決的,但是數(shù)據(jù)冗余無法解決。所以下面引入虛擬繼承!

5.2、虛擬繼承解決菱形繼承問題原理

為了研究虛擬繼承原理,我們給出一個簡單的菱形繼承體系,再借助內(nèi)存窗口觀察對象成員模型。

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;
	system("pause");
	return 0;
}

如圖是菱形繼承的內(nèi)存對象成員模型,可以看出來數(shù)據(jù)冗余?。。?/p>

下面是菱形虛擬繼承的內(nèi)存對象成員模型:

這里可以分析出D對象將A放在了對象組成的最下面,這個A同時屬于B和C,那么B和C如何去找到公共的A呢?

這里通過B和C的兩個指針,指向一張表。這兩個指針叫虛基表指針,這兩個表叫虛基表,虛基表中存的是偏移量。通過偏移量可以找到下面的A。

到此這篇關(guān)于C++繼承的賦值轉(zhuǎn)換與菱形虛擬繼承深入詳解的文章就介紹到這了,更多相關(guān)C++繼承的賦值轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于C語言自制華容道游戲的示例代碼

    基于C語言自制華容道游戲的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C語言自制華容道游戲,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C語言有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-03-03
  • C++ 中

    C++ 中"emplace_back" 與 "push_back" 的區(qū)別

    這篇文章主要介紹了C++ 中"emplace_back" 與 "push_back" 的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • 詳解C語言中的常量指針和指針常量

    詳解C語言中的常量指針和指針常量

    這篇文章主要介紹了詳解C語言中的常量指針和指針常量,包括其之間的區(qū)別是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-08-08
  • Linux網(wǎng)絡(luò)編程之基于UDP實現(xiàn)可靠的文件傳輸示例

    Linux網(wǎng)絡(luò)編程之基于UDP實現(xiàn)可靠的文件傳輸示例

    這篇文章主要介紹了Linux網(wǎng)絡(luò)編程之基于UDP實現(xiàn)可靠的文件傳輸示例,是很實用的技巧,需要的朋友可以參考下
    2014-08-08
  • C語言尋找無向圖兩點間的最短路徑

    C語言尋找無向圖兩點間的最短路徑

    這篇文章主要為大家詳細(xì)介紹了C語言尋找無向圖兩點間的最短路徑,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 解讀C++中枚舉(enum)的使用

    解讀C++中枚舉(enum)的使用

    對于開發(fā)C++來說,枚舉是一個幾乎必然用到的功能。當(dāng)然今天要講的枚舉肯定不是平常漫不經(jīng)心的使用,而是從里到外地深扒它。本文就來逐漸揭開它神秘地面紗,發(fā)現(xiàn)一些未曾注意到的東西吧
    2023-03-03
  • C/C++語言八大排序算法之桶排序全過程示例詳解

    C/C++語言八大排序算法之桶排序全過程示例詳解

    這篇文章主要為大家介紹了C/C++語言八大排序算法之桶排序算法過程的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • C++中的RAII機制詳解

    C++中的RAII機制詳解

    這篇文章主要介紹了C++中的RAII機制詳解,RAII是Resource Acquisition Is Initialization的簡稱,是C++語言的一種管理資源、避免泄漏的慣用法,需要的朋友可以參考下
    2014-09-09
  • C++之默認(rèn)參數(shù)詳解

    C++之默認(rèn)參數(shù)詳解

    這篇文章主要介紹了C++的默認(rèn)參數(shù),是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-11-11
  • 一文搞懂C++多態(tài)的用法

    一文搞懂C++多態(tài)的用法

    C++多態(tài)是在繼承的基礎(chǔ)上實現(xiàn)的,了解多態(tài)之前我們需要掌握一定的C++繼承的知識,本文將介紹C++中多態(tài)的概念,構(gòu)成條件以及用法,感興趣的可以學(xué)習(xí)一下
    2022-04-04

最新評論

清远市| 景洪市| 贵德县| 敦煌市| 宝清县| 耒阳市| 左云县| 白山市| 浮梁县| 榆树市| 巫溪县| 武陟县| 潢川县| 永吉县| 钟山县| 阿荣旗| 阳东县| 蓝田县| 鹤壁市| 罗定市| 商都县| 河源市| 华阴市| 钟祥市| 永和县| 缙云县| 湾仔区| 广德县| 水城县| 胶州市| 西乌珠穆沁旗| 济南市| 临沂市| 棋牌| 大同县| 富裕县| 阿鲁科尔沁旗| 兴海县| 盐亭县| 奎屯市| 周至县|