C++:基类与派生类对象之间的赋值兼容关系
4.5 基类与派生类对象之间的赋值兼容关系
在一定条件下,不同类型的数据之间可以进行类型转换,例如可以将整型数据赋给双精度型变量。
在赋值之前,先把整型数据转换为双精度型数据,然后再把它双精度型变量。这种不同类型之间的自动转换,称为赋值兼容。在基类和派生类对象之间也存在有赋值兼容关系,基类和派生类对象之间的赋值兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来代替。因为,通过公有继承,除了构造函数和析构函数外,派生类保留了基类其他的所有的成员。那么,派生类就具有基类的全部功能,凡是基类能够实现的功能,公有派生类都能实现。我们可以将派生类对象的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替。
例如,下面声明的两个类:
class Base{ //声明基类 ... }; class Derived:public Base{ //声明基类Base的公有派生类Derived ... };
根据兼容规则,在基类Base的对象可以使用的任何地方,都可以用派生类Derived的对象来代替,
但只能使用从基类继承来的成员。具体表现在以下几个方面:
(1)派生类对象可以向基类对象赋值,即用派生类对象中从基类继承来的数据成员,逐个赋值给基类对象的数据成员。
例如:
Base b; //定义基类Base的对象b
Derived d; //定义基类Base的公有派生类Derived的对象d
b=d; //用派生类Derived的对象d对基类Base的对象b进行赋值
这样的赋值效果是:对象b中所有数据成员都将具有对象d中对应数据成员的值。
(2)派生类对象可以初始化基类对象的引用。例如:
Base b; //定义基类Base的对象b
Derived d; //定义基类Base的公有派生类Derived的对象d
Base &br=d; //定义基类Base的对象的引用br,并用派生类Derived的对象对其进行初始化
(3)派生类对象地址可以赋值给指向基类对象的指针。例如:
Derived d; //定义基类Base的公有派生类Derived的对象b
Base *bp=&d; //把派生类对象的地址&d赋值给指向基类的指针bp,也就是说使指向基类
//对象的指针bp也可以指向派生类对象d
(4)如果函数的形参是基类对象或基类对象的引用,在调用函数时可以将派生类对象作为实参。例如:
class Base{ //声明基类Base
public:
int i;
...
};
class Derived:public Base{ //声明Base的公有派生类Derived
...
};
void fun(Base &bb)
{
cout<<bb.i<<endl; //输出该引用所代表的对象的数据成员i
}
在调用函数fun时,可以用派生类Derived的对象d4作为实参:
fun(d4);
输出派生类Derived的对象d4赋值给基类数据成员i的值。
//基类与派生类对象之间的交换
#include<iostream> using namespace std; class Base{ //声明基类Base public: int i; Base(int x) //基类Base的构造函数 { i = x; } Base(const Base &b) { cout<<"Base Copyconstructor"<<endl; } void show() //成员函数 { cout<<"i="<<i<<endl; } }; class Derived:public Base{ //声明基类Base的公有派生类Derived public: Derived(int x):Base(x) //派生类的构造函数 {} Derived(const Derived &d):Base(d) { cout<<"Derived Copyconstructor"<<endl; } }; void fun(Base &bb) //普通函数,形参为基类对象的引用 { cout<<bb.i<<endl; } int main() { Base b1(100); //定义基类对象b1 b1.show(); Derived d1(11); //定义派生类对象d1 b1=d1; //用派生类对象d1给基类对象b1赋值 b1.show(); Derived d2(22); //定义派生类对象d2 Base &b2=d2; //用派生类对象d2来对基类对象的引用b2进行初始化 b2.show(); Derived d3(33); //定义派生类对象d3 Base *b3=&d3; //把派生类对象的地址&d3赋值给指向基类对象的指针b3 b3->show(); Derived d4(44); //定义派生类对象d4 fun(d4); //派生类对象d4作为函数fun的实参 Derived d6(d4); return 0; } /* 程序运行结果如下: Base 100 Base 11 Base 22 Base 33 44 Base Copyconstructor Derived Copyconstructor
说明:
(1)声明为指向基类对象的指针可以指向它的公有派生类的对象,但不允许指向它的私有派生的对象。 例如: class Base{ ... }; class Derived:private Base{ ... }; int main() { Base op1,*ptr; //定义基类Base的对象op1及其指向基类Base的指针ptr Derived op2; //定义派生类Derived的对象op2 ptr = &op1; //将指针ptr指向基类Base对象op1 ptr = &op2; //错误,不允许将指向基类Base的指针ptr指向它的私有派生类对象op2 ...... return 0; } (2)允许将一个声明为指向基类的指针指向其公有派生类的对象,但是不能将一个声明为指向派生类 对象的指针指向其基类的一个对象。 例如: class Base{ ... }; class Derived:public Base{ ... }; int main() { Base obj1; //定义基类Base的对象obj1 Derived obj2,*ptr; //定义派生类Derived的对象obj2及其指向派生类对象的指针ptr ptr = &obj2; //将指针ptr指向派生类Derived对象obj2 ptr = &obj1; //错误,不允许将指向派生类Derived指针ptr指向它的基类Base对象obj1 ...... return 0; }