4.基类与派生类的转换:
对于数值类型变量,C++是一个弱类型语言。它允许不同类型的变量在一定的条件下进行转换:“较小”
类型的数值变量赋值给“较大”类型的数值变量。
如,整型数=>双精度数(隐式类型转换)
对于指针、引用、结构、类等类型变量,C++又是一个强类型语言。它不允许不同类型的变量在同一表达式中出现。
对于基类和派生类对象,C++允许通过公有继承方式联系起来的两个对象间进行隐式转换。
隐式转换规则:
与数值类型隐式转换的规则相反:
将“较大” 的对象(派生类对象)赋值给“较小”的对象(基类对象)。
⑴
派生类对象可以向基类对象赋值:
若定义两个对象:
CPoint point; //CPoint
基类
CRect
rect; //
CRect
派生类
则:
point =
rect;
//O.K,派生类对象赋给基类对象
rect = point;
//error,基类对象不能直接赋给派生类对象
(CPoint)rect = point;
//O.K,派生类对象经过显式类型转换成基类对象
rect =
(CRect)point;
//error,基类对象不能显式转换成派生类
大材小用式赋值——派生类对象赋值给基类对象。
![C++继承性和多态性(五) C++继承性和多态性(五)](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
说明:
﹡可以用公用派生类对象对其基类对象赋值,在赋值时舍弃派生类自己的成员。
﹡事实上,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题。
﹡请注意:赋值后不能企图通过基类对象访问派生类成员。
⑵
派生类对象可以代替基类对象向基类对象的引用进行初始化:
如,已定义了基类A对象a1,可以定义a1的引用:
--------------------------------------
A a1;
//定义基类A对象a1
B b1;
//定义公有派生类B对象b1
A&r=a1;
//定义基类A对象的引用r,并用a1对其初始化
-------------------------------------------------------
A a1;
//定义基类A对象a1
B b1;
//定义公有派生类B对象b1
A&r=b1;
//定义基类A对象的引用r,并用b1对其初始化
--------------------------------------------------------
!!!注意:此时r并不是b1的别名,也不与b1共享同一段存储单元。它只是b1中基类部分的别名,与b1中基类部分共享同一段存储单元。
⑶
如果函数的形参是基类对象或基类对象的引用,相应的实参可以用派生类对象:
如,有一函数fun():
void fun(A&r);
//形参是基类A对象的引用
{
cout<<r.num<<endl;
}
//输出引用r所代表对象的数据成员num
A a1;
B b1;
fun(b1);
//用派生类对象b1作实参传递数据
!!!注意:由于基类和派生类对象能自动隐式转换,故可以用b1代替a1作为实参。此时输出的是派生类B对象b1中的基类数据成员num。
⑷
派生类对象的地址可以赋值给基类对象的指针变量,或说,指向基类的指针也可以指向派生类:
注意2点:
(1)指向不同数据类型的指针和引用是不能互相转换的。这一点对指向不同类对象的指针也适用。
(2)如果两个指针所指向的对象是通过公共继承方式相关联的话,则允许一定程度的赋值转换。
转换规则:
(1)基类对象指针(或引用)赋值给派生类对象指针(或引用)时为不安全转换。
因为,派生类对象指针将失去访问派生类成员的功能,会出现语法错误。
p_b1 =
p_a1; ×
(2)派生类对象指针(或引用)赋值给基类对象指针(或引用)是安
全的。
因为,派生类指针除了能够访问派生类的功能,还能访问基类
的功能。而基类指针仅仅只能访问基类的功能。
此时,基类指针只能访问派生类从基类继承的功能,不能访问
派生类自身的功能。除非对基类指针作强制类型转换。
p_a1 =
p_b1;
√
(B)p_a1 = p_b1;
√
#include<
iostream>
#include< string
>
using namespace
std;
class CPoint
//基类Point类的声明
{private:
int
X,Y;
public:
CPoint(int a=0, int b=0)
{X=a; Y=b;}
void set(int a, int b) {X=a;
Y=b;}
void move(int a, int b)
{X+=a; Y+=b;}
void get(int &r_a,int
&r_b) const
{r_a=X,r_b=Y;}
};
//派生类声明
class CRect: public
CPoint
{ private:
int H,W;
//新增私有数据成员
public:
//新增公有成员函数
CRect(){CPoint::set(0,0);H=0;W=0;}
//调用基类公有成员函数
CRect(int left,int top,int
w_val,int h_val)
{CPoint::set(left,top);
H=h_val;
W=w_val;
}
void
getSize(int &r_h,int &r_w) const
{r_h=H;r_w=W;}
void
set(int left,int top,int w_val,int
h_val)
{CPoint::set(left,top);
W=w_val;
H=h_val;
}
void
print() const
{ int
top,left;
get(left,top);
cout<<" left =
"<<left<<" top =
"<<top<<endl;
}
};
int
main()
{ int
h,w;
CRect rect(20,30,40,50);
//定义一个派生类对象
rect.getSize(h,w);
//调用派生类对象成员函数
cout<<"Rect
height:"<<h<<"
width:"<<w<<endl;
CPoint point(10,10);
//定义一个基类对象
point=rect;
point.move(5,5);
//
point.print();
//
(CRect)point.print();
//
rect=point;
(CPoint)rect=point;
rect.print();
CRect *p_rect=new CRect(10,20,10,10);
p_rect->getSize(h, w);
//用派生类指针调用派生类成员函数
cout<<"Rect height:"<<h<<"
width:"<<w<<endl;
p_rect->move(10, 20);
//用派生类指针调用基类成员函数
p_rect->print();
CPoint
*p_point=p_rect;
p_point->move(10, 20);
//
p_point->print();
((CRect
*)p_point)->print();
p_point=new
CPoint(10,20);
//
p_rect->p_point;
p_point->set(30,40);
((CRect
*)p_point)->print();
delete p_point;
delete p_rect;
return 0;
}
﹡指针(引用)之间:
① 派生类对象指针可以直接赋值给基类指针;(引用)
p_point=p_rect;
√
赋值后的基类指针并不能访问派生类对象成员;除非经过显式的类型转换。
p_point->show();
×
(Crect
*)p_point->show();
√
② 基类对象指针不能直接赋值给派生类对象指针。
p_rect=p_point;
×
﹡指针(引用)之间:
① 派生类对象指针可以直接赋值给基类指针;(引用)
p_point=p_rect;
√
赋值后的基类指针并不能访问派生类对象成员;除非经过显式的类型转换。
p_point->show();
×
(Crect
*)p_point->show();
√
② 基类对象指针不能直接赋值给派生类对象指针。
p_rect=p_point;
×
类对象、对象指针、对象引用转换的必要条件:
基类和派生类必须是通过公有继承方式联系起来的,则相互之间可以进行隐式类型转换和赋值。