虚函数实现多态

虚函数实现多态

  1. 多态性的本质是一个接口,多态的目的是为了接口重用,函数都能通过接口调用到适应各自对象的实现方法,也是C++面向对象编程的核心概念
  2. C++的多态是通过虚函数来实现的,虚函数允许子类重新定义成员函数,子类重新定义父类的做法称为覆盖/重写
  3. 编译器为每个类维护一个虚函数表,每个对象的首地址保存着该虚函数表的指针,同一个类的不同对象指向同一个虚函数表,基类对象会根据赋值给它的子对象的不同以不同的方式实现(调用不同的virtual函数)
  4. 虚函数在运行期确定函数地址是晚绑定
  5. 如果派生类的函数和基类的函数同名,则无论有无virtual,基类函数都会被隐藏
  6. 如果派生类函数和基类函数同名,且基类没有virtual,基类函数会被隐藏
  7. 静态成员函数不能是虚函数,内联函数不能是虚函数,构造函数不能是虚函数,析构函数可以是虚函数

虚函数实现多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>

using namespace std;

class A{
public:
A() : i(10) {};
virtual void f() {cout<<i<<endl;}
virtual void a(int num)
{
cout<<num<<endl;
}
void b(int num1, int num2){
cout<<num1<<" "<<num2<<endl;
}
int i;
};

class B : public A{
public:
B() : i(6.6) {}
virtual void f() {cout<<i<<endl;}
virtual void a(float num){
cout<<num<<endl;
}
void b(float num1, float num2){
cout<<num1<<" "<<num2<<endl;
}

float i;
};

int main(){
A n;
B m;
A* p=&m;
p->f();
p->a(1.2);
p->b(1.2,1.3);
n=m;
n.f();
return 0;
}

  1. 每个类维护一个虚函数表,类对象的vptr指向虚函数表的头部,将指向基类对象的指针指向派生类对象
  2. 当基类指针在调用虚函数时,会查找该对象的虚函数表,虚函数表的地址在每个对象的首地址,查找该虚函数表中的该函数进行调用
  3. 类比2,在普通函数中,即使将派生类对象赋给基类指针,调用的仍然是基类的成员函数
  4. 如果虚函数在基类与派生类中出现仅仅名字相同,而参数和返回值类型不同,即使加上virtual也不会产生多态掉过,见函数a运行结果
  5. 只有对象的指针或引用才能实现动态绑定,对象的点访问不能实现,如程序n.f();运行结果所示

纯虚函数

  1. 基类中没有定义,但是要求派生类必须定义自己的实现方法
  2. 而普通函数中的虚函数有定义,派生类可以定义自己的实现方法,也可以不定义
  3. 含有纯虚函数的类是抽象类,不能生成对象
WhitneyLu wechat
Contact me by scanning my public WeChat QR code
0%