类的组合,类的继承
类的组合(汽车类,轮子类,此时可以把轮子类组合到汽车类;)
类的继承(交通工具类,汽车类,此时汽车类可以派生自交通工具类;)
组合:常用描述has a..
继承:常用描述is a ..
如果既可以用组合又可以用派生解决,那首选组合方式;
继承与派生的目的
继承的目的:实现设计和代码的重用
派生的目的:当新的问题出现,原有程序无法解决,需要对原有的程序进行改造
派生类的构成
吸收基类的成员
改造基类的成员
添加新的成员
吸收基类的成员
默认情况下派生类包含了全部的基类中除了构造函数和析构函数之外的所有的成员
C++11规定可以使用using语句继承基类的构造函数
改造基类成员
如果派生类声明了一个和某基类成员同名的新成员,派生类的新成员就隐藏或者覆盖了外层同名的成员
公有继承:
派生类中的成员函数可以直接访问基类中的public和protected成员,但不能访问直接访问基类中的private成员;
通过派生类的对象:只能访问public的成员
私有继承(private):
继承的访问控制:
基类的public和protected成员:都以private身份出现在派生类中;
基类的private成员:不可以直接访问
访问权限:
派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的
private成员;
通过派生类的对象不能访问从基类中继承的任何成员;
保护继承(protected):
继承的访问控制:
基类的public和protected成员:都以protected身份出现在派生类中
基类的private成员:不可以直接访问
访问权限:
派生类中的成员函数:可以直接访问基类中的public和protected成员,但不能直接访问基类中的private成员;
通过派生类的对象:不能直接访问从基类继承的任何成员;
protected成员的特点和作用
对建立其所在类对象的模块来说,它与private成员的性质相同
对于其派生类来说,它与public成员的性质相同
既实现了数据隐藏,又方便继承,实现代码的重用
class A {
protected:
int x;
};
int main()
{
A a;
a.x = 5;//错误
}
类型转换
- 公有派生类对象可以被当作基类的对象使用,反之则不行;
- 派生类的对象可以隐含转换为基类的对象
- 派生类的对象可以初始化基类的引用
- 派生类的指针可以隐含转换为基类的指针
- 通过基类对象名、指针只能使用从基类继承的成员
注意:不要重新定义继承而来的非虚函数
默认情况下:
基类的构造不被继承,派生类需要定义自己的构造函数;
C++11规定
可以使用using语句继承基类构造函数;
但是只能初始化从基类继承的成员;对于派生类新增的成员无法完成初始化;
语法形式:
using B::B;
若不继承基类的构造函数
派生类新增的成员:派生类定义构造函数完成初始化
继承来的成员:自动调用基类的构造函数初始化
派生类的构造函数需要给基类的构造函数传递参数;
单继承时构造函数的定义语法:
派生类名::派生类名(基类所需的形参,本类成员所需的形参):
基类名(参数表),本类成员初始化列表
{
//其他的初始化操作
}
派生类与基类的构造函数
当基类有默认的构造函数时
派生类构造函数可以不向基类的构造函数传递参数;
构造派生类的对象时,基类的默认构造函数将被调用;
如需要执行基类中带参数的构造函数,那么
派生类构造函数应该为基类构造函数提供参考;
多继承且有对象成员时派生的构造函数定义语法
派生类名::派生类名(形参表):
基类名1(参数),基类名2(参数),...基类名n(参数),
本类成员(含对象成员)初始化列表
{
//其他的初始化操作
}
注释:此处的本类成员指的是类的成员,当然也可以是本类包括的其他类的对象;
执行次序按照定义时候的顺序执行;
派生类的复制构造函数:
若派生类没有声明复制构造函数,则编译器会在需要时生成一个隐含的复制构造函数;
先调用基类的复制构造函数;
再为派生类新增的成员执行复制;
若派生类定义复制构造函数
一般都要为基类的复制构造函数传递参数,复制构造函数只能接受一个参数,既用来初始化派生类定义的成员,也将被传递给基类的复制构造函数;
基类的复制构造函数形式参数类型是基类对象的引用,实参可以是派生类对象的引用;
例如:
C::C(const C &c1):B(c1) {}
访问从基类中继承的成员时,
当派生类与基类中有相同的成员时:
1.若没有特别的限定,则通过派生类对象使用的是派生类中的同名成员;
2.如要通过派生类对象访问基类中被隐藏的同名成员,可以使用基类名和作用域操作符号::来限定;
二义性问题:
如果从不同的基类继承了同名的函数,但是在派生类中没有定义同名的成员,派生类对象名或引用名 .成员名,“派生类指针->成员名”访问存在二义性问题。
解决方式:用类名限定
当继承多个基类时(假如两个基类又继承自另一个相同的类,此时容易出现继承相同数据的情况),容易导致继承内容相同的情况,在操作过程中容易导致数据的冗余以及数据的不一致;
虚基类
问题:
当派生类从多个基类派生,而这些基类有共同的基类,则在访问此共同基类中的成员时,将产生冗余,并有可能因冗余带来不一致性;
方案:
声明虚基类
以virtual说明基类继承方式
例:class B1:virtual public B
作用:
主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题;
为最远的派生类提供唯一的基类成员,而不是重复产生多次复制;
注意:
在第一级继承时就要将共同基类设计为虚基类;
虚基类以及其派生类的构造函数
建立对象时所指定的类称为最远派生类;
虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。
在整个继承结构中,直接或者间接继承虚基类的所有派生类,都必须在构造函数的成员初始化列表中为虚基类的构造函数列出参数。如果未列出,则表示调用该虚基类的默认构造函数;
在建立对象时,只有最远派生类的构造函数调用基类的构造函数,其他类对虚基类构造函数的调用被忽略。
目标:降低程序的复杂性,提高代码的可复用性。
http://www.xuetangx.com/courses/course-v1:TsinghuaX+00740043_2x_2015_T2+sp/courseware/8d1fd477f469492ba2c1297e6ace6f5d/2a889505dd584a639363f2b4e8726040/