持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天点击查看活动详情
静态多态
函数重载 运算符重载 编译阶段确定函数地址
动态多态
派生类 虚函数实现运行时多态 运行阶段确定函数地址
动态多态满足关系
1,有继承关系 2.子类重写父类的虚函数 3.重写 需要函数返回值类型 函数名 参数列表 完全相同
动态多态使用
父类指针或引用指向子类对象
(虚函数调用)允许父类指针(引用)指向子类对象
父类引用指向子类对象: yang yan; animal ani& yan; 父类指针指向子类对象: animal *ani = new yang;
class animal
{
public:
//如果在这里写virtual void speak()那么就能实现地址晚绑定 下面输出的就是yang is speaking
void speak()
{
cout << "animal is speaking";
}
};
class yang :public animal
{
public:
void speak()
{
cout << "yang is spraking";
}
};
//如果上面的animal类函数中没有写virtual 则这里是静态多态 地址在这里的编译阶段就已经确定是animal 无论是传他的什么子类对象都是animal
void dospeak(animal &ani) //允许animal& ani = yan;
{
ani.speak();
}
int main()
{
yang yan;
dospeak(yan);//实际输出的是animal is speaking
}
虚函数多态实现原理
原理就是 基类指针指向派生类对象 他在执行函数时就不再是直接去代码区找 而是先在该类的虚函数表中找到该函数地址 再去代码区找
如果注释掉重写的猫说话函数 这里还是四个字节的原因是虽然没有重写speak对象 但是继承了animal的虚函数指针 所以也是四个字节
也就是如果类里面有虚函数 就会多出四个字节 这四个字节会存储一个地址 就是虚函数表的地址
虚函数表(vfptr)
是一个线性表 本质是一个动态数组 数组的元素是函数指针 指针指向该函数在代码区中的地址 派生类继承基类时会继承虚函数表中的元素
如果派生类继承了基类
但是并没有重写虚函数 那么虚函数表中继承的指针依旧指向基类虚函数在代码区的地址
当重写之后 就会在代码区新开辟一块地址存储新的函数内容 并且派生类中虚函数表指针指向它
获取虚函数表地址
Father father;
Son son;
int* ptrAdd = (int *)&father;//强制转换的原因是我们只需要拿这个对象的前四个字节的地址 因为虚函数表的地址就在这
printf("虚函数表地址:%p\n", *ptrAdd);
int Add = *((int*)*ptrAdd);
printf("虚函数表第一个元素地址:%p\n", Add);
获取虚函数地址 通过函数指针指向虚函数地址调用函数
class Father
{public:
virtual void fun()
{
cout << "i am father" << endl;
}
};
class Son :public Father
{
public:
virtual void fun()
{
cout << "i am son" << endl;
}
void fun2()
{
cout << "son fun2" << endl;
}
};
typedef void (*FUNC)();
int main()
{
Father father;
Son son;
/*获取虚函数表的地址*/
int* ptrAdd = (int *)&father;//强制转换的原因是我们只需要拿这个对象的前四个字节的地址 因为虚函数表的地址就在这
printf("虚函数表地址:%p\n", *ptrAdd);
/*获取虚函数表的第一个元素的地址 也就是存储的第一个方法的地址*/
int Add = *((int*)*ptrAdd);
printf("虚函数表第一个元素地址:%p\n", Add);
/*创建函数指针 指向函数地址*/
FUNC pFunc = (FUNC)Add;
/*调用函数指针*/
pFunc();
return 0;
}
多态实现计算器实例
class AbstractCalculator
{
public:
virtual int getResult()//方便子类重写
{
return 0;
}
int num1;
int num2;
};
class AddCalculator :public AbstractCalculator
{
public:
int getResult()
{
return num1 + num2;
}
};
class SubCalculator :public AbstractCalculator
{
public:
int getResult()
{
return num1 - num2;
}
};
class MulCalculator :public AbstractCalculator
{
public:
int getResult()
{
return num1 * num2;
}
};
int main()
{
AbstractCalculator* cal = new AddCalculator;
cal->num1 = 100;
cal->num2 = 200;
cout << cal->num1 << "+" << cal->num2 << "=" << cal->getResult() << endl;
delete cal;//一定要记得销毁堆内存
cal = new SubCalculator;
cal->num1 = 100;
cal->num2 = 200;
cout << cal->num1 << "-" << cal->num2 << "=" << cal->getResult() << endl;
delete cal;//一定要记得销毁堆内存
cal = new MulCalculator;//这里就体先了多态的作用 只需要创建一个对象 就行了
cal->num1 = 100;
cal->num2 = 200;
cout << cal->num1 << "*" << cal->num2 << "=" << cal->getResult() << endl;
delete cal;//一定要记得销毁堆内存
}