携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
1 原理解释
类中只有一个非静态的成员的函数 它并不属于类的对象上面。所以它类似一个空类,空类的大小是一个字节。
当父类中有virtual函数,就相当于父类里面含有四个大小的指针,这个指针名字叫做:vfptr(虚函数表指针): v - virtual/f - function/ptr - pointer
这个指针会指向虚函数表:vftable
v - virtual/f - function/table - table
内部会记录虚函数表的地址 &Fat::spr(要加上作用域)
子类: 如果没有发生重写的情况,那就是一个继承了,就是把父类所有的内容全部拿到子类,父类的指针也要拿过来一份:vfptr,并且指向子类的虚函数表vftable:记录的也是虚函数&Fat::spr(要加上作用域)
当你发生重写之后,那么子类会把子类中虚函数表中的内容做一个覆盖操作,即:子类中的虚函数表内部会替换成子类的虚函数地址。 &Son::spr(要加上作用域)
父类没有发生改变,父类中的指针没有发生改变,在父类依然是有的,子类只是替换子类的虚函数表。
当父类的指针或者引用指向子类对象时候,会发生多态。
2 原理举例
#include<iostream>
using namespace std;
class Fath
{
public:
//Speak函数就是虚函数
//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
void spr()
{
cout << "父类" << endl;
}
};
class Son1 :public Fath
{
public:
void spr()
{
cout << "子类1" << endl;
}
};
class Son2 :public Fath
{
public:
void spr()
{
cout << "子类2" << endl;
}
};
//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编
void DoSpr(Fath & fath)
{
fath.spr();
}
//
//多态满足条件:
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象
void test()
{
cout << "sizeof Fath = " << sizeof(Fath) << endl;
}
int main() {
test();
system("pause");
return 0;
}
输出:
sizeof Fath = 1 请按任意键继续. . .
class Fath
{
public:
//Speak函数就是虚函数
//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
virtual void spr()
{
cout << "父类" << endl;
}
};
输出:
sizeof Fath = 4 请按任意键继续. . .
class Fath
{
public:
//Speak函数就是虚函数
//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
virtual void spr()
{
cout << "父类" << endl;
}
};
class Son1 :public Fath
{
public:
};
void test()
{
cout << "sizeof Son1 = " << sizeof(Son1) << endl;
}
输出:
sizeof Son1 = 4 请按任意键继续. . .
class Fath
{
public:
//Speak函数就是虚函数
//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
virtual void spr()
{
cout << "父类" << endl;
}
};
class Son1 :public Fath
{
public:
void spr()
{
cout << "子类1" << endl;
}
};
sizeof Son1 = 4
请按任意键继续. . .