下面是一段C++ 代码,其功能是通过基类指针实现多态调用不同派生类的函数。代码定义了一个抽象基类Canimal
,包含一个受保护的字符串成员变量mname
和一个纯虚函数bark
。dog
和cat
类从Canimal
派生,并各自实现了bark
函数。
#include<iostream>
#include<string>
using namespace std;
class Canimal
{
protected:
string mname;
public:
Canimal(string name):mname(name){}
virtual void bark() =0;
};
class dog:public Canimal
{
public:
dog(string name):Canimal(name){};
void bark()
{
cout<<mname<<":"<<"wang wang awng "<<endl;
}
};
class cat:public Canimal
{
public:
cat(string name):Canimal(name){}
void bark()
{
cout<<mname<<":"<<"miao miao miao "<<endl;
}
};
在main
函数中,创建了dog
和cat
对象,并使用Canimal
类型的指针s1
和s2
分别指向它们,这是实现多态的常见方式。
int main()
{
Canimal *s1 = new dog("dog");
Canimal *s2 = new cat("cat");
如果main
函数中没有以下这组交换代码(即被///
包含的部分),程序的输出结果是正常的多态表现,即dog
对象调用dog
类的bark
函数,cat
对象调用cat
类的bark
函数,输出为:
dog:wang wang wang
cat:miao miao miao
然而,当加入这组交换代码后:
///
int *p11 =(int*)s1;
int*p22 = (int*)s2;
int tep = *p11;
*p11 =* p22;
*p22= tep;
/
程序的输出结果变为:
dog:miao miao miao
cat:wang wang awng
这是因为在C++ 中,对于包含虚函数的类对象,其前四个字节(在32位系统上,64位系统是8个字节)通常存放的是虚函数表指针(vfptr
)。上述交换代码将dog
对象和cat
对象的前四个字节进行了交换,实际上就是交换了它们的虚函数表指针。
因此,当调用s1->bark()
时,虽然s1
指向的是dog
对象,但由于虚函数表指针已被交换为cat
对象的虚函数表指针,所以它查询的是cat
的虚函数表,最终调用的是cat
的bark
函数;同理,当调用s2->bark()
时,由于虚函数表指针被交换为dog
对象的虚函数表指针,所以它查询的是dog
的虚函数表,调用的是dog
的bark
函数。
需要强调的是,这种底层指针操作是非常危险且不规范的,它破坏了对象的内部结构和虚函数机制的正常运行,在实际编程中应避免此类操作,以免引发不可预测的行为和错误。