多态易错题4

下面是一段C++ 代码,其功能是通过基类指针实现多态调用不同派生类的函数。代码定义了一个抽象基类Canimal,包含一个受保护的字符串成员变量mname和一个纯虚函数barkdogcat类从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函数中,创建了dogcat对象,并使用Canimal类型的指针s1s2分别指向它们,这是实现多态的常见方式。

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的虚函数表,最终调用的是catbark函数;同理,当调用s2->bark()时,由于虚函数表指针被交换为dog对象的虚函数表指针,所以它查询的是dog的虚函数表,调用的是dogbark函数。

需要强调的是,这种底层指针操作是非常危险且不规范的,它破坏了对象的内部结构和虚函数机制的正常运行,在实际编程中应避免此类操作,以免引发不可预测的行为和错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值