1. 程式人生 > 其它 >C++繼承中的賦值相容規則你瞭解多少???

C++繼承中的賦值相容規則你瞭解多少???

技術標籤:指標多型c++資料結構

C++ 賦值相容規則

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

1.派生類物件 可以賦值給 基類的物件

   A a1; //定義基類A物件a1
   B b1; //定義類A的公用派生類B的物件b1
   a1=b1; //用派生類B物件b1對基類物件a1賦值
  • 在賦值時捨棄派生類自己的成員,只進行資料成員的賦值。
  • 實際上,所謂賦值只是對資料成員賦值,對成員函式不存在賦值問題,記憶體中資料成員和成員函式是分開的。
  • 請注意: 賦值後不能企圖通過物件a1去訪問派生類物件b1的成員,因為b1的成員與a1的成員是不同的
  • 只能用子類物件對其基類物件賦值,而不能用基類物件對其子類物件賦值,理由是顯然的,兩種物件的大小是不同的,因為基類物件不包含派生類的成員,無法對派生類的成員賦值。同理,同一基類的不同派生類物件之間也不能賦值。

2.派生類物件 可以賦值給 基類的引用

	A a1; //定義基類A物件a1
    B b1; //定義公用派生類B物件b1
    A& r1=a1; //定義基類A物件的引用變數r1(A的別名是r),並用a1對其初始化這時,r和a1共享同一段儲存單元。也可以用派生類物件初始化引用變數r,將上面最後一行改為
    A& r2=b1;//定義基類A物件的引用變數r2,並用派生類B物件b1//對其初始化
  • 引用的底層實現就是指標,因此引用同理指標
  • 此時r2並不是b1的別名,也不與b1共享同一段儲存單元。它只是b1中基類部分的別名(個人認為這裡的r定義為A類的引用,所以它的有效範圍就只有A類那麼大)

如果函式的引數是基類物件或基類物件的引用,相應的實參可以用子類物件。如有一函式fun():

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class A
{
public:
	int num = 10;

};
class
B: public A { public: int num = 20; }; void fun(A &a1) { cout << a1.num << endl; } int main() { A a1; B b1; A &r1 = a1; cout << r1.num << endl; A &r2 = b1; cout << r2.num << endl; cout << a1.num << endl; cout << b1.num << endl; fun(a1); fun(b1); system("pause"); return 0; }

函式的形參是類A的物件的引用變數,本來實參應該為A類的物件。由於子類物件與派生類物件賦值相容,派生類物件能自動轉換型別, 在呼叫fun函式時可以用派生類B的物件b1作實參: fun(b1); 輸出類B的物件b1的基類資料成員num的值。與前相同,在fun函式中只能輸出派生類中基類成員的值。
輸出結果:
在這裡插入圖片描述

3.派生類物件 可以賦值給 基類的指標

	A a1;
	B b1;
	A* a2 = &a1;//基類指標a2指向基類物件a1;
	A* a3 = &b1;//基類指標指向派生類物件b1;

看看接下來程式碼執行結果:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class A
{
public:
	int num = 10;
	void print()
	{
		cout << "this is A" << endl;
	}

};
class B: public A
{
public:
	int num = 20;
	void print()
	{
		cout << "this is B" << endl;
	}
};
int main()
{
	A a1;
	B b1;
	A* a2 = &a1;
	A* a3 = &b1;
	a2->print();
	a3->print();
	cout << a2->num << endl;
	cout << a3->num << endl;
	system("pause");
	return 0;
	
}

很多人以為a3指向的是派生類的物件b1,而派生類中根據同名隱藏規則,被呼叫的應該是派生類的print()函式,分別輸出"this is A" 和 “this is B” 但結果並非如此。
在這裡插入圖片描述
問題在於:a3是指向派生類物件b1的指標變數,但實際上a3指向的是b1中從基類繼承的部分(它指向的空間只能是基類中資料成員那麼大的空間)。通過指向基類物件的指標,只能訪問派生類中的基類成員,而不能訪問派生
類增加的成員。所以a3->print()呼叫的不是派生類b1物件所增加的print()函式,而是基類的print()函式,所以只輸出"this is A".