一、三种继承方式
public
private
同名隐藏
如果派生类声明一个和某基类成员同名的新成员(如果是成员函数,则参数表也要相同,参数不同的情况属于重载),派生的新成员就隐藏了外层(基类)同名成员,称为同名隐藏
protected
二、 类型兼容规则(类型转换)
公有派生类对象可以被当作基类的对象使用,反之则不可。
派生类的对象可以隐含转换为基类对象;
class A; class B:public A A a1; B b1; a1 = b1;
派生类的对象可以初始化基类的引用;
A &a = b1;
派生类对象的地址可以隐含转换为基类的指 针。
A *ra ; ra = &b1;
在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。
例如:
虽然根据类型兼容规则,可以将派生类对象的地址赋值给基类Base1的指针,
但是通过这个基类的指针(或者对象名)只能访问从基类继承的成员。
所以运行结果是:
Base1 :: display( )
Base1 :: display( )
Base1 :: display( )
可以使用 虚函数 解决这个问题(详细解析见后续文章)
三、派生类的构造函数
按照 Base2,Base1,Base3的顺序调用基类的构造函数进行初始化,
按照 Base1,Base2,Base3的顺序初始化成员对象
析构函数的调用顺序和构造函数的调用顺序正好相反
四、访问从基类继承的成员
二义性问题
如果某个派生类的部分或全部基类都是从另一个共同的基类派生而来,
在这些直接基类中,从上一级继承而来的成员就拥有相同的名称,因此派生类中就会出现同名现象。
多继承时的二义性和冗余性问题:
使用作用域限定符,派生类的对象在内存中就同时拥有成员var0的多份同名副本,可赋不同的值,若只需要一个这样的数据副本,使用虚基类
作用域限定
当派生类与基类中有相同成员时:
若未特别限定,则通过派生对象使用的是派生类中的同名成员(同名隐藏)
如果要通过派生类对象访问基类中被隐藏的同名成员,应使用基类名和作用域操作符
::
来限定
使用作用域限定符,通过直接基类名来确定要访问的成员,这种情况下,
派生类的对象在内存中就同时拥有成员var0的两份同名副本(Base1和Base2的)可赋不同的值
可以使用类名限定解决多继承时的二义性问题
虚基类
解决多继承(派生类继承多个小基类,这些小基类又都继承同一个大基类)时的二义性和冗余性问题
举例:
虚基类和作用域分辨符比较
前者只维护一份成员副本,后者在派生类中拥有同名成员的多个副本,可以存放不同的数据。
相比之下,前者使用更为简洁,空间更为节省,后者可以容纳更多的数据