#include <iostream>
using namespace std;
/************************************************************************/
/*多太分为两类
1.静态多态:函数重载和运算符重载数据静态多态,复用函数名
2.动态多态:派生类和虚函数实现运行时多态;
静态多态和动态多态的区别
1.静态多态的函数地址早绑定-编译阶段确认函数地址
2.动态多态的函数地址晚绑定-运行阶段确认函数地址
空类的空间大小为1,但带有虚函数则空间大小为4(虚函数指针)
/************************************************************************/
class Animal
{
public:
void speak()
{
cout<<"animal speak"<<endl;
}
//虚函数,在父类成员函数前加virtual关键字
virtual void work()
{
cout<<"animal work"<<endl;
}
};
class Cat:public Animal
{
public:
void speak()
{
cout<<"cat speak"<<endl;
}
};
class Dog:public Animal
{
public:
//子类继承父类成员函数,对虚函数进行了重写,子类virtual关键字可写、可不写
//重写:子类对父类虚函数进行重写,返回值、函数名称和函数列表和父类必须一样
void work()
{
cout<<"Dog speak"<<endl;
}
};
void dospeak(Animal &mal)
{
//该阶段在编译时就确认了函数地址,父类对象调用父类成员函数
mal.speak();
}
void dowork(Animal &mal)
{
//该阶段在运行阶段才绑定函数地址,调用子类的成员函数
mal.work();
}
void test1()
{
Cat ct;
dospeak(ct);
}
void test2()
{
Dog dog;
//父类对象的引用或指针,指向子类对象,若子类重写了父类的虚成员函数,则会调用子类重写的成员函数
dowork(dog);
}
int main()
{
test1();
test2();
cout<<sizeof(Animal)<<endl;
return 0;
}
父类的指针或引用指向子类对象,若子类没有对继承的虚成员函数进行重写(子类的虚函数指针指向的虚函数表内容是继承过来的父类作用域的虚成员函数), 则在编译阶段就绑定了函数地址,实际调用的是父类的虚成员函数;
Animal &mal = ct;
mal.work();
若子类对继承过来的父类虚成员函数进行了重写,则虚函数指针指向的虚函数表内容是子类的虚成员函数(对继承的父类虚函数表内容进行了覆盖),在运行阶段会动态的绑定子类的虚成员函数;
Animal &mal = dog;
mal.work();