多态
所谓多态,就是当使用基类的指针或引用调用重写的虚函数时,当指向父类调用的就是父类的虚函数,指向子类调用的就是子类的虚函数。
下面来通过代码来理解多态的含义
class AA
{
public:
virtual void fun()
{
cout << "AA::fun()" << endl;
}
};
class BB : public AA
{
public:
virtual void fun()
{
cout << "BB::fun()" << endl;
}
};
void FUN(AA& a)
{
a.fun();
}
void Test1()
{
AA a;
BB b;
FUN(a);
FUN(b);
}
结果为:
AA::fun()
BB::fun()
C++的多态分为静态多态和动态多态。
静态多态:静态多态就是重载,因为是在编译期决议确定。也就是在编译的时候就能确定函数的地址。
动态多态:是通过继承重写基类的虚函数实现的多态,在运行期间决议确定。也就是编译期间不知道函数的地址,只知道存储函数地址的虚表的地址。
C++中多态的实现就是通过虚函数实现的,虚函数的对象实例中都存在一张虚函数表。
虚函数表
虚函数表是通过一块连续内存来存储虚函数的地址,指明了实际调用的虚函数指针。
class AA
{
public:
virtual void fun1()
{}
virtual void fun2()
{}
protected:
int _a;
};
void Test2()
{
AA a;
}
通过监视窗口可以看到,对象a的首部存储了一个地址,指向的空间存储了虚函数的地址,称为虚函数表。所以sizeof(a)的值为8。
【含有虚函数的单继承对象模型】
typedef void(*FUNC) ();
class AA
{
public:
virtual void fun1()
{
cout << "AA::fun1()" << endl;
}
virtual void fun2()
{
cout << "AA::fun2()" << endl;
}
protected:
int _a;
};
class BB : public AA
{
public:
virtual void fun1()
{
cout << "BB::fun1()" << endl;
}
virtual void fun3()
{
cout << "BB::fun3()" << endl;
}
protected:
int _b;
};
void PrintfVTable(int *VTable)
{
cout << "虚表地址:" << "0x" << VTable << endl;
for (int i = 0; VTable[i] != 0; ++i)
{
cout <<"虚函数地址:0x"<< VTable[i] << " ";
FUNC f = (FUNC)VTable[i];
f();
}
cout << endl;
}
void Test3()
{
AA a;
BB b;
int* VTable1 = (int *)(*(int *)&a);
int* VTable2 = (int *)(*(int *)&b);
PrintfVTable(VTable1);
PrintfVTable(VTable2);
}
通过这种方式,可以依次打印出虚表地址以及虚函数的地址,结果如下:
虚表后面的0标志着虚表结束,类似于字符串结束符“/0”。
提示:若在windows平台vs下,程序出现异常中断,可以“清理解决方案”,这是由于编译器的小bug,没有在虚表最后加上0,出现死循环。
【含有虚函数的多继承对象模型】
typedef void(*FUNC) ();
class AA1
{
public:
virtual void fun1()
{
cout << "AA1::fun1()" << endl;
}
virtual void fun2()
{
cout << "AA1::fun2()" << endl;
}
protected:
int _a1;
};
class AA2
{
public:
virtual void fun1()
{
cout << "AA2::fun1()" << endl;
}
virtual void fun2()
{
cout << "AA2::fun2()" << endl;
}
protected:
int _a2;
};
class BB : public AA1,public AA2
{
public:
virtual void fun1()
{
cout << "BB::fun1()" << endl;
}
virtual void fun3()
{
cout << "BB::fun3()" << endl;
}
protected:
int _b;
};
void PrintfVTable(int *VTable)
{
cout << "虚表地址:" << "0x" << VTable << endl;
for (int i = 0; VTable[i] != 0; ++i)
{
cout <<"虚函数地址:0x"<< VTable[i] << " ";
FUNC f = (FUNC)VTable[i];
f();
}
cout << endl;
}
void Test4()
{
BB b;
int* VTable = (int *)(*(int *)&b);
PrintfVTable(VTable);
VTable = (int *)(*((int*)&b + sizeof (AA1) / 4));
PrintfVTable(VTable);
}