文章目录
【1】继承
继承的本质
继承的本质就是代码的复用
1.继承的访问限定?
2.派生类怎么初始化从基类继承来的成员?
通过调用基类相应的构造函数进行初始化,派生类只会初始化自己的成员。
3. 构造析构的顺序?
先构造基类部分 再构造派生类部分 析构时先析构派生类对象 再析构析构基类方法
4.继承结构是从上到下的结构
默认支持从下到上的转换
基类对象=》派生类对象 ------------ 不可以 ----------上到下
派生类对象=》基类对象 ------------ 可以 -------------下到上
基类指针/引用=》派生类对象 ----- 可以 - -----------下到上
派生类指针/引用=》基类对象 ------不可以 ----------上到下
【2】多态
1.什么是多态?
静态多态:函数重载和模板(编译期的绑定)
动态多态:call 虚函数 实际 call 寄存器eax 不确定(运行时的绑定)
2.多态的好处
通过基类指针指向派生类对象 调用派生类的同名覆盖方法 基类指针指向哪个对象 就调用哪个派生类的虚函数表中的方法
3.重载 隐藏 覆盖(基类和派生类同名成员函数之间的关系)
重载:
函数名相同 参数列表不同 同一个作用域
隐藏:
处在基类和派生类中 函数名相同就可以
覆盖:
基类和派生类当中 函数的返回值 函数名 参数列表都相同 而且基类的函数是virtual虚函数 称作覆盖关系(虚函数表的覆盖)
4.请解释静态绑定(编译)(函数调用)和动态绑定(运行)?
静态类型:对象在声明时采用的类型,在编译期既已确定;
动态类型:通常是指一个指针或引用目前所指对象的类型,是在运行期决定的;
静态绑定 直接绑定函数的地址 绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期;
动态绑定 绑定虚函数表 寄存器 绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期 运行时确定
5.vfptr vftable 什么时候生成?运行时加载到那一块内存??
如果一个函数有虚函数 那么在编译阶段该类型会产生一个对应的虚函数表 存虚函数的地址 运行时加载到全局的数据段
类的大小为成员对象内存加上虚函数指针的内存大小
虚函数指针指向虚函数表的起始地址
继承的时候会继承过去虚函数 产生派生类的对象时 也会产生虚函数表 覆盖掉原来的虚函数表
6.RTTI指针
RTTI指针存储在虚函数表vftable当中,指向一段类型字符串 运行时的类型信息
7.虚函数表
存的内容:运行时的类型信息RTTI 偏移量 虚函数的地址
存在的前提:此时已经有对象 对象可以取地址
8. 抽象类
凡是含有纯虚函数的类叫做抽象类 例:virtual void fun() = 0;
这种类不能定义对象,只是作为基类为派生类服务,但可以定义指针或引用。
除非在派生类中完全实现基类中所有的的纯虚函数,否则,派生类也变成了抽象类,不能实例化对象。在派生类实现该纯虚函数后,定义抽象类对象的指针,并指向或引用子类对象。
9.虚函数的缺省参数(重点)
虚函数是动态绑定的,但是为了执行效率,缺省参数是静态绑定的。
class A
{
public:
virtual void Fun(int number = 10)
{
std::cout << "A:: with number " << number<<endl;
}
};
class B: public A
{
public:
virtual void Fun(int number = 20)
{
std::cout << "B:: with number " << number<<endl;
}
};
int main()
{
B b;
A &a = b;
b.Fun();
a.Fun();
}
代码运行如下
从结果可以看到因为缺省参数属于静态绑定,
所以当b->Display() 默认的参数是10;d->Display() 默认的参数是20 这是我们不愿意看到的。
在使用虚函数的时候,一定要考虑号缺省参数的问题。
【3】继承和多态的常见笔试题的分析
1.能不能成为虚函数=》记录函数地址(vftrbles)/vfptr (地址)
答:必须有对象已经存在 而且可以取地址
2.析构函数能不能实现成virtual虚析构函数?
答:可以的,此时已经有对象的存在
3.构造函数能不能实现成virtual虚构造函数?
答:不可以 因为这时候还没有对象
4.在构造函数中调用virtual虚函数,请问是静态绑定还是动态绑定?
答:静态绑定 因为此时没有产生对象 动态绑定依赖于对象 此时不能访问对象的前四个字节RTTI。
5.在析构函数中调用virtual虚函数,请问是静态绑定还是动态绑定?
答:是动态绑定,此时已经有对象的存在了。
6.static静态成员方法可不可以写成虚函数?
答:不可以 他的调用不依赖对象的存在
7.inline内联函数可不可以写成虚函数?
答:C++11新标准 已经可以写成虚函数 加virtual之后变成普通函数。
8.什么时候析构函数必须写成虚析构函数?
答:基类指针(引用)指向堆上派生类的的资源时,此时要把析构函数写成虚析构函数。
9.调用虚函数一定会发生动态绑定么?
不一定 对象的直接调用虚函数 永远是静态绑定
而指针或者引用调用虚函数的话才会发生动态绑定。