---记录基本概念与编程要点
一些概念: 1、继承:在基类的基础上加以扩展,增加功能,这样产生的类,叫派生类 2、多态:发生在不同层次的类中,以及同一类中,同名函数之间的关系问题
- 编译时期的多态(早绑定):指在编译时期就确定了函数的执行时机、调用关系,如函数的重载
- 运行时期的多态(晚绑定):是以虚函数+公有继承为基础,在程序运行时才能确定的调用关系
- struct默认public,struct继承时,缺省情况下是公有继承
- class默认private,class继承时,缺省情况下是私有继承
4、编译链接时候,会在派生类中对象中,先构建一个基类对象(隐藏对象),再去构建派生类对象的数据成员。
5、继承时的访问权限问题:不论是哪种继承方式,在派生类中只有非自己的私有成员不可访问。但,派生类中的基类具名对象的保护和私有无法访问,这和继承是不同的。
隐藏:在派生类中会对基类中的同名成员进行隐藏,访问遵循就近原则(也是原因)。
友元类:可以访问类中的所有成员。
6、赋值兼容规则:(公有继承是前提)
- 派生类对象可以赋值给基类对象
- 派生类对象的指针可以赋值给基类的指针
- 派生类对象可以初始化基类对象的引用
7、转型规则:
- 向上转型:派生类对象转为基类对象,使用dynamic_cast
(),可能会发生切片现象 - 向下转型:基类对象转为派生类对象,可以使用强制转换,但并不安全
8、在继承关系中,构造函数与析构函数具有继承性,拷贝构造函数不具有继承性,赋值函数也不具有继承性,必须明确调用。
9、C++类对象的初始化顺序:父类构造 先于 成员类对象构造 先于 自身构造
- 初始化列表不一定是构建的顺序,其中成员变量的初始化与声明顺序有关,构造函数的调用顺序是类派生表中的顺序
- 析构函数的析构顺序与构造函数构造顺序相反
多态与虚函数
1、只有类的成员函数才可以被定义为虚函数,虚函数定义:
- virtual 返回类型 函数名(参数列表){ 函数体 } //类外定义时可以不加virtual关键字,但类内的声明一定要写
当一个类的成员函数被定义为虚函数,则其所有的派生类中,该函数始终保持虚函数特征。
运行时多态的发生条件: - public 继承,派生类对于基类一定要是公有继承的
- 基类中写有虚函数
- 使用指针或者引用调用虚函数
满足以上三点,才能够是动多态。
派生类中的虚函数与基类中的虚函数必须是同名、同参数列表、同返回类型,否则被认为是重载(同名函数的隐藏)【若为基类中虚函数返回基类指针,派生类中虚函数返回派生类指针也可以视作是多态】
静态函数、友元函数、内联函数不可作为虚函数,因为需要有继承关系,所以,所有的构造函数也不会是虚函数,但析构函数可以是虚函数,以便完成对某些派生类对象的动态析构。
构造函数不会是虚函数的原因:1.首先,有虚函数的类有一个虚表,虚表地址要存储在类对象的内存空间中,但是构造函数就是来构造类对象的,还没构造,何来内存空间存储,不形成逻辑闭环。2.虚函数作用于多态发生函数的调用,而构造函数呢是为了构造类对象而调用的,不会是通过基类的指针或引用来进行调用,所以,他也没必要是虚函数。3.最后,虚表是在构造函数调用之后才建立的,因而构造函数不能为虚函数。
2、虚继承:解决C++多重继承的问题:1.浪费存储空间,2.存在二义性问题(如菱形继承)
采用虚继承则会在派生类中有一个虚基表指针,指向虚基表(实际上是存放相对偏移量用来寻找虚基类)
虚表在构造函数之前写入
纯虚函数:本质是将虚函数表中对应的表项赋值为0,也就是指向了一个不存在的函数,因此,该类不能够实例化对象,在其派生类中,除非重写了此函数,否则也将无法实例化对象
虚函数和纯虚函数的定义中不能有static关键字:因为静态关键字是在编译前期进行确定的,而虚函数和纯虚函数作用于多态,发生在执行时期进行动态绑定,这二者是相互违背的
拷贝构造函数的参数是引用&,若为值传递,则将出现无无限递归。



