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,基类对象不能显式转换成派生类
大材小用式赋值——派生类对象赋值给基类对象。
说明:
﹡可以用公用派生类对象对其基类对象赋值,在赋值时舍弃派生类自己的成员。
﹡事实上,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题。
﹡请注意:赋值后不能企图通过基类对象访问派生类成员。
⑵ 派生类对象可以代替基类对象向基类对象的引用进行初始化:
如,已定义了基类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点:
转换规则:
因为,派生类对象指针将失去访问派生类成员的功能,会出现语法错误。
p_b1 = p_a1; ×
因为,派生类指针除了能够访问派生类的功能,还能访问基类 的功能。而基类指针仅仅只能访问基类的功能。
此时,基类指针只能访问派生类从基类继承的功能,不能访问 派生类自身的功能。除非对基类指针作强制类型转换。
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; ×
类对象、对象指针、对象引用转换的必要条件:
基类和派生类必须是通过公有继承方式联系起来的,则相互之间可以进行隐式类型转换和赋值。