基类可分为直接基类和间接基类,间接基类就是在类的层次结构中向上间隔两层以上(含两层)所继承的类。
三种继承方式:公有继承,私有继承,保护继承。默认的继承方式为私有继承。
【例】:
class BaseClass
{
private:
int baseData;
} ;
class DerivedClass : public BaseClass
{
};
继承方式与访问控制:
基类成员 继承方式 | private | protected | public |
---|---|---|---|
private | 不可访问 | 可访问\私有成员 | 可访问\私有成员 |
protected | 不可访问 | 可访问\保护成员 | 可访问\保护成员 |
public | 不可访问 | 可访问\保护成员 | 可访问\公有成员 |
不可访问、可访问,表示在派生类中访问基类的能力。
私有成员,保护成员,公有成员,表示基类成员在派生类中访问控制属性变化情况。
派生类吸收基类成员:派生类继承吸收了基类的全部数据成员,
以及除了构造函数,析构函数,赋值和私有函数之外的全部函数成员。
对基类成员的覆盖:在派生类中定义了与基类中同名的数据成员或成员函数,由于作用域不同
于是发生了同名覆盖,基类被派生类覆盖。
1 . 基类的私有成员无论采用怎么样的继承方式,它在派生类中均不可访问,也不存在访问控制属性改变的问题。基类中的私有成员只能通过保护或公有的函数访问。
2 . 基类的保护成员在派生类中所有的继承方式均可直接访问,不过私有继承方式会把基类访问控制属性中的保护成员转换成派生类的私有成员,而保护和公有继承方式依然保持其为保护成员的访问属性。
3 . 基类的公有成员在派生类中也是可直接访问的,派生类中基类成员的访问控制属性均随继承方式而改变。
【注意】:1 . 需要强调的是,无论采用什么样的继承方式,基类中的所有成员均被派生类所继承
派生类对象一定含有基类的数据成员和成员函数,哪怕是基类的私有成员也被继承。
2 . 继承方式仅仅影响到基类成员在派生类中的访问控制属性。
3 . 对于在派生类中不可直接访问的私有成员,正确方法是通过基类提供的公有成员函
数进行间接访问。
子类函数覆盖父类函数的实例:
同名覆盖概念:由于派生类与基类的同名成员函数的函数签名相同(形参相同),派生类对象在调
用同名函数时,系统调用派生类的同名成员函数,而基类的相应函数被覆盖。
隐藏的概念:由于派生类与基类的同名成员函数的函数签名不同(形参不同),派生类对象在调用
同名成员函数时,系统只在派生类查找,不再深入到基类。
编译器调用类的成员函数的方法是:根据函数名(不是函数签名)沿着类的继承链逐级向上查找相匹配的函数定义。如果在类层次结构的某个类中找到了同名的成员函数,则停止查找,否则沿着继承链向上继续查找。派生中的同名函数阻止编译器到其基类继续查找,这就是出现同名覆盖和隐藏现象的原因。整个查找过程会出现下列两种情况:
1 ,在派生类中没有找到成员函数,再到基类中查找。如果在基类中找到并且实参与形参正确匹
配,则函数调用成功,否则出错。
2 , 在派生类中找到了同名的成员函数,不再到基类中查找。此时又有两种情况:
其一:函数调用实参与形参匹配正确,则调用派生类中的同名函数(同名覆盖)
其二:实参与形参匹配不成功,编译器报错(隐藏)。
派生类与基类的赋值兼容:
问 ? 派生类对象是否能赋值给基类对象,指针或引用呢 ?
由于派生类中包含从基类继承的成员,因此在任何需要基类对象的地方都可以用公有派生类的对象来代替。
1 ,派生类对象可以赋值给基类对象,它是把派生类对象中从对应基类中继承来的成员赋值给
基类对象。
2 , 派生类对象的地址可以赋值给指向基类的指针变量,即基类指针可以指向派生类对象。但
通过该指针只能访问派生类中从基类继承的成员,不能访问派生类中的新增成员。
3 , 派生类对象可以代替基类对象 向 基类对象的引用进行赋值或初始化。但它只能引用包含在
派生类对象中基类部分的成员。
基类对象不能赋值给派生类对象。
多重继承:
class C : public A , public B
{
public:
C() : B() , A() {}
}
基类A的构造函数先调用,尽管在构造函数声明中基类B的构造函数在基类A的前面。
由于多重继承的基类不止一个,而不同的类其数据成员和成员函数有可能同名,此时
派生类继承了不同基类的同名成员,会出现无法访问的二义性问题。