c++整理--虚函数

一、虚函数是这么实现的

解析:

  简单的说,虚函数是通过虚函数表实现的,那么什么是虚函数表呢?

  事实上,如果一个类中含有虚函数表,则系统会为这个类分配一个指针成员指向一张虚函数表(vtbl),表中每一项指向一个虚函数的地址,实际上就是一个函数指针的数组。为了说明虚函数表,请看程序:

    class Parent  
    {  
    public:  
        virtual void foo1() {}  
        virtual void foo2() {}  
        void foo3();  
    };  
      
    class Child1 : public Parent  
    {  
    public:  
        void foo1() {}  
        void foo3();  
    };  
      
    class Child2 : public Parent  
    {  
    public:  
        void foo1() {}  
        void foo2() {}  
        void foo3();  
    };  

下面列出了各个类的虚函数表

Parent类的vtbl:Parent::foo1()的地址、Parent::foo2()。

Child1类的vtbl:Child1::foo1()的地址、Parent::foo2()。

Child2类的vtbl:Child2::foo1()的地址、Child2::foo2()。

  可以看出,虚函数表既有继承性,又有多态性。每个派生类的vtbl继承了它各个基类的vtbl,如果基类vtbl中包含某一项,则其派生类的vtbl中也包含同样一项,但是两项的值可能不同。如果派生类覆盖(override)了该项对应的虚函数,则派生类vtbl的该项指向重载后的虚函数,如果没有重载的话,则沿用基类的值。

  在类对象的内存布局中,首先是vtbl指针,然后才是对象的数据。在通过对象指针调用一个虚函数时,编译器生成的代码将先获取对象类的vtbl指针,然后调用vtbl中对应的项。对于通过对象调用指针的情况,在编译期间无法确定指针指向的是基类对象还是派生类对象,或者是哪个派生类对象。但是在运行期间执行到调用语句时,这一点已经确定,编译后的调用代码能够根据具体对象获取正确的vtbl,调用正确的虚函数,从而实现多态性。

  分析一下这里的思想所在,问题的实质是这样,对于发出虚函数调用的这个对象指针,在编译期间缺乏更多的信息,而在运行期间具备足够的信息,但那时已不再进行绑定了,怎么在二者之间做一个过渡呢?把绑定所需的信息用一种通用的数据结构记录下来,该数据结构可以同对象指针相联系,在编译时只需要使用这个数据结构进行抽象的绑定,而在运行期间将会得到真正的绑定。这个数据结构就是vtbl。可以看到,实现用户所需的抽象和多态需要进行后绑定,而编译器又是通过抽象和多态实现后绑定的。


二、构造函数调用虚函数

#include <iostream>  
  
using namespace std;  
  
class A  
{  
public:  
    A() { doSth(); }                //构造函数调用虚函数  
    virtual void doSth()  
    {  
        printf("I am A");  
    }  
};  
  
class B : public A  
{  
public:  
    virtual void doSth()  
    {  
        printf("I am B");  
    }  
};  
  
int main()  
{  
    B b;  
      
    return 0;  

执行结果是什么?为什么?

  在构造函数中,虚拟机制不会发生作用,因为基类的构造函数在派生类构造函数之前执行,当基类构造函数执行时,派生类数据成员还没有被初始化。如果基类构造函数期间调用的虚函数向下匹配到派生类,派生类的函数理所应当会涉及本地数据成员,但是那些数据成员还没有被初始化,而调用涉及一个对象还没有被初始化的部分自然是危险的,所以c++会提示此路不通。因此,虚函数不会向下匹配到派生类,而是直接执行基类的函数。

结果:


  1. I am A 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Beep函数是一个Windows API函数,用于在计算机上发出声音。它的原型为:WINBASEAPI WINBOOL WINAPI Beep (DWORD dwFreq, DWORD dwDuration)。\[1\]该函数接受两个参数,dwFreq表示要发出的声音的频率,dwDuration表示声音的持续时间。通过调用Beep函数,可以在程序中产生不同频率和持续时间的声音效果。 在引用\[2\]的代码示例中,可以看到Beep函数被用来产生一段音乐。通过调用Beep函数并传入不同的频率和持续时间参数,可以实现不同音符的发声效果。这段代码使用了一系列的Beep函数调用来演奏了一首曲子。 除了Beep函数,Windows.h头文件中还定义了其他一些函数,比如MessageBox函数。MessageBox函数用于在窗口中显示一个消息框,可以用来向用户显示一些提示信息或者询问用户是否执行某个操作。\[3\]该函数也接受多个参数,包括消息框的标题、消息内容和按钮样式等。 总结起来,Beep函数是一个用于在计算机上发出声音的函数,可以通过调用该函数并传入不同的参数来产生不同的声音效果。而MessageBox函数则是用于在窗口中显示消息框的函数,可以用来向用户显示提示信息或者询问用户是否执行某个操作。 #### 引用[.reference_title] - *1* *2* *3* [C++ Beep、MessageBox函数详解](https://blog.csdn.net/Dpi168/article/details/110731492)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值