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".
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/242954.html
標籤:其他
