加入收藏 | 设为首页 | 会员中心 | 我要投稿 开发网_郴州站长网 (http://www.0735zz.com/)- 云通信、区块链、物联设备、云计算、站长网!
当前位置: 首页 > 教程 > 正文

C++的多态如何在编译和运行期达成

发布时间:2021-11-24 15:07:19 所属栏目:教程 来源:互联网
导读:多态是什么?简单来说,就是某段程序调用了一个API接口,但是这个API有许多种实现,根据上下文的不同,调用这段API的程序,会调用该API的不同实现。今天我们只关注继承关系下的多态。 还是得通过一个例子来看看C++是怎样在编译期和运行期来实现多态的。很简

多态是什么?简单来说,就是某段程序调用了一个API接口,但是这个API有许多种实现,根据上下文的不同,调用这段API的程序,会调用该API的不同实现。今天我们只关注继承关系下的多态。
 
还是得通过一个例子来看看C++是怎样在编译期和运行期来实现多态的。很简单,定义了一个Father类,它有一个testVFunc虚函数哟。再定义了一个继承Father的Child类,它重新实现了testVFunc函数,当然,它也学习Father定义了普通的成员函数testFunc。大家猜猜程序的输出是什么?
 
[cpp]
#include <iostream>   
using namespace std;  
  
class Father  
{  
public:  
    int m_fMember;  
  
    void testFunc(){  
        cout<<"Father testFunc "<<m_fMember<<endl;  
    }  
    virtual void testVFunc(){  
        cout<<"Father testVFunc "<<m_fMember<<endl;  
    }  
    Father(){m_fMember=1;}  
};  
  
class Child : public Father{  
public:  
    int m_cMember;  
    Child(){m_cMember=2;}  
      
    virtual void testVFunc(){cout<<"Child testVFunc "<<m_cMember<<":"<<m_fMember<<endl;}  
    void testFunc(){cout<<"Child testFunc "<<m_cMember<<":"<<m_fMember<<endl;}  
    void testNFunc(){cout<<"Child testNFunc "<<m_cMember<<":"<<m_fMember<<endl;}  
};  
  
  
int main()  
{  
    Father* pRealFather = new Father();  
    Child* pFalseChild = (Child*)pRealFather;  
    Father* pFalseFather = new Child();  
      
    pFalseFather->testFunc();  
    pFalseFather->testVFunc();  
  
    pFalseChild->testFunc();  
    pFalseChild->testVFunc();      
    pFalseChild->testNFunc();      
  
    return 0;  
}  
同样调用了testFunc和testVfunc,输出截然不同,这就是多态了。它的g++编译器输出结果是:
[cpp]
Father testFunc 1  
Child testVFunc 2:1  
Child testFunc 0:1  
Father testVFunc 1  
Child testNFunc 0:1  
看看main函数里调用的五个test*Func方法吧,这里有静态的多态,也有动态的多态。编译是静态的,运行是动态的。以下解释C++编译器是怎么形成上述结果的。
 
 
首先让我们用gcc -S来生成汇编代码,看看main函数里是怎么调用这五个test*Func方法的。
 
[cpp]
        movl    $16, %edi  
        call    _Znwm   
        movq    %rax, %rbx  
        movq    %rbx, %rdi  
        call    _ZN6FatherC1Ev  
        movq    %rbx, -32(%rbp)  
        movq    -32(%rbp), %rax  
        movq    %rax, -24(%rbp)  
        movl    $16, %edi  
        call    _Znwm   
        movq    %rax, %rbx  
        movq    %rbx, %rdi  
        call    _ZN5ChildC1Ev  
        movq    %rbx, -16(%rbp)  
        movq    -16(%rbp), %rdi  
<span style="color:#ff0000;">        call    _ZN6Father8testFuncEv    本行对应pFalseFather->testFunc();</span>  
        movq    -16(%rbp), %rax  
        movq    (%rax), %rax  
        movq    (%rax), %rax  
        movq    -16(%rbp), %rdi  
<span style="color:#ff0000;">        call    *%rax                                        本行对应pFalseFather->testVFunc();</span>  
        movq    -24(%rbp), %rdi  
<span style="color:#ff0000;">        call    _ZN5Child8testFuncEv     本行对应pFalseChild->testFunc();</span>  
        movq    -24(%rbp), %rax  
        movq    (%rax), %rax  
        movq    (%rax), %rax  
        movq    -24(%rbp), %rdi  
<span style="color:#ff0000;">        call    *%rax                                        本行对应pFalseChild->testVFunc();    </span>  
        movq    -24(%rbp), %rdi  
<span style="color:#ff0000;">        call    _ZN5Child9testNFuncEv        本行对应pFalseChild->testNFunc();    </span>  
        movl    $0, %eax  
        addq    $40, %rsp  
        popq    %rbx  
        leave  
红色的代码,就是在依次调用上面5个test*Func。可以看到,第1、3次testFunc调用,其结果已经在编译出来的汇编语言中定死了,C++代码都是调用某个对象指针指向的testFunc()函数,输出结果却不同,第1次是:Father testFunc 1,第3次是:Child testFunc 0:1,原因何在?在编译出的汇编语言很明显,第一次调用的是_ZN6Father8testFuncEv代码段,第三次调用的是_ZN5Child8testFuncEv代码段,两个不同的代码段!编译完就已经决定出同一个API用哪种实现,这就是编译期的多态。

(编辑:开发网_郴州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读