1 . 多态概念及条件
1.1 概念
不同的对象完成相同的行为产生出不同的状态。
举个例子:支付宝扫码领红包,新用户扫码普遍领的多,经常使用的老用户反而比较少,这就是不同对象完成相同行为产生不同状态。
1.2 虚函数
虚函数是一个特殊的形式,有以下几点需要注意
-
虚函数只能是类的成员函数
-
继承时基类中的虚函数可以和子类中的虚函数构成重写/覆盖关系,构成重写/覆盖的条件是“三同” + 虚函数,即返回类型,函数名和参数列表完全相同。
-
虚函数构成重写是构成多态的必要条件
1.3 虚函数在内存中的存储
虚函数的地址会被放进虚表存储在对象中。
1.4 构成多态的条件
构成多态有两个条件,第一是虚函数重写,第二是父类指针或者引用调用,只有符合这两点才能构成多态。
但是C++在这里又开了一些特例
-
如果子类中的函数不写virtual虚函数声明也可以算重写,真的很无语
-
返回值类型也可以不同,这个叫做重写的协变,但是呢,返回值必须是父子关系的指针或者引用。这里又不讲人话了,通俗的讲,现在有A, B,C,D四个类,A是B的父类,C是D的父类,那么A的返回值可以是A*也可以是 C *,只要是父类就可以,而D的返回值就是B *或者D *了,这样就叫做有父子关系的指针。
class A
{
public:
virtual void func(int val = 1){ std::cout<<"A->"<< val <<std::endl;
virtual void test(){ func();}
};
class B : public A
{
public:
void func(int val=0)
{
std::cout<<"B->"<< val <<std::endl;
}
};
int main(int argc ,char* argv[])
{
B*p = new B;
p->test();
return 0;
}
A:A->0; B:B->1; C:A->1; D:B->0; E:编译出错; F:以上都不正确;
这道题目应选择B,B中func不写virtual也会被认为是虚函数,因此构成重写。p指针指向的test函数参数列表中默认有this指针,而这个this指针是A型的,这个this去调用func(),满足了父类调用的条件,所以这里是一个多态调用,这里就会去调用B的func(),但是因为虚函数重写是接口继承,普通函数继承是实现继承。接口继承会把父类那个虚函数的框架整个地拿下来,其中也包括了缺省值,因此就算B中写了缺省值,最后用的还是A的,因此这里的val是1,最后打印出来的就是B->1.
2. 多态的原理
多态的原理源自于虚函数表。
只有符合多态的两个条件,调用函数时才会去调用指向对象的虚表。符合多态的虚函数调用需要在运行时去虚表中寻找需要调用的虚函数地址。
只要父类使用了virtual声明,使用父类指针或者引用调用,就会生成虚表(编译器检查不够细致),但是如果子类和父类不构成重写,子类和父类的虚 表内存放的
3 . C++的override和final
C++新增的两个关键字
-
override:
-
在子类的函数名后,函数体前声明,用来检查有没有完成重写。
-
final:
-
在父类函数声明,表明该虚函数不能被重写。
4 . 抽象类
含有纯虚函数的类叫做抽象类,纯虚函数是指在虚函数的后面写上 =0,抽象类不能实例化出对象,其派生类只有重写纯虚函数后才能实例化出对象,抽象类锁死了需要重写。
1. 什么是多态?答: 不同的对象进行相同行为时产生不同状态2. 什么是重载、重写(覆盖)、重定义(隐藏)?答: 重载是指在同一作用域内,两个函数名相同但参数类型不同的函数之间的关系。重写是指在基类和派生类中两个3. 多态的实现原理?答:当使用父类指针指向不同的类时,能够通过虚表调用到不同类的函数4. inline函数可以是虚函数吗?答:按理来说是不可以的,但是inline仅是一个建议,当满足多态调用时,inline会被忽略;若不满足多态调用,函数的代码量较小且多次调用时,会被展开。5. 静态成员可以是虚函数吗?答:不可以,虚函数需要通过this指针来访问虚表,而静态函数不具有this指针6. 构造函数可以是虚函数吗?答:不可以,因为调用虚函数需要虚表,而虚表内的指针是通过构造函数来初始化的7. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?8. 对象访问普通函数快还是虚函数更快?答:分情况,如果没有多态调用是一样快的,有多态调用则普通函数更快9. 虚函数表是在什么阶段生成的,存在哪的?答:编译阶段生成,存在代码段10. C++菱形继承的问题?虚继承的原理?答:菱形继承是一种特殊的多继承,虚继承的原理是生成了虚基表,表中存放着每一部分类与公共变量的距离11. 什么是抽象类?抽象类的作用?答:抽象类是包含纯虚函数的类,抽象类用来保证虚函数的重写