精华内容
下载资源
问答
  • 虚函数的基类与子类构造函数中调用虚函数。当生成子类对象时,函数的调用顺序是怎样的
  • 析构函数参考:http://blog.csdn.net/zengchen__acmer/article/details/22592195?utm_source=tuicool构造函数参考:...C++构造函数调用顺序: 1、创建派生类的对象,基类的构造函数函数优先被调用(也优先于...

    析构函数参考:
    http://blog.csdn.net/zengchen__acmer/article/details/22592195?utm_source=tuicool
    构造函数参考:
    http://www.cnblogs.com/nliao/archive/2012/02/05/2339175.html

    C++构造函数调用顺序:

    1、创建派生类的对象,基类的构造函数函数优先被调用(也优先于派生类里的成员类,多继承时,按照派生表的顺序依次调用);

    2、如果类里面有成员类,成员类的构造函数优先被调用(按照声明的顺序调用);

    3、派生类构造函数。

    C++析构函数主要遵从一下四点规则:

    1、首先调用派生类的析构函数(清理派生类的新增成员);

    2、如果派生类中有子对象 , 则再调用派生类中子对象的析构函数 , 调用顺序是:在派生类中,先定义后调用。(清理派生类新增的成员对象);

    3、再调用普通基类的析构函数(清理从基类继承来的新增成员);

    4、最后调用虚基类的析构函数。

    转载于:https://www.cnblogs.com/wrencai/p/5894943.html

    展开全文
  • 继承作为面向对象编程的一种基本特征,其使用频率...  假设derived 继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。(貌似有些牵强!某些编译器确实如此)  因此
  • C++虚函数与函数的执行顺序

    千次阅读 2016-05-28 17:26:53
    虚函数与纯虚函数的区别,虚函数与一般函数的执行顺序的先后,根据几道例题来分析理解

    一.定义

    虚函数: 在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,可实现函数成员的动态重载。

    纯虚函数: 纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。含有纯虚函数的类被称为抽象类(abstract class)


    二.格式

    虚函数:virtual <函数返回类型>< 函数名>(<参数表>) {函数体};

    纯虚函数:virtual <函数返回类型><函数名>(<参数表>)=0;


    三.不同点

    1.虚函数可以直接使用,也可以在子类中重载以多态的形式调用,但纯虚函数在基类中只有声明没有定义,所以只能在子类中实现了该函数才可以以多态的形式调用。
    2.虚函数在子类中可以不被重载,但是纯虚函数必须在子类中实现。
    3.包含纯虚函数的类成为抽象类,这种类不能声明对象,只是作为基类为派生类服务。除非在派生类中完全实现基类中所有的的纯虚函数,否则,派生类也变成了抽象类,不能实例化对象。

    虚函数以及构造函数执行顺序的一些特性(例题)

    例题一(函数执行顺序)

    下面这段代码会打印出什么?

    class A
    {
    public:
        A()
        {
            printf("A ");
        }
        ~A()
        {
            printf("deA ");
        }
    };
    
    class B
    {
    public:
        B()
        {
            printf("B ");
        }
        ~B()
        {
            printf("deB ");
        }
    };
    
    class C: public A, public B
    {
    public:
        C()
        {
            printf("C ");
        }
        ~C()
        {
            printf("deC ");
        }
    };
    int main()
    {
        A *a = new C();
        delete a;
        return 0;
    }
    

    正确答案: A 你的答案: B (错误)

    (A) A B C deA

    (B) C A B deA

    (C) A B C deC

    (D) C A B deC

    解析:构造函数的执行先执行父类,再执行子类。析构函数的执行顺序相反,A B的析构函数不是虚函数,所以不会执行子类的虚函数。


    例题二(函数执行顺序)

    这里写图片描述

    解析:
    1.当派生类中不含对象成员时
    在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
    析构函数相反。
    2.当派生类中含有对象成员时
    在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
    析构函数相反。


    例题三(虚函数调用顺序)

    这里写图片描述
    这里写图片描述

    解析:创建一个类对象c,然后动态类型转换,让一个B *b1指针指向c,再一次动态类型转换,让一个基类A *a2指针指向b1,当delete a2时,调用析构函数,但是基类A的析构函数不是虚函数,所以只调用A的析构函数,结果应该是:~A()
    动态的多态通过虚函数实现,基类指针指向派生类的对象,若指针调用的函数派生类中存在,且在基类中声明为虚函数,则调用的函数是派生类中的函数。 析构函数总是要声明为虚函数,这样析构时,先调用派生类的析构函数,再调用基类的析构函数,防止内存造成泄露 。A类的析构函数未声明为虚函数,所以A类的指针,只可以调用A类的析构函数


    例题四(纯虚函数)

    这里写图片描述
    解析:纯虚函数格式:virtual <类型> <函数名> (<参数表>) = 0;

    展开全文
  • 如果子类中有虚函数则先将子类的虚函数入栈,然后是父类的虚函数,如果子类重写了父类的虚函数,则入栈的是子类重写的函数,即重写的子类的函数替换对应的父类的虚函数。 如://A.h #ifndef __A_H #define __A_H ...

    如果子类中有虚函数则先将子类的虚函数入栈,然后是父类的虚函数,如果子类重写了父类的虚函数,则入栈的是子类重写的函数,即重写的子类的函数替换对应的父类的虚函数。

    如://A.h

    #ifndef __A_H
    #define __A_H
    #include <iostream>
    using namespace std;
    class A{
    //private:
    virtual void f()
    {
    cout<<"A::f"<<endl;
    }
    virtual void g(){
    cout<<"A::g"<<endl;
    }
    };

    #endif

    //B.h

    #ifndef __B_H
    #define __B_H

    //#include <iostream>
    #include "A.h"

    class B:public A{
    void d()
    {
    cout<<"B::d"<<endl;
    }
    virtual void h()
    {
    cout<<"B::h"<<endl;
    }
    };
    #endif

    //main.cpp

    #include "B.h"
    typedef void(*Fun)(void);
    int main()
    {
    B b;
    Fun pFun;
    int i;
    for(i=0;i<3;i++)
    {
    pFun=(Fun)*((int*)*(int*)(&b)+i);
    pFun();
    }
    }


    展开全文
  • 笔者最近学习过程中发现对C++的虚拟继承不是很明朗,故在这里对继承做个小结。 首先说下遇到的问题吧。代码如下(代码来自于何海涛《程序员面试精选100题第32题)。意图是要设计一个不能被继承的类,类似java中的...

    虚拟继承是C++语言中一个非常重要但是又比较生僻的存在,它的定义非常简单,但是对于理解C++的继承机制却是非常有用的。笔者最近学习过程中发现对C++的虚拟继承不是很明朗,故在这里对虚继承做个小结。

    首先说下遇到的问题吧。代码如下(代码来自于何海涛《程序员面试精选100题第32题)。意图是要设计一个不能被继承的类,类似java中的final。但是又可以生成栈对象,可以像一般的C++类一样使用。

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include "stdafx.h"  
    2. #include <iostream>  
    3. using namespace std;  
    4. template <class T> class MakeFinal  
    5. {  
    6.     friend T;  
    7. private:  
    8.     MakeFinal()  
    9.     {  
    10.         cout<<"in MakeFinal"<<endl;  
    11.     }  
    12.     ~MakeFinal(){}  
    13. };  
    14. class FinalClass: virtual public MakeFinal<FinalClass>  
    15. {  
    16. public:  
    17.     FinalClass()  
    18.     {  
    19.         cout<<"in FinalClass"<<endl;  
    20.     }  
    21.     ~FinalClass(){}  
    22. };  
    23.   
    24. class Try: public FinalClass  
    25. {  
    26. public:  
    27.     Try()  
    28.     {  
    29.         cout<<"in Try"<<endl;  
    30.     }  
    31. };  

    这样的确使得FinalClass不能被继承了,原因在于类FinalClass是从类MakeFinal<Final>虚继承过来的,在调用Try的构造函数的时候,会直接跳过FinalClass而直接调用MakeFinal<FinalClass>的构造函数。而Try不是MakeFinal<Final>的友元,所以这里就会出现编译错误。但是如果把虚继承改成一般的继承,这里就没什么问题了。笔者对这里的调用顺序不是很明朗,为了对虚继承有彻底的了解,故做个小结。将从下面几个方向进行总结:1、为何要有虚继承;2、虚继承对于类的对象布局的影响;3、虚基类对构造函数的影响;

    1、为什么需要虚继承

    由于C++支持多重继承,那么在这种情况下会出现重复的基类这种情况,也就是说可能出现将一个类两次作为基类的可能性。比如像下面的情况

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include<iostream>  
    2. using std::cout;  
    3. using std::endl;  
    4. class Base  
    5. {  
    6. protected:  
    7.     int value;  
    8. public:  
    9.     Base()  
    10.     {  
    11.         cout<<"in Base"<<endl;  
    12.     }  
    13. };  
    14. class DerivedA:protected Base  
    15. {  
    16. public:  
    17.     DerivedA()  
    18.     {  
    19.         cout<<"in DerivedA"<<endl;  
    20.     }  
    21. };  
    22. class DerivedB: protected Base  
    23. {  
    24. public:  
    25.     DerivedB()  
    26.     {  
    27.         cout<<"in DerivedB"<<endl;  
    28.     }  
    29. };  
    30. class MyClass:DerivedA,DerivedB  
    31. {  
    32. public:  
    33.     MyClass()  
    34.     {  
    35.         cout<<"in MyClass"<<value<<endl;  
    36.     }  
    37. };  

    编译时的错误如下


    这中情况下会造成在MyClass中访问value时出现路径不明确的编译错误,要访问数据,就需要显示地加以限定。变成DerivedA::value或者DerivedB::value,以消除歧义性。并且,通常情况下,像Base这样的公共基类不应该表示为两个分离的对象,而要解决这种问题就可以用虚基类加以处理。如果使用虚继承,编译便正常了,类的结构示意图便如下。

    虚继承的特点是,在任何派生类中的virtual基类总用同一个(共享)对象表示,正是如上图所示。

    2、虚继承对类的对象布局的影响

    要理解多重继承情况中重复基类时为什么会出现访问路径不明确的编译错误,需要了解继承中类对象在内存中的布局。在C++继承中,子类会继承父类的成员变量,因此在子类对象在内存中会包括来自父类的成员变量。实例代码如下,输出结果表明了每个对象在内存中所占的大小。

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include<iostream>  
    2. using std::cout;  
    3. using std::endl;  
    4. class Base  
    5. {  
    6. protected:  
    7.     int value;  
    8. public:  
    9.     Base()  
    10.     {  
    11.         //cout<<"in Base"<<endl;  
    12.     }  
    13. };  
    14. class DerivedA:protected  Base  
    15. {  
    16. protected:  
    17.     int valueA;  
    18. public:   
    19.     DerivedA()  
    20.     {  
    21.         //cout<<"in DerivedA"<<endl;  
    22.     }  
    23. };  
    24. class DerivedB: protected  Base  
    25. {  
    26. protected:  
    27.     int valueB;  
    28. public:  
    29.     DerivedB()  
    30.     {  
    31.         //cout<<"in DerivedB"<<endl;  
    32.     }  
    33. };  
    34. class MyClass:DerivedA  
    35. {  
    36. private:  
    37.     int my_value;  
    38. public:  
    39.     MyClass()  
    40.     {  
    41.         //cout<<"in MyClass"<<value<<endl;  
    42.     }  
    43. };  
    44. int main()  
    45. {  
    46.     Base base_obj;  
    47.     DerivedA derA_obj;  
    48.     MyClass my_obj;  
    49.     cout<<"size of Base object "<<sizeof(base_obj)<<endl;  
    50.     cout<<"size of DerivedA object "<<sizeof(derA_obj)<<endl;  
    51.     cout<<"size of MyClass object "<<sizeof(my_obj)<<endl;  
    52. }  

    输出结果如下

    从类的定义结合这里的输出便不难明白,在子类对象中是包含了父类数据的,即在C++继承中,一个子类的object所表现出来的东西,是其自己的members加上其基类的member的总和。示意图如下(这里只讨论非静态变量)


    在单继承的时候,访问相关的数据成员时,只需要使用名字即可。但是,在多重继承时,情况会变得复杂。因为重复基类中,在子类中变量名是相同的。这时,如果直接使用名字去访问,便会出现歧义性。看下面的代码以及对应的输出

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include<iostream>  
    2. using std::cout;  
    3. using std::endl;  
    4. class Base  
    5. {  
    6. protected:  
    7.     int value;  
    8. public:  
    9.     Base()  
    10.     {  
    11.         //cout<<"in Base"<<endl;  
    12.     }  
    13. };  
    14. class DerivedA:protected  Base  
    15. {  
    16. protected:  
    17.     int valueA;  
    18. public:   
    19.     DerivedA()  
    20.     {  
    21.         //cout<<"in DerivedA"<<endl;  
    22.     }  
    23. };  
    24. class DerivedB: protected  Base  
    25. {  
    26. protected:  
    27.     int valueB;  
    28. public:  
    29.     DerivedB()  
    30.     {  
    31.         //cout<<"in DerivedB"<<endl;  
    32.     }  
    33. };  
    34. class MyClass:DerivedA,DerivedB  
    35. {  
    36. private:  
    37.     int my_value;  
    38. public:  
    39.     MyClass()  
    40.     {  
    41.         //cout<<"in MyClass"<<value<<endl;  
    42.     }  
    43. };  
    44. int main()  
    45. {  
    46.     Base base_obj;  
    47.     DerivedA derA_obj;  
    48.     MyClass my_obj;  
    49.     cout<<"size of Base object "<<sizeof(base_obj)<<endl;  
    50.     cout<<"size of DerivedA object "<<sizeof(derA_obj)<<endl;  
    51.     cout<<"size of MyClass object "<<sizeof(my_obj)<<endl;  
    52. }  

    输出如下


    代码的变化之处在于MyClass同时继承了DerivedA和DerivedB。而my_obj在内存中的大小变成了20,比之前大了8.正好是增加了继承至DerivedB中的数据部分的大小。上面情况中,my_obj在内存中的布局示意图如下



    从图中可以看到,来自Base基类的数据成员value重复出现了两次。这也正是为什么在MyClass中直接访问value时会出现访问不明确的问题了。

    那么使用虚继承后,对象的数据在内存中的布局又是什么样子呢?按照预测,既然在my_obj中只有一份来自Base的value,那么大小是否就是16呢?

    代码及输出如下

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include<iostream>  
    2. using std::cout;  
    3. using std::endl;  
    4. class Base  
    5. {  
    6. protected:  
    7.     int value;  
    8. public:  
    9.     Base()  
    10.     {  
    11.         //cout<<"in Base"<<endl;  
    12.     }  
    13. };  
    14. class DerivedA:protected  virtual Base  
    15. {  
    16. protected:  
    17.     int valueA;  
    18. public:   
    19.     DerivedA()  
    20.     {  
    21.         //cout<<"in DerivedA"<<endl;  
    22.     }  
    23. };  
    24. class DerivedB: protected virtual Base  
    25. {  
    26. protected:  
    27.     int valueB;  
    28. public:  
    29.     DerivedB()  
    30.     {  
    31.         //cout<<"in DerivedB"<<endl;  
    32.     }  
    33. };  
    34. class MyClass:DerivedA,DerivedB  
    35. {  
    36. private:  
    37.     int my_value;  
    38. public:  
    39.     MyClass()  
    40.     {  
    41.         //cout<<"in MyClass"<<value<<endl;  
    42.     }  
    43. };  
    44. int main()  
    45. {  
    46.     Base base_obj;  
    47.     DerivedA derA_obj;  
    48.     DerivedB derB_obj;  
    49.     MyClass my_obj;  
    50.     cout<<"size of Base object "<<sizeof(base_obj)<<endl;  
    51.     cout<<"size of DerivedA object "<<sizeof(derA_obj)<<endl;  
    52.     cout<<"size of DerivedB object "<<sizeof(derB_obj)<<endl;  
    53.     cout<<"size of MyClass object "<<sizeof(my_obj)<<endl;  
    54. };  

    输出结果如下


    可以看到,DerivedA和DerivedB对象的大小变成了12,而MyClass对象的大小则变成了24.似乎大大超出了我们的预料。这其实是由于编译器在其中插入了一些东西用来寻找这个共享的基类数据所用而造成的。(来自《深度探索C++对象模型》第3章 侯捷译)这样理解,Class如果内含一个或多个虚基类子对象,那么将被分割为两部分:一个不变部分和一个共享部分。不变局部中的数据,不管后继如何衍化,总是拥有固定的offset,所以这一部分数据可以直接存取。至于共享局部,所表现的就是虚基类子对象。根据编译其的不同,会有不同的方式去得到这部分的数据,但总体来说都是需要有一个指向这部分共享数据的指针。

    示意图如下


    当然实际编译器使用的技术比这个要复杂,这里就不做详细讨论了。感兴趣的朋友可以参见《深入探索C++对象模型》

    3、虚继承对构造函数的影响

    对于构造函数的影响,借助于下面的原则可以理解(来自《深入理解C++对象模型》)

    构造函数的调用可能内带大量的隐藏码,因为编译器会对构造函数进行扩充,一般而言编译器所作的扩充操作大约如下:

    1、记录在成员初始化列表中的数据成员的初始化操作会被放到构造函数本身中,按照数据成员声明的顺序

    2、如果有一个数据成员没有出现在初始化列表中,但是它有一个默认构造函数,那么这个默认构造函数会被调用

    3、在那之前,如果有虚函数表,会调整虚函数表指针

    4、在那之前,会对上一层基类的构造函数进行调用

    5、在那之前,所有虚基类的构造函数必须被调用,按照声明的继承顺序从左往右,从最深到最浅的顺序


    从上面的规则可以看出,对于虚基类的构造函数的调用是放在最前面的,并且需要子类对于虚基类的构造函数拥有访问权限

    从下面的示例代码可以看出

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include<iostream>  
    2. using std::cout;  
    3. using std::endl;  
    4. class Base  
    5. {  
    6. protected:  
    7.     int value;  
    8. public:  
    9.     Base()  
    10.     {  
    11.         cout<<"in Base"<<endl;  
    12.     }  
    13. };  
    14. class DerivedA:protected  Base  
    15. {  
    16. protected:  
    17.     int valueA;  
    18. public:   
    19.     DerivedA()  
    20.     {  
    21.         cout<<"in DerivedA"<<endl;  
    22.     }  
    23. };  
    24. class DerivedB  
    25. {  
    26. protected:  
    27.     int valueB;  
    28. public:  
    29.     DerivedB()  
    30.     {  
    31.         cout<<"in DerivedB"<<endl;  
    32.     }  
    33. };  
    34. class TestClass  
    35. {  
    36. public:  
    37.     TestClass()  
    38.     {  
    39.         cout<<"in TestClass"<<endl;  
    40.     }  
    41. };  
    42. class MyClass:DerivedA,virtual DerivedB  
    43. {  
    44. private:  
    45.     int my_value;  
    46.     TestClass testData;  
    47. public:  
    48.     MyClass()  
    49.     {  
    50.         //cout<<"in MyClass"<<value<<endl;  
    51.     }  
    52. };  
    53. int main()  
    54. {  
    55.     /* 
    56.     Base base_obj; 
    57.     DerivedA derA_obj; 
    58.     DerivedB derB_obj; 
    59.     MyClass my_obj; 
    60.     cout<<"size of Base object "<<sizeof(base_obj)<<endl; 
    61.     cout<<"size of DerivedA object "<<sizeof(derA_obj)<<endl; 
    62.     cout<<"size of DerivedB object "<<sizeof(derB_obj)<<endl; 
    63.     cout<<"size of MyClass object "<<sizeof(my_obj)<<endl;*/  
    64.     MyClass my_obj;  
    65. }  

    代码运行后的效果如下所示


    虽然在声明继承顺序的时候DerivedA的顺序是在DerivedB的前面的,但是由于DerivedB是虚拟继承,所以对DerivedB的调用会在最前。但是如果将DerivedA继承也改成虚继承,那么调用顺序就会发生变化。并且具体DerivedA的构造函数的调用与DerivedB的构造函数的调用顺序还与是MyClass虚继承DerivedA还是DerivedA虚继承Base有关。还是用代码来说明

    MyClass虚继承DerivedA的情况,由于DerivedA声明在DerivedB前面,并且都是虚继承,所以先调用DerivedA的构造函数。但DerivedA的父类是Base,所以具体的构造函数的调用顺序是Base、DerivedA、DerivedB、TestClass。这种情况代码如下

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include<iostream>  
    2. using std::cout;  
    3. using std::endl;  
    4. class Base  
    5. {  
    6. protected:  
    7.     int value;  
    8. public:  
    9.     Base()  
    10.     {  
    11.         cout<<"in Base"<<endl;  
    12.     }  
    13. };  
    14. class DerivedA:protected  Base  
    15. {  
    16. protected:  
    17.     int valueA;  
    18. public:   
    19.     DerivedA()  
    20.     {  
    21.         cout<<"in DerivedA"<<endl;  
    22.     }  
    23. };  
    24. class DerivedB  
    25. {  
    26. protected:  
    27.     int valueB;  
    28. public:  
    29.     DerivedB()  
    30.     {  
    31.         cout<<"in DerivedB"<<endl;  
    32.     }  
    33. };  
    34. class TestClass  
    35. {  
    36. public:  
    37.     TestClass()  
    38.     {  
    39.         cout<<"in TestClass"<<endl;  
    40.     }  
    41. };  
    42. class MyClass:virtual DerivedA,virtual DerivedB  
    43. {  
    44. private:  
    45.     int my_value;  
    46.     TestClass testData;  
    47. public:  
    48.     MyClass()  
    49.     {  
    50.         //cout<<"in MyClass"<<value<<endl;  
    51.     }  
    52. };  
    53. int main()  
    54. {  
    55.     /* 
    56.     Base base_obj; 
    57.     DerivedA derA_obj; 
    58.     DerivedB derB_obj; 
    59.     MyClass my_obj; 
    60.     cout<<"size of Base object "<<sizeof(base_obj)<<endl; 
    61.     cout<<"size of DerivedA object "<<sizeof(derA_obj)<<endl; 
    62.     cout<<"size of DerivedB object "<<sizeof(derB_obj)<<endl; 
    63.     cout<<"size of MyClass object "<<sizeof(my_obj)<<endl;*/  
    64.     MyClass my_obj;  
    65. }  

    输出如下



    但如果将虚继承放在由DerivedA虚继承Base,而MyClass非虚继承DerivedA。那么按照从左往右,从深到浅的顺序,调用顺序应该是Base、DerivedB、DerivedA、TestClass

    ,代码示例如下

    [cpp]  view plain  copy
      在CODE上查看代码片 派生到我的代码片
    1. #include<iostream>  
    2. using std::cout;  
    3. using std::endl;  
    4. class Base  
    5. {  
    6. protected:  
    7.     int value;  
    8. public:  
    9.     Base()  
    10.     {  
    11.         cout<<"in Base"<<endl;  
    12.     }  
    13. };  
    14. class DerivedA:protected virtual  Base  
    15. {  
    16. protected:  
    17.     int valueA;  
    18. public:   
    19.     DerivedA()  
    20.     {  
    21.         cout<<"in DerivedA"<<endl;  
    22.     }  
    23. };  
    24. class DerivedB  
    25. {  
    26. protected:  
    27.     int valueB;  
    28. public:  
    29.     DerivedB()  
    30.     {  
    31.         cout<<"in DerivedB"<<endl;  
    32.     }  
    33. };  
    34. class TestClass  
    35. {  
    36. public:  
    37.     TestClass()  
    38.     {  
    39.         cout<<"in TestClass"<<endl;  
    40.     }  
    41. };  
    42. class MyClass: DerivedA,virtual DerivedB  
    43. {  
    44. private:  
    45.     int my_value;  
    46.     TestClass testData;  
    47. public:  
    48.     MyClass()  
    49.     {  
    50.         //cout<<"in MyClass"<<value<<endl;  
    51.     }  
    52. };  
    53. int main()  
    54. {  
    55.     /* 
    56.     Base base_obj; 
    57.     DerivedA derA_obj; 
    58.     DerivedB derB_obj; 
    59.     MyClass my_obj; 
    60.     cout<<"size of Base object "<<sizeof(base_obj)<<endl; 
    61.     cout<<"size of DerivedA object "<<sizeof(derA_obj)<<endl; 
    62.     cout<<"size of DerivedB object "<<sizeof(derB_obj)<<endl; 
    63.     cout<<"size of MyClass object "<<sizeof(my_obj)<<endl;*/  
    64.     MyClass my_obj;  
    65. }  

    输出如下


    这里还有一个问题是,左右顺序和深浅顺序该如何抉择呢?答案是先左右,再深浅。比如将上面的代码改为class MyClas: virutal DerivedB, DerivedA{...}

    那么最后的调用顺序就是DerivedB,Base, DerivedA,TestClass。读者可以自己验证。


    展开全文
  • 虚函数调用的几种方式 /* * 虚函数的三种调用 * 1: 指针 * 2: 引用 * 3: 对象(不能实现多态) */ #include &lt;iostream&gt; //继承,默认情况下class是私有继承 struct默认是公有继承 //虚函数...
  • 原本以为自己对虚函数掌握的还可以,结果前几天面试的时候被问了一个构造和析构函数里调用虚函数的问题,结果就给答错了。
  • 基类(父类)构造函数–>类成员变量的构造函数—>派生类(子类)构造函数 2:析构 派生类子类构造函数–>基类(父类)构造函数 所以 析构和析构 基本是对称的 AABBCAA <------===-----> ~A ~A ~C ~B ...
  • 虚函数定义及其调用

    千次阅读 2018-09-14 08:40:21
    /*虚函数总是在继承环境中使用,用虚函数实现动态多态性的一般方法如下: 在基类中定义虚函数 在派生类中定义与基类虚函数同名同参数同返回值类型的成员函数 即派生类中的虚函数 虽然基类中的虚函数与个派生类中的...
  • 在构造函数中调用虚函数

    千次阅读 2019-07-19 15:44:02
    所以在构造函数中完全可以调用虚函数,只是调用的语义不符预期,在A()中的this类型是A *指针,我们期望调用的是B::fun(),但是实际上调用的是A::fun()。 原因也很简单,仔细过一下构造函数的执行流程即可。调用B...
  • 解释某个函数,我通常的讲解不会先去长篇大论去空谈,先整个例子来看看!!走起.... #include #include string> using namespace std; class A { public: A(const char*s) { coutendl; } }; class B:...
  • 构造函数和析构函数调用顺序

    千次阅读 2019-09-03 15:47:29
    目录构造函数和析构函数构造函数复制构造函数析构函数构造函数与析构函数调用顺序单继承多继承 构造函数和析构函数 构造函数 构造函数是特殊的成员函数,与类同名,没有返回类型,而且允许重载。如果没有为类显式...
  • C++继承中构造函数、析构函数调用顺序析构函数 首先说说构造函数,大家都知道构造函数里就可以调用成员变量,而继承中子类是把基类的成员变成自己的成员,那么也就是说子类在构造函数里就可以调用...
  • 构造和析构函数调用顺序

    千次阅读 2019-03-11 20:40:54
    缺省构造函数时,系统将自动调用该缺省构造函数初始化对象,缺省构造函数会将所有数据成员都初始化为零或空 创建一个对象时,系统自动调用构造函数②析构函数 析构函数没有参数,也没有返回值。不能重载,也就是说,...
  • ,当你执行这个虚函数时,首先找到该虚函数代表的实体子类,并执行子类中的相关代码。 ************************************************************************** 比如有一个父类superClass,它有2个子类...
  • 虚函数调用

    千次阅读 2017-03-12 17:44:58
    虚函数怎么调用: (1)先找到虚函数表 (2)从虚表中找到要调用虚函数。单继承中派生类虚表的形成: 先看下述的代码:#include using namespace std;//基类中包含虚函数和普通函数 class Base { public: ...
  • 构造函数调用顺序

    2014-09-27 19:30:47
    构造函数调用顺序: 1》首先调用基类的构造函数(如果有基类);如果有多个基类,则按基类被列出的顺序调用; 2》调用这个类的成员对象的构造函数(如果有的话);弱国有多个成员对象,则按成员对象定义的顺序被调用...
  • 虚函数调用过程

    千次阅读 2016-03-15 15:54:33
    2.(mov edx,dword ptr [ecx])this指针指向该对象的首地址,而该处的前四个字节存放着该对象的虚函数表的首地址,将虚表指针放到edx中。 3.(call dword ptr [edx+4])由于edx中存放着虚表指针,则edx+4表示调用...
  • C++虚函数指针虚函数

    千次阅读 多人点赞 2017-07-10 22:25:57
    函数重载和运算符重载实现的多态属于静态多态,而通过虚函数可以实现动态多态。实现函数的动态联编其本质核心则是虚表指针与虚函数表。   1. 虚函数与纯虚函数区别 1)虚函数在子类里面也可以不重载的;但纯虚必须...
  • 派生类的构造函数与析构函数调用顺序 前面已经提到,构造函数和析构函数调用顺序是先构造的后析构,后构造的先析构。 那么基类和派生类中的构造函数和析构函数调用顺序是否也是如此呢? 构造函数调用...
  • 执行t.GetData(),three中无此函数,去父类two找也无此函数,再去父父类one中找到了此函数,执行调用了dodata函数,因为dodata为虚函数虚函数实现了多态,根据实例化的对象选择调用哪个类中的函数,父类为虚函数 ...
  • 创建Derived对象时调用Derived构造函数,Derived构造函数中没有显示调用父类Base构造函数,但是创建Derived对象时依然会调用父类base的构造函数,故输出了Base和Derived构造信息。同样的通过动态分配内存创建Derived...
  • 通常情况下: 当创建派生类对象时: 基类的构造函数——>派生类的构造函数;...1.派生类的构造函数和析构函数调用顺序 (1) 输出的是:基类的构造函数 基类的构造函数 派生类的构造函数 输出...
  • 第一个例子: #include using namespace std;...所以从这里可以总结出的调用顺序是: 先调用父类的构造函数,接着调用类成员对象的构造函数(因为先初始化成员),最后才轮到调用自身的构造函数
  • 继承时,构造函数和析构函数调用顺序 保证你们一篇看懂,不懂得可以留言!!!一定给你们讲明白! 先调用父类的构造函数,再初始化成员,最后调用自己的构造函数 先调用自己的析构函数,再析构成员,最后调用父类...
  • C++虚函数

    千次阅读 多人点赞 2019-09-03 14:13:44
    C++虚函数纯虚函数虚函数 纯虚函数 纯虚函数 virtual void fun() = 0; 纯虚函数的出现时为了应对一些特殊的情况,即基类无法实现某些抽线行为,交由继承类去实现。 =0告诉编译器此函数为纯虚函数,由此可以引出...
  • 可以,虚函数底层实现原理(但是最好不要在构造和析构函数中调用) 可以,但是没有动态绑定的效果,父类构造函数中调用的仍然是父类版本的函数,子类中调用的仍然是子类版本的函数。 effictive c++第九条,绝不在构造...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,507
精华内容 25,002
关键字:

虚函数调用顺序