精华内容
下载资源
问答
  •   C++构造函数可以调用虚函数吗?这个问题比较奇怪,为什么要在构造函数调用虚函数,这更多的应该是用在一些框架里面,构造函数里调用虚函数是可以的,没问题。例如下面的代码: #include <iostream> using...

      C++构造函数可以调用虚函数吗?这个问题比较奇怪,为什么要在构造函数调用虚函数,这更多的应该是用在一些框架里面,构造函数里调用虚函数是可以的,没问题。例如下面的代码:

    #include <iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A() 
        {
            fun();
        }
    
        ~A() {}
    
        virtual void fun()
        {
            cout << "A  fun" << endl;
        }
    };
    
    class B :public A
    {
    public:
        B()
        {
            fun();
        }
    
        ~B() {}
    
        void fun()
        {
            cout << "B  fun" << endl;
        }
    };
    
    int main()
    {
        A* p = new B();
    
        cout << "-----------------------" << endl;
    
        p->fun();
    
        return 0;
    }
    

      输出结果
    在这里插入图片描述
      可以看出,在类里面调用虚函数,始终是调用本身的,不管有没有加virtual关键字。

      这是什么原因呢,看侯捷的书可以找到答案
    在这里插入图片描述
      就是说在new B时,由于是派生于A,先构造A, 此时的虚表指针去A的虚表找虚函数,当构造B时就去B的虚表找虚函数,这是伪多态,不过p->fun()是多态。

    展开全文
  • 可以;通过(程序可以正常运行);不通过(不是我们想要的结果)。原文链接:http://www.cnblogs.com/hellogiser/p/whether-constructor-can-call-virtual-function.html#include <iostream>using namespace std;...

    问题回答:
    可以;通过(程序可以正常运行);不通过(不是我们想要的结果)。


    原文链接:http://www.cnblogs.com/hellogiser/p/whether-constructor-can-call-virtual-function.html

    #include <iostream>
    
    using namespace std;
    
    class Base
    {
    public:
        Base()
        {
            cout << "Base::Base()" << endl;
            Foo();
        }
    
        virtual void Foo()
        {
            cout << "Base::Foo " << 1 << std::endl;
        }
    };
    
    class Derived : public Base
    {
    public:
        Derived() : Base(), m_pData(new int(2)) { 
            cout << "Derived::Derived()" << endl; 
            Foo();
        }
        ~Derived()
        {
            delete m_pData;
        }
    
        virtual void Foo()
        {
            cout << "Derived::Foo " << *m_pData << std::endl;
        }
    private:
        int *m_pData;
    };
    
    int main()
    {
        Base *p = new Derived();
        delete p;
        return 0;
    }

    如上程序的运行结果为:
    这里写图片描述

    基类部分在派生类部分之前被构造,当基类构造函数执行时派生类中的数据成员还没被初始化。如果基类构造函数中的虚函数调用被解析成调用派生类的虚函数,而派生类的虚函数中又访问到未初始化的派生类数据,将导致程序出现一些未定义行为和bug。

    构造函数直接调用 纯虚函数(pure virtual function),编译会报错: unresolved externals

    构造函数间接调用 纯虚函数(pure virtual function)(即:构造函数调用普通函数,但是普通函数又调用了纯虚函数),编译阶段不会报错,可以生成可执行文件,但是运行会出错,因为纯虚函数没有定义。

    展开全文
  • 这个问题来自于《Effective C++》条款9:永远不要在构造函数或析构函数中调用虚函数 。 简要结论: 1. 从语法上讲,调用完全没有问题。 2. 但是从效果上看,往往不能达到需要的目的。 Effective 的解释是: 派生...

    不能。这个问题来自于《Effective C++》条款9:永远不要在构造函数或析构函数中调用虚函数 。

    简要结论: 
    1. 从语法上讲,调用完全没有问题。 
    2. 但是从效果上看,往往不能达到需要的目的。 
    Effective 的解释是: 
    派生类对象构造期间进入基类的构造函数时,对象类型变成了基类类型,而不是派生类类型。 
    同样,进入基类析构函数时,对象也是基类类型。
     

    在基类的构造过程中,虚函数调用从不会被传递到派生类中。代之的是,派生类对象表现出来的行为好象其本身就是基类型。不规范地说,在基类的构造过程中,虚函数并没有被"构造"。

      简单的说就是,在子类对象的基类子对象构造期间,调用的虚函数的版本是基类的而不是子类的。

      对上面这种看上去有点违背直觉的行为可以用一个理由来解释-因 为基类构造器是在派生类之前执行的,所以在基类构造器运行的时候派生类的数据成员还没有被初始化。如果在基类的构造过程中对虚函数的调用传递到了派生类, 派生类对象当然可以参照引用局部的数据成员,但是这些数据成员其时尚未被初始化。这将会导致无休止的未定义行为和彻夜的代码调试。沿类层次往下调用尚未初始化的对象的某些部分本来就是危险的,所以C++干脆不让你这样做。

      在对象的析构期间,存在与上面同样的逻辑。一旦一个派生类的析构器运行起来,该对象的派生类数据成员就被假设为是未定义的值,这样以来,C++就把它们当做是不存在一样。一旦进入到基类的析构器中,该对象即变为一个基类对象,C++中各个部分(虚函数,dynamic_cast运算符等等)都这样处理。

    展开全文
  • C++中构造函数调用虚函数吗? 分类: C++ Win322011-08-31 00:07 4481人阅读 评论(8) 收藏 举报 c++class编译器c汇编java  环境:XPSP3 VS2005  今天黑总给应聘者出了一个在C++的构造函数中...

    C++中构造函数能调用虚函数吗?

    分类: C++ Win32 4481人阅读 评论(8) 收藏 举报

          环境:XPSP3 VS2005

            今天黑总给应聘者出了一个在C++的构造函数中调用虚函数的问题,具体的题目要比标题复杂,大体情况可以看如下的代码:

    1. class Base  
    2. {  
    3. public:  
    4.     Base()  
    5.     {  
    6.         Fuction();  
    7.     }  
    8.   
    9.     virtual void Fuction()  
    10.     {  
    11.         cout << "Base::Fuction" << endl;  
    12.     }  
    13. };  
    14.   
    15. class A : public Base  
    16. {  
    17. public:  
    18.     A()  
    19.     {  
    20.         Fuction();  
    21.     }  
    22.   
    23.     virtual void Fuction()  
    24.     {  
    25.         cout << "A::Fuction" << endl;  
    26.     }  
    27. };  
    28.   
    29. // 这样定义一个A的对象,会输出什么?  
    30. A a;  

            首先回答标题的问题,调用当然是没有问题的,但是获得的是你想要的结果吗?或者说你想要什么样的结果?

            有人说会输出:

    [html] view plaincopy
    1. A::Fuction  
    2. A::Fuction  

            如果是这样,首先我们回顾下C++对象模型里面的构造顺序,在构造一个子类对象的时候,首先会构造它的基类,如果有多层继承关系,实际上会从最顶层的基类逐层往下构造(虚继承、多重继承这里不讨论),如果是按照上面的情形进行输出的话,那就是说在构造Base的时候,也就是在Base的构造函数中调用Fuction的时候,调用了子类A的Fuction,而实际上A还没有开始构造,这样函数的行为就是完全不可预测的,因此显然不是这样,实际的输出结果是:

    [html] view plaincopy
    1. Base::Fuction  
    2. A::Fuction  

            据说在JAVA中是上一种输出(感觉有点匪夷所思)。

            我们来单步看一下到底发生了什么?在A的构造函数里面首先会去调用Base的构造函数,Base的构造函数如下:

    class Base
    {
    public:
     Base()
    00411600  push        ebp  
    00411601  mov         ebp,esp 
    00411603  sub         esp,0CCh 
    00411609  push        ebx  
    0041160A  push        esi  
    0041160B  push        edi  
    0041160C  push        ecx  
    0041160D  lea         edi,[ebp-0CCh] 
    00411613  mov         ecx,33h 
    00411618  mov         eax,0CCCCCCCCh 
    0041161D  rep stos    dword ptr es:[edi] 
    0041161F  pop         ecx  
    00411620  mov         dword ptr [ebp-8],ecx 
    00411623  mov         eax,dword ptr [this] 
    00411626  mov         dword ptr [eax],offset Base::`vftable' (41770Ch)
     {
      Fuction();
    0041162C  mov         ecx,dword ptr [this] 
    0041162F  call        Base::Fuction (4111A9h)

     }
    00411634  mov         eax,dword ptr [this] 
    00411637  pop         edi  
    00411638  pop         esi  
    00411639  pop         ebx  
    0041163A  add         esp,0CCh 
    00411640  cmp         ebp,esp 
    00411642  call        @ILT+460(__RTC_CheckEsp) (4111D1h) 
    00411647  mov         esp,ebp 
    00411649  pop         ebp  
    0041164A  ret

            从单步跟踪来看,注意黑色加粗的那部分汇编代码,ecx中存放的是对象的地址(0x0012ff60,我的机器上的情况看下图,有图有真相),首先是设置vtable的地址到对象的前四个字节(不同的编译器可能不同),然后就直接调用了Base::Fuction函数,并没有走虚机制,而我们此时看虚表中的状态,虚表已经填充的是0x4111a9,注意虚表的地址0x0041770c,而此时对象地址0x0012FF60前四个字节存放的正是0x0041770c。

            继续跟踪,流程又回到A的构造函数中,再次注意加粗部分的代码,从基类Base的构造函数返回后,在A的构造函数中,重设了虚表指针,现在的虚表指针是(0x417700h),同样调用Fuction的时候直接调用了A::Fuction函数,并没有使用虚机制,而且此时虚表0x417700h指向的位置存放的0x41110e正是A::Fuction的地址。

    class A : public Base
    {
    public:
     A()
    00411590  push        ebp  
    00411591  mov         ebp,esp 
    00411593  sub         esp,0CCh 
    00411599  push        ebx  
    0041159A  push        esi  
    0041159B  push        edi  
    0041159C  push        ecx  
    0041159D  lea         edi,[ebp-0CCh] 
    004115A3  mov         ecx,33h 
    004115A8  mov         eax,0CCCCCCCCh 
    004115AD  rep stos    dword ptr es:[edi] 
    004115AF  pop         ecx  
    004115B0  mov         dword ptr [ebp-8],ecx 
    004115B3  mov         ecx,dword ptr [this] 
    004115B6  call        Base::Base (411140h) 
    004115BB  mov         eax,dword ptr [this] 
    004115BE  mov         dword ptr [eax],offset A::`vftable' (417700h)
     {
      Fuction();
    004115C4  mov         ecx,dword ptr [this] 
    004115C7  call        A::Fuction (41110Eh)
     }
    004115CC  mov         eax,dword ptr [this] 
    004115CF  pop         edi  
    004115D0  pop         esi  
    004115D1  pop         ebx  
    004115D2  add         esp,0CCh 
    004115D8  cmp         ebp,esp 
    004115DA  call        @ILT+460(__RTC_CheckEsp) (4111D1h) 
    004115DF  mov         esp,ebp 
    004115E1  pop         ebp  
    004115E2  ret


            其实事情就是这么简单。

     

    更多0
    上一篇:CMarkup成员方法简介下一篇:C语言编译全过程
    2
    1
    相关主题推荐
    c++ 编译器 对象 继承 微软
    相关博文推荐
    乱水bnuoj
    C++继承的三种方式
    OpenGL进阶(十八) - 从零搭建基...
    SQLite编程相关
    【Leetcode】Word Ladder
    Makefile:2: *** 遗漏分隔...
    linux下的C++编程
    C++之字节对齐与结构体大小(转)
    查看评论
    8楼 shifters 2011-08-31 20:36发表 [回复]
    2楼正解,c++中已有规定
    7楼 爱技术的华仔 2011-08-31 19:56发表 [回复]
    其实只要将C++对象的构造顺序和机制想通就能推断出来了
    6楼 谭海燕 2011-08-31 12:47发表 [回复]
    你的分析虚函数表的指针是什么时候出来的。
    5楼 androidrobot1 2011-08-31 11:41发表 [回复]
    汇编不懂啊,感觉因该是第二中结果
    4楼 wangjiabin2007 2011-08-31 11:11发表 [回复]
    不错
    3楼 iaccepted 2011-08-31 09:50发表 [回复]
    表示直接输出正确,基础学的还是不错的,呵呵!
    2楼 dbzhang800 2011-08-31 09:45发表 [回复]
    恩,C++标准2.7对此有明文规定

    Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2).
    When a virtual function is called directly or indirectly from a constructor (including the mem-initializer or
    brace-or-equal-initializer for a non-static data member) or from a destructor, and the object to which the
    call applies is the object under construction or destruction, the function called is the one defined in the
    constructor or destructor’s own class or in one of its bases, but not a function overriding it in a class derived
    from the constructor or destructor’s class, or overriding it in one of the other base classes of the most derived
    object (1.8). If the virtual function call uses an explicit class member access (5.2.5) and the object-expression
    refers to the object under construction or destruction but its type is neither the constructor or destructor’s
    own class or one of its bases, the result of the call is undefined.
    展开全文
  • 可以虚函数底层实现原理(但是最好不要在构造和析构函数中调用) 可以,但是没有动态绑定的效果,父类构造函数调用的仍然是父类版本的函数,子类中调用的仍然是子类版本的函数。 effictive c++第九条,绝不在构造...
  • 构造函数调用虚函数

    千次阅读 2013-03-22 14:31:05
    构造函数可以调用虚函数吗?语法上通过吗?语义上可以通过吗? C++是不允许虚构造函数。 测试代码: class A { public: virtual A() { cout; } private: int x; }; int main() { A
  • 环境:XPSP3 VS2005 ... 今天黑总给应聘者出了一个在C++的构造函数调用虚函数的问题,具体的题目要比标题复杂,大体情况可以看如下的代码: [cpp] view plain copy class Bas
  • C++ 构造函数中能调用虚函数吗

    千次阅读 2014-04-16 14:45:44
    答案是可以的,只是起不到虚函数的作用,举例如下:   #include using namespace std; class Base  {  public:   Base()   {   Fuction();   }   virtual void Fuction()   {   cout...
  • 这个问题来自于《Effective C++》条款9:永远不要在构造函数或析构函数中调用虚函数 。 简要结论: 1. 从语法上讲,调用完全没有问题。 2. 但是从效果上看,往往不能达到需要的目的。 Effective 的解释是: ...
  • 这个问题来自于《Effective C++》条款9:永远不要在构造函数或析构函数中调用虚函数 。 简要结论:  1. 从语法上讲,调用完全没有问题。  2. 但是从效果上看,往往不能达到需要的目的。  Effective 的解释是:...
  • 面试管问你,构造函数可以虚函数吗?如果你知道,你可以勇敢的反问,能不要问这么简单的问题吗?如果你不知道,请记住这个答案-----不能! 以下是copy一个CSDN大佬写的博客,刚好我是后者! 从存储空间角度 ...
  • 可以,编译期就不会通过。 虚函数是通过虚表指针和虚函数...如果存在虚构造函数,试问,一个对象还没构造出来,如何调用虚函数? 转载于:https://www.cnblogs.com/helloweworld/archive/2013/06/14/3136707.html...
  • 1.构造函数必不可以是虚函数 2.析构函数可以虚函数,...4.析构函数不仅可以是虚函数,有时还必须是虚函数,因为基类相对于子类,基类的析构函数若不是虚函数,子类析构函数就会即调用自己的析构又调用基类的。 ...
  • 那么问题又来了,析构函数可以虚函数吗? 答:可以 把基类析构函数定义为虚函数,在调用析构函数时,会根据指向的对象类型到它的虚函数表中找到对应的虚函数,此时找到的是派生类的析构函数,因此调用该析构函数;...
  • 构造函数:只有当调用构造函数,这个对象才能产生,如果把构造函数写成虚函数,这时候我们的对象就没有办法生成。更别说用对象去调用了。所以构造函数不能成为虚函数。 静态成员函数:静态成员函数是属于类的,...
  • 当存在虚函数时,每个对象都有一个指向虚函数表的指针vptr,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。 如果构造函数虚函数,那么调用构造函数就需要先找vptr,但此时vptr还没初始化,发生冲突...
  • 三、构造函数和析构函数可以虚函数吗?为什么? 1、构造函数 从存储空间角度,虚函数对应一个指向vtable虚函数表的指针,这大家都知道,可是这个指向vtable的指针其实是存储在对象的内存空间的。问题出来了,...
  • 文章目录1 构造函数不能是虚函数,析构函数可以是虚函数2 构造析构函数调用虚函数不会发生多态3 小结 1 构造函数不能是虚函数,析构函数可以是虚函数 构造函数不可能成为虚函数 在构造函数执行结束后,虚函数表指针...
  • 分析C++方式构造函数调用虚函数的问题

    万次阅读 热门讨论 2011-04-17 00:00:00
    构造函数可以运行虚函数吗?我们先不讨论实际项目中是否有这个必要(至少我还没碰到过,也许即便碰到了也有其他的解决办法。),单就构造函数调用虚拟函数的情况来做些分析。在JAVA中,如果在构造函数调用虚拟...
  • 虚函数对应一个vtable,这大家都知道,可是这个...问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。 2,从使用
  • 构造函数中,虚拟机制尚未发生作用,因为此时overriding尚未发生。万丈高楼平地起,总得先打地基吧?对象的建立也是这样——先把基类构造完毕,然后在此基础上构造派生类。   看看这个例子: #include&lt;...
  • 抽象类中可以构造函数吗

    千次阅读 2017-06-11 16:48:25
    而派生类在实例化调用构造函数的时候会先调用基类中的构造函数,所以抽象类的构造函数也是可以调用的,所以抽象类中可以构造函数。抽象类的析构函数最后是析构函数。 比如上面的程序在执行的时候就会执行...

空空如也

空空如也

1 2 3 4 5
收藏数 85
精华内容 34
关键字:

构造函数可以调用虚函数吗