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

来源:互联网 发布:打谱软件muse用法 编辑:程序博客网 时间:2024/05/19 22:51

我们知道一般的赋值兼容,如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()函数。


原创粉丝点击