类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。 通过公有继承,派生类得到了基类中除构造函数和析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。类型兼容规则中指的替代包括以下的情况:
(1)派生类的对象可以隐含转换为基类对象
(2)派生类的对象可以初始化基类的引用
(3)派生类的指针可以隐含转换为基类的指针
在替代之后,派生类对象就可以作为基类对象使用,但只能使用从基类继承的成员。
如果B类为基类,D为B的公有派生类,则D类中包含了基类B中除构造函数和析构函数之外的所有成员。这时根据类型兼容规则,在基类B的对象可以出现在任何地方,都可以用派生类D的对象来替代。
在如下程序中,b1为B类的对象,d1为D类的对象
class B{...};
class D:public B{...};B b1;
B *p1;
D d1;
这时:
(1)派生类对象可以隐含转换为基类对象,即用派生类对象中从基类继承来的成员,逐个赋值给基类对象成员:
b1=d1;
(2)派生类对象也可以初始化基类对象的引用:
B &rb=d1;
(3)派生类对象的地址可以隐含转换为指向基类的指针:
p1=&d1;
由于类型兼容规则的引入,对于基类及其公有派生类对象,可以使用相同的函数统一处理。因为当函数的形参为基类的对象(或引用、指针)时,实参可以是派生类的对象(或指针),而没有必要为每一个类设计单独的模块,大大提高了程序效率。
【例】类型兼容规则实例
基类A以公有继承方式派生出B类,B类再作为基类以公有继承方式派生出C类。基类A中定义了成员函数display(),在派生类中对这个成员函数进行了隐藏。
class A//基类A定义
{
public:void display()const{cout << "显示类A" << endl;}
};class B :public A//公有派生类B定义
{
public:void display()const{cout << "显示类B" << endl;}
};class C :public B//公有派生类C定义
{
public:void display()const{cout << "显示类C" << endl;}
};void fun(A* p)//参数为指向基类A的对象的指针
{p->display();//"对象指针->成员名"
}int main()
{A a;B b;C c;fun(&a);fun(&b);fun(&c);return 0;
}
运行结果:
这样,通过“对象名.成员名”或者“对象指针->成员名”的方式,就应该可以访问到各派生类中继承自基类的成员。虽然根据类型兼容规则,可以将派生类对象的地址赋值给基类A的指针,但是通过这个基类类型的指针,却只能访问到从基类继承的成员。
在程序中,声明了一个形参为基类A类型的指针的普通函数fun,根据类型兼容兼容规则,可以将公有派生类对象的地址赋值给基类类型的指针,这样,使用fun函数就可以同一对这个类族中的对象进行操作。在程序运行过程中,分别把基类对象、派生类B的对象和派生类C的对象的地址赋值给基类类型的指针p,但是通过p,只能使用继承下来的基类成员。也就是说,尽管指针指向派生类C的对象,fun函数运行时通过这个指针只能访问到C类从基类A继承过来的成员函数display,而不是C类自己的同名成员函数。因此,主函数中3次调用fun的结果是相同的——访问了基类的公有成员函数。
通过这个例子可以看出,根据类型兼容规则,可以在基类对象出现的任何场合使用派生类对象进行替代,但是替代之后派生类对象仅仅发挥出基类对象的作用。