1. 什么是类和继承
类与类之间的关系
has-A 包含关系,⽤以描述⼀个类由多个部件类构成,实现 has-A 关系⽤类的成员属性表示,即⼀个类的成员属性是另⼀个已经定义好的类;
use-A,⼀个类使⽤另⼀个类,通过类之间的成员函数相互联系,定义友元或者通过传递参数的⽅式来实现;
is-A,继承关系,关系具有传递性;
继承的相关概念
所谓的继承就是⼀个类继承了另⼀个类的属性和⽅法,这个新的类包含了上⼀个类的属性和⽅法,被称为⼦类或者派⽣类,被继承的类称为⽗类或者基类;
继承的特点
⼦类拥有⽗类的所有属性和⽅法,⼦类可以拥有⽗类没有的属性和⽅法,⼦类对象可以当做⽗类对象使⽤;
继承中的访问控制
public、 protected、 private
继承中的构造和析构函数
继承中的兼容性原则
2. 什么是组合?
⼀个类⾥⾯的数据成员是另⼀个类的对象,即内嵌其他类的对象作为⾃⼰的成员;创建组合类的对象:⾸先创建各个内嵌对象,难点在于构造函数的设计。创建对象时既要对基本类型的成员进⾏初始化,⼜要对内嵌对象进⾏初始化。
创建组合类对象,构造函数的执⾏顺序:先调⽤内嵌对象的构造函数,然后按照内嵌对象成员在组合类中的定义顺序,与组合类构造函数的初始化列表顺序⽆关。然后执⾏组合类构造函数的函数体,析构函数调⽤顺序相反。
3. 构造函数析构函数可否抛出异常
C++ 只会析构已经完成的对象,对象只有在其构造函数执⾏完毕才算是完全构造妥当。在构造函数中发⽣异常,控制权转出构造函数之外。因此,在对象 b 的构造函数中发⽣异常,对象b的析构函数不会被调⽤。因此会造成内存泄漏。
⽤ auto_ptr 对象来取代指针类成员,便对构造函数做了强化,免除了抛出异常时发⽣资源泄漏的危机,不再需要在析构函数中⼿动释放资源;
如果控制权基于异常的因素离开析构函数,⽽此时正有另⼀个异常处于作⽤状态, C++ 会调⽤ terminate 函数让程序结束;
如果异常从析构函数抛出,⽽且没有在当地进⾏捕捉,那个析构函数便是执⾏不全的。如果析构函数执⾏不全,就是没有完成他应该执⾏的每⼀件事情。
4. 类如何实现只能静态分配和只能动态分配
前者是把 new、 delete 运算符重载为 private 属性。
后者是把构造、析构函数设为 protected 属性,再⽤⼦类来动态创建
建⽴类的对象有两种⽅式:
静态建⽴
静态建⽴⼀个类对象,就是由编译器为对象在栈空间中分配内存;
动态建⽴
A *p = new A();
动态建⽴⼀个类对象,就是使⽤ new 运算符为对象在堆空间中分配内存。这个过程分为两步,第⼀步执⾏ operator new() 函数,在堆中搜索⼀块内存并进⾏分配;第⼆步调⽤类构造函数构造对象;
只有使⽤ new 运算符,对象才会被建⽴在堆上,因此只要限制 new 运算符就可以实现类对象只能建⽴在栈上。可以将 new 运算符设为私有
5. 何时需要成员初始化列表?过程是什么?
当初始化⼀个引⽤成员变量时;
初始化⼀个 const 成员变量时;
当调⽤⼀个基类的构造函数,⽽构造函数拥有⼀组参数时;
当调⽤⼀个成员类的构造函数,⽽他拥有⼀组参数;
编译器会⼀⼀操作初始化列表,以适当顺序在构造函数之内安插初始化操作,并且在任何显示⽤户代码前。 list中的项⽬顺序是由类中的成员声明顺序决定的,不是初始化列表中的排列顺序决定的。
6. 程序员定义的析构函数被扩展的过程?
析构函数函数体被执⾏;
如果 class 拥有成员类对象,⽽后者拥有析构函数,那么它们会以其声明顺序的相反顺序被调⽤;
如果对象有⼀个 vptr,现在被重新定义
如果有任何直接的上⼀层⾮虚基类拥有析构函数,则它们会以声明顺序被调⽤;
如果任何虚基类拥有析构函数
7. 构造函数的执⾏算法?
在派⽣类构造函数中,所有的虚基类及上⼀层基类的构造函数调⽤;
对象的 vptr 被初始化;
如果有成员初始化列表,将在构造函数体内扩展开来,这必须在 vptr 被设定之后才做;
执⾏程序员所提供的代码;
8. 构造函数的扩展过程?
记录在成员初始化列表中的数据成员初始化操作会被放在构造函数的函数体内,并与成员的声明顺序为顺序;
如果⼀个成员并没有出现在成员初始化列表中,但它有⼀个默认构造函数,那么默认构造函数必须被调⽤;
如果 class 有虚表,那么它必须被设定初值;
所有上⼀层的基类构造函数必须被调⽤;
所有虚基类的构造函数必须被调⽤。
9. 哪些函数不能是虚函数
构造函数,构造函数初始化对象,派⽣类必须知道基类函数⼲了什么,才能进⾏构造;当有虚函数时,每⼀个类有⼀个虚表,每⼀个对象有⼀个虚表指针,虚表指针在构造函数中初始化;
内联函数,内联函数表示在编译阶段进⾏函数体的替换操作,⽽虚函数意味着在运⾏期间进⾏类型确定,所以内联函数不能是虚函数;
静态函数,静态函数不属于对象属于类,静态成员函数没有this指针,因此静态函数设置为虚函数没有任何意义。
友元函数,友元函数不属于类的成员函数,不能被继承。对于没有继承特性的函数没有虚函数的说法。
普通函数,普通函数不属于类的成员函数,不具有继承特性,因此普通函数没有虚函数。