【一天一篇CPP】基类与派生类的转换(单向:从派生类赋值给基类,舍弃一部分)

时间:2022-09-07 21:16:57

我们知道一般的赋值兼容,如double d,  int  i,  int *ip;  d = i 可以直接赋值,  i = d 可以舍弃小数赋值,而 ip = 1024 则出现错误,要添加强制转换,如 ip = (int *) 1024,则不算赋值兼容。

不同数据之间的自动转换和赋值,称为赋值兼容。


1. 那么基类对象和派生类对象是否存在赋值兼容关系?

存在,但是是单向的【从派生类赋值给基类,舍弃其它部分】,而且只能赋值数据成员【为什么?因为赋值函数成员会导致混乱】只有公有继承才能赋值【为什么?因为私有继承和保护继承的基类成员在类的外部是不可见的,防止意外操作】

2. 如何赋值?什么情况下系统会自动转换?

A 派生类可以向基类对象赋值,

【假如 B 继承于 A 】A a1;  B b1;  a1 = b1;在赋值的时候舍弃派生类自己的成员,“大材小用”。

一个例子【注意是公有继承】:

#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A(int i) : a(i){}//构造函数
	void COUT() {cout << a <<endl;}
private:			
	int a;
};

class B : public A
{
public: 
	B(int i) : A(i) {b = 10;}
	int b;
};

int main()
{
	A a1(0);
	B b1(20);
	a1 = b1;	//即使是私有成员a,也将被赋值
	a1.COUT();

	return 0;
}

B 派生类可以向基类对象的引用进行赋值和初始化。【派生类的基类部分和引用具有相同地址】

#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A(int i) : a(i){}//构造函数
private:			
	int a;
};

class B : public A
{
public: 
	B(int i) : A(i) {b = 10;}
	int b;
};

int main()
{
	A a1(10);
	B b1(20);

	A &r = a1;
	r = b1;			//只是一般的赋值操作,引用是不能重定向的
	A &r2 = b1;


	//r和a1具体相同地址,b1的基类部分地址和r2具有相同地址
	cout << &r <<endl;
	cout << &a1 <<endl;
	cout << &b1 <<endl;

	
	cout << &r2 <<endl;
	cout << &b1 <<endl;

	return 0;
}

C 如果函数的参数是基类对象或基类对象的引用,实参也可以是子对象【子对象:基类经过公有继承后的子类的对象】,赋值过程和上面的类似。

void fun(A &r) {cout << r.num <<endl; }                               fun( b1 )

D 派生类的对象的地址可以赋给指向基类对象的指针变量,依然是指向派生类继承于该基类的数据部分的起始地址。


3.一个有趣的实例

#include <iostream>
#include <string>
using namespace std;

class Base{			
	int base;
};

class A{
public:
	A(int i) : a(i){}//构造函数
private:			
	int a;
};

class B : public Base,public A
{
public: 
	B(int i) : A(i) {b = 10;}
	int b;
};

int main()
{
	A a1(10);
	B b1(20);

	A *ap = &b1;

	cout << (int *)ap <<endl;
	cout << (int *)&b1 <<endl;
	
	return 0;
}
请问上面的ap和&b1值相同吗,答案是不同的。因为B类继承了两个父类,一个是Base【这个是B类对象的地址真正指向的类,因为它是第一个父类】,一个是A,而ap是指向B类对象中A类的部分的地址,所以不同。【假如是私有继承和保护继承,那么A *ap = &b1; 操作将产生错误,因为B类中继承于A类的数据在其它地方是不可见的】


4.另一个有趣的问题【假如A和B类都有display()成员函数,且B继承于A】

A *p = b1;则p->display()调用的是A的display函数还是B的display函数呢,答案是A的display()函数。