多态的基本概念
多态是C++面向对象三大特性之一
多态分为两类
- 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
- 动态多态: 派生类和虚函数实现运行时多态
静态多态和动态多态区别:
- 静态多态的函数地址早绑定 - 编译阶段确定函数地址
- 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
#include<iostream>
using namespace std;
class Animal
{
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
class Dog : public Animal
{
public:
void speak()
{
cout << "狗在说话" << endl;
}
};
class Cat : public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
void doSpeak(Animal& animal)
{
animal.speak();
}
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
int main()
{
test01();
system("pause");
return 0;
}
上述代码输出结果
我们发现并没有按照我们设想的那样打印“猫在说话;狗在说话”
这是因为:
//地址早绑定 在绑定阶段就确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定
想要让函数地址晚绑定,那么需要将speak这个函数变为虚函数,改动如下;
class Animal
{
public:
//Speak函数就是虚函数
//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
改动后的完整代码如下:
#include<iostream>
using namespace std;
class Animal
{
public:
//Speak函数就是虚函数
//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
class Dog : public Animal
{
public:
//重写,函数返回值类型 函数名 参数列表 完全相同
void speak()
{
cout << "狗在说话" << endl;
}
};
class Cat : public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
void doSpeak(Animal& animal)
{
animal.speak();
}
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
int main()
{
test01();
system("pause");
return 0;
}
上述输出结果
正常输出小猫在说话,小狗在说话
我们使用VS 开发人员命令行工具看一下执行上述代码对象发生的变化
先看下没有加virtual时是什么
首先打开Developer Command Prompt for VS 2019(我使用的是vs2019)
然后切换到项目文件盘符
我这里放在了E盘中
然后切换到项目文件(自己创建的项目文件)
然后使用命令行 ’cl /d1 reportSingleClassLayoutAnimal 01多态基本概念.cpp’
(reportSingleClassLayoutCat意思是打印报告单个类动物;01多态基本概念.cpp是我的源文件)
这里可以看到Animal这个类的大小是1,是个空类
现在我们加上virtual,再看下Animal的大小
发现现在的大小变成了4,这个大小是一个指针的大小,这个指针就是vfptr,可以在图中看出,这个指针指向了vftable,vftable里面存储的就是Animal::speak这个函数。
接下来我们看Cat这个类发生了什么变化
先在Cat类中不进行函数重写
即讲下列代码中speak函数注释
class Cat : public Animal
{
public:
// void speak()
// {
// cout << "小猫在说话" << endl;
// }
};
然后使用命令行 ’cl /d1 reportSingleClassLayoutCat 01多态基本概念.cpp’
这里同样的有个指针vfptr,可以在图中看出,这个指针指向了vftable,vftable里面存储的是Animal::speak这个函数,所以执行结果是“动物在说话”
然后对Cat 类里函数进行重写
查看输出结果
发现vftable里面存储的是Cat::speak这个函数,所以执行结果是“小猫在说话”