C++ 基类与派生类之间的相互引用、赋值问题
这是我第一次真正的自己写C++的文章,前两天在网上找基类与派生类之间的赋值,引用,指针之间的问题是没有找到一个详细介绍的,这也正是我决定写这篇文章的目的。关于显式复制构造函数的声明、定义,转换操作符的声明、定义都在附件中,里面是一个完整的程序。
源程序下载链接:http://download.csdn.net/detail/qq252101792/4196000
// 基类
class Cd { // represents a CDdisk
private:
char * performers;
char * label;
int selections; // number ofselections
double playtime; // playing time inminutes
public:
Cd();
Cd(char * s1, char * s2, int n, double x);
Cd(const Cd & d);
virtual ~Cd();
virtual void Report() const; // reports all CDdata
Cd & operator=(const Cd & d);
};
//派生类
class Classic:public Cd{
private:
char * master; //Titlemusic
public:
Classic();
Classic(char *s1, char *s2, char *s3, int n, double x);
Classic(const Classic &p);
Classic(const Cd &d);
virtual ~Classic();
virtual void Report() const;
Classic & operator=(const Classic &p);
Classic & operator=(const Cd &d);
};
定义下面2个变量:
Cd c1("Beatles", "Capitol", 14, 35.5);
Classic c2 = Classic("Piano Sonatain B flat, Fantasia in C", "AlfredBrendel", "Philips", 2, 57.17);
一、指针和引用兼容性
Cd *pcd ;
Classic *plus ;
pcd = c1; //valid
pcd = c2; //valid
plus = c1; //ivalid
plus = (Classic *)c1; //valid
在C++中,将派生类引用或指针转换为基类引用或指针被称为“向上强制转换”,这使公有继承不需要进行显式强制类型转换。Classic对象都是Cd对象,因为它继承了Cd对象的所有数据成员和成员函数,所以对Cd对象执行的任何操作都适用于Classic对象,而不必担心会导致任何问题。
相反的过程,将基类引用或者指针转换为派生类引用或指针被称为“向下强制转换”,如果不进行显式强制类型转换,向下强制转换是不允许的。继承是不可逆的。派生类增加了新的数据成员,使用这些数据成员的成员函数不能应用于基类,基类没有这些属性和行为。
二、复制构造函数
凡是在构造函数中使用 new操作申请内存的类中,都要定义显式的复制构造函数,进行深度复制。C++默认的复制构造函数进行浅复制,复制的是成员的值:例如str = “hello world!”,浅复制只复制str的地址,而深度复制是复制str所指向的整个字符串。
使用同类对象构造同类对象的不存在任何问题,除非你的构造函数本身是错误的,这只能埋怨你自己不细心咯!
1、 使用派生类对象 复制构造 基类对象:
Cd copyCon(c2);
C++允许这种操作,将classic中的Cd数据成员复制到新的变量中,忽略classic中新增加的成员。如果Cd的复制构造函数中没有使用new则不需要显式定义这种复制构造函数;
2、 使用基类对象 复制构造 派生类对象:
Classic copyCd(c1);
调用基类的复制构造函数初始化派生类中基类成员的值,然后对派生类的特有成员分别进行赋值。需要注意的是:这种复制构造函数只将基类引用作为唯一参数。
三、赋值
和复制构造函数类似,如果构造函数中使用new操作申请内存的类中,都要重载赋值运算符,以进行深度复制,避免系统默认的浅复制所带来的bug。
1、将基类对象 赋给 派生类对象:
Classic newPlus;
newPlus = c1;
C++不允许这种转换操作,除非定义转换操作符,此处是赋值(=)操作符;
① 如果派生类有显式定义用基类构造派生类的复制构造函数,而没有定义转换复制操作符,则上述赋值操作将调用派生类的复制构造函数来完成赋值操作;(这一条是我自己在VC上单步调试得到的结果,至于其它编译器我不确定是否是这样。)
② 有定义转换操作符,则将调用转换操作符进行赋值操作
2 将派生类对象 赋给 基类对象;
Cd newCd;
newCd = c2;
C++将调用基类的赋值运算符,建立起对c2的基类引用,然后进行赋值。
欢迎大家留言讨论