c++实现多态分为两种,静态多态与动态多态,多态是指父类调用子对象方法
静态多态
函数重载,运算符重载属于静态多态
在编译阶段就确定好函数地址
动态多态
派生类和虚函数
需要在运行阶段才能确定好地址
多态测试代码
#include<iostream>
using namespace std;
class Animal {
public :
void speak()//未被虚函数修饰的静态方法,无法由上访问下方
{
cout << "动物在说话" << endl;
}
virtual void eat()//虚函数修饰的动态方法,可以上方访问下方
{
cout << "动物在吃饭" << endl;
}
};
class Cat :public Animal
{
public :
void speak()
{
cout << "小猫在说话" << endl;
}
void eat()
{
cout << "小猫在吃饭" << endl;
}
};
class Dog :public Animal {
public :
void eat();
};
void Dog::eat()
{
cout << "狗狗在吃饭" << endl;
}
通过父类调用方法
void dospeak(Animal &animal)//父类引用接受子类对象。自上到下(c++允许自动将子类转化为父类)
{
animal.speak();
}
void doeat(Animal& animal)
{
animal.eat();
}
void test01()
{
Cat cat;
dospeak(cat);//动物在说话,静态多态,说明地址早绑定,在编译阶段就确定了函数地址
doeat(cat);//小猫在吃饭,静态多态,在运行时才进行,传进来什么执行什么,
//只需要在对应的想要变成动态多态的前面添加virtual关键字即可
}
静态多态的测试
void test02()
{
//speak()是静态方法,无法调用多态
Animal* dog = new Dog();
dog->speak();
Animal* cat = new Cat();
cat->speak();
Animal* ani = new Animal();
ani->speak();
/* 运行结果
静态多态开始测试
动物在说话
动物在说话
动物在说话
*/
}
动态动态
void test03()
{
//多态的另一种方式,虽然都是动物类,但是创建的对象不同
//但是通过虚函数声明之后变成动态多态,(eat()是动态方法,所以会引入多态特性)
//通过访问就可以访问对应的方法的某些方法
Animal* dog = new Dog();
dog->eat();
Animal* cat = new Cat();
cat->eat();
Animal* ani = new Animal();
ani->eat();
/* 运行结果
动态多态开始测试
狗狗在吃饭
小猫在吃饭
动物在吃饭*/
}
main方法
int main(void)
{
test01();
cout << "静态多态开始测试" << endl;
test02();
cout << "动态多态开始测试" << endl;
test03();
}
vireual会生成一个虚函数(表)指针
虚函数(表)指针指向一个虚函数表
表内部记录了虚函数地址,记录自己作用域具体虚函数,子类也会创建一个虚函数表,与虚函数指针,当子类重写了这个虚函数时,并且子类对象覆盖父类对象时(利用指针覆盖或者引用起别名覆盖),会重写这个虚函数表,将原有的作用域覆盖掉,(父类并没有被改变)
当子类没有发生重写时,虚函数表还是父类的表