zoukankan      html  css  js  c++  java
  • C++中的虚函数(1)

    虚函数语法形式

    class Foo{
        ...
        virtual void func();
        ...
    };

    C++虚函数必须和C++的继承结合起来一起看。示例是最好的解释。

    #include <iostream>
    using namespace std;
    class Base{
        public:
            void func1(){
                cout<<"I'm Base func1"<<endl;
            }
            virtual void func2(){
                cout<<"I'm Base func2"<<endl;
            }
    };
    
    class Derived:public Base{
        public:
            void func1(){
                cout<<"I'm Derived func1"<<endl;
            }
            virtual void func2(){
                cout<<"I'm Derived func2"<<endl;
            }
    };
    
    int main(){
        Derived d= Derived();
        Base &o = d;            //创建了一个指向子类对象的引用
        o.func1();              //func1不是虚函数,因此使用了Base的func1方法
        o.func2();              //func2是虚函数,因此根据引用所指向的实际对象的类型选择func2,即Derived的func2
        return 0;
    }

    运行结果

    I'm Base func1
    I'm Derived func2

    汇编代码分析

      40091c:       48 c7 45 f0 00 00 00    movq   $0x0,-0x10(%rbp)          #-0x10(%rbp)中存放的是对象d,这个对象占用8个字节
      400923:       00                                                       #这8个字节将会用来存储一个指针,指针指向Derived类的虚函数表
      400924:       48 8d 45 f0             lea    -0x10(%rbp),%rax
      400928:       48 89 c7                mov    %rax,%rdi
      40092b:       e8 18 01 00 00          callq  400a48 <_ZN7DerivedC1Ev>  #调用Derived的默认构造函数
      400930:       48 8d 45 f0             lea    -0x10(%rbp),%rax
      400934:       48 89 45 f8             mov    %rax,-0x8(%rbp)           #-0x8(%ebp)存储引用o,o的内容实际上是对象d的起始地址。
      400938:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      40093c:       48 89 c7                mov    %rax,%rdi                 #这两行准备this指针
      40093f:       e8 70 00 00 00          callq  4009b4 <_ZN4Base5func1Ev  #不是虚函数,直接调用Base的func1
      400944:       48 8b 45 f8             mov    -0x8(%rbp),%rax           #取出d的地址
      400948:       48 8b 00                mov    (%rax),%rax               #取出d的内容,即指向Derived类虚函数表的指针
      40094b:       48 8b 10                mov    (%rax),%rdx               #func2是Derived类的唯一虚函数,即第0项。取出func2的地址。
      40094e:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      400952:       48 89 c7                mov    %rax,%rdi                 #这两行也是准备this指针
      400955:       ff d2                   callq  *%rdx                     #调用func2

    如果感兴趣,可以用gdb实际调试一下,观察运行的过程。

    NOTE 1: 当子类不override父类的虚函数,那么子类就自动继承父类的虚函数。

    NOTE 2: 虚函数也可以有默认参数。如果用父类的指针或引用指向子类的对象,那么调用的函数是子类的,使用的默认参数却是父类函数的。(C++真是无比混乱啊!)

    NOTE 3: 如果不想动态调用虚函数,可以使用类名+'::'来限定调用哪个函数。例如,上例中可以添加语句o.Base::func2()来调用父类的func2。

  • 相关阅读:
    HDU 1501 Zipper(DFS)
    HDU 2181 哈密顿绕行世界问题(DFS)
    HDU 1254 推箱子(BFS)
    HDU 1045 Fire Net (DFS)
    HDU 2212 DFS
    HDU 1241Oil Deposits (DFS)
    HDU 1312 Red and Black (DFS)
    HDU 1010 Tempter of the Bone(DFS+奇偶剪枝)
    HDU 1022 Train Problem I(栈)
    HDU 1008 u Calculate e
  • 原文地址:https://www.cnblogs.com/richardustc/p/2988449.html
Copyright © 2011-2022 走看看