对C++的多态的思考

    在面向对象的编程过程中,经常使用多态,以便得到不同的实现。

不使用virtual关键字

class Super
{
public:
    /*Super():id(0),str("hello")
    {
    }*/
    void DoSth()
    {
        cout<<"Super-DoSth"<<endl;
        //cout<<str<<endl;
    }
    /*~Super()
    {

    }*/
//private:
    //int id;//4bytes
    //string str;//32bytes
};

Super类的布局:

class Super    size(1):
    +---
    +---

Sub类继承Super,重写DoSth函数。

class Sub : public Super
{
public:
    void DoSth()
    {
        cout<<"Sub-DoSth"<<endl;
    }
};

Sub类的布局:

  class Sub    size(1):
      +---
      | +--- (base class Super)
      | +---
      +---

//函数的调用:

Super super;
 ((Sub&)super).DoSth();//输出Sub-DoSth

通过向子类的类型的转换,实现调用子类的函数。


使用virtual关键字

把Super的DoSth()前加virtual,如下:

virtual void DoSth()

那么Super类的布局变为:

class Super    size(4):
      +---
   0    | {vfptr}
      +---
 
  Super::$vftable@:
      | &Super_meta
      |  0
  0    | &Super::DoSth
 
  Super::DoSth this adjustor: 0

Sub类的布局变为:

  class Sub    size(4):
      +---
     | +--- (base class Super)
  0    | | {vfptr}
      | +---
      +---
 
  Sub::$vftable@:
      | &Sub_meta
      |  0
   0    | &Sub::DoSth
 
  Sub::DoSth this adjustor: 0

//函数的调用:

Super super;
 ((Sub&)super).DoSth();//输出Super-DoSth

当加入virtual的时候,说明Super加了多态,这样就多了4个字节的虚函数表。类的布局已经变化,上面的写法调用的是父类的函数。

通过以下方式实现调用子类的方法:

Sub sub;
Super* pSuper=&sub;
pSuper->DoSth();//输出Sub-DoSth


总结:在设计类的时候,考虑到函数多种实现的时候,不一定非要在函数前面加vritual,当加virtual的时候会有虚函数表,会增加开销。














<think>好的,我需要帮助用户了解C++多态与虚函数的使用方法,并提供实验代码示例。首先,我需要回顾用户提供的引用内容,确保回答准确。用户引用了三篇关于C++多态和虚函数的文章,其中提到了虚函数表、动态多态的实现原理以及构造函数和析构函数的示例。 首先,我应该从多态的基本概念开始,区分静态多态和动态多态。静态多态如函数重载和模板,动态多态则通过虚函数实现。用户需要教程和实验代码,所以需要详细步骤和示例。接下来,我需要解释为什么引入虚函数,即为了解决基类指针或引用调用派生类方法的问题。例如,当基类指针指向派生类对象时,如果没有虚函数,调用的可能还是基类的方法,这不符合多态的需求。因此,虚函数的作用是允许在运行时确定调用的函数,实现动态绑定。 然后,我需要描述虚函数的底层实现,即虚函数表(vtable)和虚函数指针(vptr)。每个含有虚函数的类都有一个虚函数表,存储虚函数的地址。对象中包含指向该表的指针。当派生类覆盖虚函数时,虚函数表中的对应项会被替换为派生类的函数地址。这一点在引用[2]中有详细说明,需要正确引用。接下来是使用虚函数的注意事项,比如析构函数应为虚函数,以防止对象析构时仅调用基类析构函数导致资源泄漏。引用[3]中的示例展示了基类和派生类的构造和析构函数,但未将析构函数声明为虚函数,这可能是一个问题点,需要指出。然后,我需要提供实验代码示例。应包括基类定义虚函数,派生类覆盖虚函数,以及通过基类指针调用派生类方法的示例。此外,可以展示虚函数表的影响,比如使用sizeof查看对象大小,验证vptr的存在。同时,要演示虚析构函数的重要性,比如创建派生类对象并用基类指针删除,观察析构函数的调用情况。 在代码部分,需要确保语法正确,比如使用virtual关键字,正确继承,以及指针的使用。例如,基类Animal有虚函数makeSound(),派生类Dog和Cat覆盖该函数。主函数中通过基类指针数组指向不同派生类对象,循环调用makeSound(),展示多态效果。另外,关于虚析构函数的实验,可以设计一个基类和派生类,基类析构函数非虚,然后用基类指针删除派生类对象,观察是否只调用基类析构函数。再将基类析构函数声明为虚函数,重复实验,显示派生类和基类的析构函数都被调用,说明虚析构函数的重要性。 最后,生成相关问题,帮助用户进一步学习,比如虚函数表的实现机制、动态绑定的性能影响、纯虚函数与抽象类的区别等。这些问题应基于教程内容,引导用户深入思考。 需要确保所有数学公式或代码格式正确,行内公式用$...$,独立公式用$$...$$,但本回答可能较少涉及数学公式,更多是代码示例。代码块用三个反引号包裹,并注明语言为cpp。 检查引用部分,确保正确标注。例如,在解释虚函数表时引用[^2],在讨论析构函数时引用[^3]。同时,用户可能混淆静态多态和动态多态,需要明确区分,引用[^1]中提到的静态多态方式。 总结步骤:介绍多态概念,解释虚函数的作用和原理,注意事项,提供代码示例,实验验证,最后相关问题。确保结构清晰,逐步引导用户理解。</think>### C++多态与虚函数使用教程及实验示例 #### 一、多态的核心概念 C++多态分为**静态多态**和**动态多态**: 1. **静态多态**:编译期确定,通过函数重载或模板实现 2. **动态多态**:运行期确定,通过虚函数和继承体系实现[^1] #### 二、虚函数的作用原理 1. **核心作用**:允许基类指针调用派生类重写的方法 2. **实现机制**: - 每个含虚函数的类生成**虚函数表(vtable)** - 对象内存首部存储**虚函数指针(vptr)**指向vtable - 派生类会覆盖基类虚函数表中的对应项[^2] $$ \text{对象内存布局} = [\text{vptr}] + [\text{成员变量}] $$ #### 三、实验代码示例 ```cpp #include <iostream> using namespace std; // 基类定义 class Animal { public: virtual void makeSound() { // 虚函数声明 cout << "动物发出声音" << endl; } virtual ~Animal() {} // 虚析构函数 }; // 派生类1 class Dog : public Animal { public: void makeSound() override { // 重写虚函数 cout << "汪汪汪" << endl; } }; // 派生类2 class Cat : public Animal { public: void makeSound() override { cout << "喵喵喵" << endl; } }; // 实验验证 int main() { Animal* animals[] = {new Dog(), new Cat()}; // 多态调用演示 for (auto animal : animals) { animal->makeSound(); delete animal; } // 验证虚函数指针存在 Animal a; cout << "对象大小(含vptr): " << sizeof(a) << " bytes" << endl; return 0; } ``` #### 四、关键注意事项 1. **虚析构函数必要性**:基类必须声明虚析构函数,否则通过基类指针删除派生类对象时会导致资源泄漏[^3] 2. **覆盖规则**:使用`override`关键字明确重写关系 3. **性能影响**:虚函数调用需要通过vptr间接寻址(约多消耗1次指针跳转) #### 五、进阶实验建议 1. 尝试移除`virtual`关键字观察行为变化 2. 添加非虚函数对比调用结果 3. 通过调试器查看对象内存中的vptr地址 4. 设计三层继承体系验证虚函数覆盖规则
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值