Call virtual functions during construction

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • evenstar
    New Member
    • Jul 2009
    • 30

    Call virtual functions during construction

    hello every body,
    I know I shouldn't call virtual functions during construction or destruction.
    Code:
    #include <iostream>
    using namespace std;
    
    class   BaseWithPureFunction 
    { 
    public: 
        
    
        virtual   void   PureFunc()   =   0; 
        void   CallPureFunc()   
        { 
            PureFunc();     
        } 
    
        BaseWithPureFunction() ;
    }; 
    
       BaseWithPureFunction::BaseWithPureFunction()   
    { 
       /* 
        Call pure-virtual via CallPureFun. 
        Cause r6025 error.I have no question here.
       */
        CallPureFunc();   
            
    } 
    
    void BaseWithPureFunction::PureFunc()
    {
       cout<<"Pure!"<<endl;
    }
    
    
    
    
    class   BaseEx:public   BaseWithPureFunction 
    { 
    public: 
        virtual   void   PureFunc() 
        { 
            printf( "BaseEx::PureFunc()\r\n "); 
        } 
    }; 
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
       BaseEx ex;
        
       return 0;
    }

    If replace the BaseWithPureFun ction function :
    Code:
       BaseWithPureFunction::BaseWithPureFunction()   
    { 
        /*
          Call pure-virtual directly.
          Running well.I puzzled.
       
        */
              PureFunc();   
           
    }
    I puzzled why call pure-virtual directly, the programe won't cause error.I found some explanation in "Effective C++ Item 9".But I still think that this explanation is not detailed enough.
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    Think about this.

    When you have a virtual function, you instruct the compiler that when there is a choice between calling the base function or the derived function, the derived function is to be called.

    Therefore, if you have:

    class Base
    {
    public:
    virtual void Method();
    };

    Comment

    • weaknessforcats
      Recognized Expert Expert
      • Mar 2007
      • 9214

      #3
      Think about this.

      When you have a virtual function, you instruct the compiler that when there is a choice between calling the base function or the derived function, the derived function is to be called.

      However, during construction there is no guarantee that the derived object has been created yet. Therefore, when the base portion of the object is created, the call goes to the base virtual function.

      The reverse appplies during destruction. Since the object is destroyed in reverse order, calling a virtual function in a destirctor results in a call to the local function since the derived portion of the object may have already been destroyed.

      The net result is the the virtual keyword is ignored inside constructors and destructors.

      Comment

      • evenstar
        New Member
        • Jul 2009
        • 30

        #4
        Thanks for your help.
        I know during construction the base virtual function will be called.So What you said is not that I want to know.
        I want to find the answer :why this part of code can go well:
        Code:
        BaseWithPureFunction::BaseWithPureFunction()    
        {  
            /* 
              Call pure-virtual directly. 
              Running well.I puzzled. 
            */ 
                  PureFunc();    
          }
        In my opnion,it will cause r6025 error,too.But.. .

        Comment

        • weaknessforcats
          Recognized Expert Expert
          • Mar 2007
          • 9214

          #5
          You are creating a BaseEx object.

          That object inherits BaseWithPureFun ction::PureFunc .

          You call BaseWithPureFun ction::PureFunc from a BaseEx member function.

          So what's the problem?

          Remember, a pure virtual function cannot be called by an object of its class but it's OK to call it from some other object.

          To enforce not calling BaseWithPureFun ction::PureFunc using a BaseWithPureFun ction object, the compiler will not allow you to create a BaseWithPureFun ction object.

          But can create a BaseEx object and call BaseWithPureFun ction::PureFunc usign the BaseEx object.

          Comment

          • evenstar
            New Member
            • Jul 2009
            • 30

            #6
            The fact was that I called the function of PureFunc directly and by the CallPureFunc function indirectly had different results.One is running well,but the other cause a error.Tow ways both invoked PureFunc function by the same types of 'this' pointer that pointed to base type,but they had different results.
            Is there any ambiguous?

            Comment

            • weaknessforcats
              Recognized Expert Expert
              • Mar 2007
              • 9214

              #7
              You should not be using CallWithPureFun c().

              That function is a member function of the class BaseWithPureFun ction and wghen you code:

              Code:
              BaseWithPureFunction  obj;
              obj.CallWithPurFunc();
              you a compile error that you can't create an object of an abstract class because you can't use a BaseWithPureFun ction object to call a pure virtual function in the BaseWithPureFun ction class.

              However, you can code:

              Code:
              BaseEx  obj;
              obj.BaseWithPureFunction::PureFunc();
              to call PureFunc using a BaseEx object.

              You could also:

              Code:
              BaseEx obj1;
              obj1.PureFunc();
              but no it's not cleas whether BaseEx::PureFun c() or BaseWithPureFun ction::PureFunc () is being called unless you look in the code and see. Therefore, this is the preferred code:

              Code:
              BaseEx  obj;
              obj.BaseWithPureFunction::PureFunc();

              Comment

              • evenstar
                New Member
                • Jul 2009
                • 30

                #8
                Thanks again for your help.
                At the point the base class constructor is invoked from the derived class constructor, the object ex is not yet of type BaseEx.The base class constructor initializes the BaseWithPureFun ction subobject within ex to behave like a BaseWithPureFun ction object. Therefore, when the virtual PureFunc is called in base class constructor, it binds to BaseWithPureFun ction::PureFunc .According to holy,it should lead a error.But when I running this code it goes well.
                So I altered BaseWithPureFun ction constructor I made it invoke the BaseWithPureFun ction::CallPure Func.Then the virtual function PureFunc will be invoked by CallPureFunc.
                When I running the code I have altered,a r6025 error appeared.
                Two kinds of codes are both equal to using a BaseWithPureFun ction object-a base object- to call a pure virtual function .
                So I begin to think why two kinds of codes will lead differernt results.

                Comment

                • weaknessforcats
                  Recognized Expert Expert
                  • Mar 2007
                  • 9214

                  #9
                  The virtual keyword is suspended in constrcutors and destructors. It's like its not there.

                  Re-read my post #3.

                  Comment

                  • evenstar
                    New Member
                    • Jul 2009
                    • 30

                    #10
                    ...My question has been answered?May be my expression is unclear.
                    Please look at the question again,and make sure what I want to know.Thank you.
                    Code:
                    #include <iostream>
                    using namespace std;
                    
                    struct BaseWithPureFunction
                    { 
                        virtual void PureFunc() = 0;
                    
                        void CallPureFunc()
                        {
                            PureFunc();
                        }
                    
                        BaseWithPureFunction();
                    };
                    
                    BaseWithPureFunction::BaseWithPureFunction()
                    {
                        PureFunc();//running well
                        CallPureFunc(); //error.
                      //Is there any difference between PureFunc and CallPureFunc.
                    }
                    
                    void BaseWithPureFunction::PureFunc()
                    {
                        cout << 3 << endl;
                    }
                    
                    struct BaseEx : BaseWithPureFunction
                    { 
                        virtual void PureFunc()
                        {
                            cout << "BaseEx::PureFunc()" << endl;
                        }
                    };
                    
                    int main()
                    {
                        BaseEx ex;
                    
                        return 0;
                    }

                    Comment

                    • weaknessforcats
                      Recognized Expert Expert
                      • Mar 2007
                      • 9214

                      #11
                      This is your code:
                      Code:
                      struct BaseWithPureFunction 
                      {  
                          virtual void PureFunc() = 0; 
                        
                          void CallPureFunc() 
                          { 
                              PureFunc(); 
                          } 
                        
                          BaseWithPureFunction(); 
                      }; 
                        
                      BaseWithPureFunction::BaseWithPureFunction() 
                      { 
                          PureFunc();//running well 
                          CallPureFunc(); //error. 
                        //Is there any difference between PureFunc and CallPureFunc. 
                      }
                      When you call PureFunc(), you really are calling
                      BaseWithPureFun ction::PureFunc () because the virtual keyword is suspended inside a constructor.

                      However, when you are inside CallPureFunc() you may not be inside a constructor so when you call PureFunc() the VTBL is accessed and you bomb with a run-time error about calling a pure virtual function. All you need to do is tell the compiler to call the function without using the VTBL. That is, you need to specify the complete function name:

                      Code:
                      struct BaseWithPureFunction 
                      {  
                          virtual void PureFunc() = 0; 
                        
                          void CallPureFunc() 
                          { 
                      		BaseWithPureFunction::PureFunc(); 
                          } 
                        
                          BaseWithPureFunction(); 
                      };
                      Now you are calling the function by name directly without using the VTBL. Now the program runs correctly.

                      Comment

                      • evenstar
                        New Member
                        • Jul 2009
                        • 30

                        #12
                        I finally understand.
                        Thank you very much indeed .

                        Comment

                        Working...