tags:

views:

233

answers:

6

I was asked by my friend a virtual function problem.

If a child object call a virtual function, under what condition, this virtual function is actually executed the one in the father's implementation?

A: 

If the child class' destructor has already been called, then the object is now of the parent's type, so the parent's virtual functions will be called.

Ned Batchelder
The C++ standard certainly says no such thing.
anon
Hi Ned,Could you give some exmaples?Hi NeilWhat's your answer to this question?
skydoor
I can't quote the standard, but I didn't make it up: http://c2.com/cgi/wiki?PureVirtualFunctionCalled and http://msdn.microsoft.com/en-us/magazine/cc163897.aspx
Ned Batchelder
You can't quote the standard because the standard says nothing about a vtable.
GMan
Forgive my terminology. I've fixed the answer.
Ned Batchelder
If the derived clas destructor has been called, you no longer have a derived class instance - the object you are talking about is now a base instance. Its functions will then be called non-virtually.
anon
Precisely: A function declared virtual in the base class is invoked, even though the object was declared as a derived instance. I'm glad we agree on this being the answer to the OP's question.
Ned Batchelder
Saying that it will be called "non-virtually" is not really an explanation. A non-virtual call is a compiler optimization, which is only generally possible when the call is made *directly* from the constructor/destructor. In more complicated cases, like an *indirect* call through an intermediate function (constructor calls foo and foo calls a virtual function) or a call through a pointer of a pointer-to-member type, making a "non-virtual" call is generally impossible. Yet, the language requires that such calls be dispatched correctly (i.e. to the current type of the object). (continued)
AndreyT
The compilers use simple "tricks" to achieve this, but the notion of "non-virtual" call plays no significant role here. These "tricks" make sure that all calls go where they have to go, regardless of whether they are "virtual" or "non-virtual". For this reason, the concept of "non-virtual call" is completely irrelevant here. It is a completely optional optimization, not something critical for the things to work correctly.
AndreyT
Every time someone says that virtual calls from the constructor/destructor work the way they work because they are "non-virtual" or "static", they simply fail the realize the full extent of the issue.
AndreyT
+3  A: 

I think you need to post some code to clarify what you are asking, but (with the exception of the destructor) the base class function will not be called unless the child calls itt explicitly from its own function. For example, in:

struct A {
    virtual ~A() {}
    virtual void f() {}
};

struct B : public A {
    virtual void f() {}
};

int main() {
    A * a = new B;
    a->f();
    delete a;
}

only B's virtual function f() is called. If you wanted A::f() to be called you would have to do so explicitly:

struct B : public A {
    virtual f() { 
       A::f();    // explicit call
    }
};

Oh, and of course in the case when B does not declare the function - in this case A::f() will always be called.

anon
I have no code yet. I think the question is like thisclass B{ virtual f() {cout<<"in Base!"<<endl;}}class D{ virtual f() { cout<<"in Derived"<<endl;}}there is two object d and b, when d calls the function d.f(), it shows "in Base!".Under what situation, this would happen?
skydoor
Virtual calls only happen via pointers and references, not via object instances.
anon
well, thanks for your comments. However I think there is some misunderstanding. I think the question is why the derived object called the virtual function, but the function in the base class is executed. It is not about how to call the function in base class.
skydoor
Sorry, you seem to be muddying the waters even more. As AndreyT says, you really to clarify exactly what you are asking about (or ask your "friend" to). and when you do, plase make the clarification by editing your original question, not via a comment.
anon
A: 

If this invocation is whithin a constructor, the dispatch will be static. Read this for more info: http://cplusplus.co.il/2009/09/30/virtual-dispatching-within-a-constructor-or-a-destructor/

Here's the example from the article I've linked to:

struct A {
    A () { f(); }
    virtual void f () { }
};

struct B : A {
        B () :member(0) {}
        void f () { std::cout << member; }
    private:
        int member;
};

int main () {
    B b;
    return 0;
}

The invoked f is A::f, despite the fact that it is virtual and called by an object of type B who has its own implementation.

rmn
Both this and Ned's answer are to do with static dispatch. I think the OP isa sking about virtual dispatch - his comment to my answer seems to indicate that.
anon
It is incorrect to say that the dispath is *static*. The dispatch is not static. From the language point of view for virtual functions the dispatch is always *dynamic*, but when the call is made from constructor the dynamic type of the object is the class whose constructor is currently working. I don't know where this strange idea of a *static dispatch* comes from. The compiler can optimize it to be static, but that's just a compiler specific optiization.
AndreyT
So if I say (using my example code) A a; a.f(); you say this is dynamic dispatch?
anon
Yes, Neil, it can be. That's the point. In C++ there's no such thing as "dynamic" or "static" dispatch. What the language says is as follows: when you call a virtual function, the function that is actually called is determined by the dynamic type of the object (key notion here). In your example with `a.f()` the dynamic type of the object is `A`, so the `A::f` is called. How the compiler makes sure that `A::f` is called it its internal business. Maybe it uses the "dynamic dispatch" (will work). Maybe it optimizes it to "static dispatch" (OK too). Maybe if does something else. Who knows...
AndreyT
+2  A: 

It is impossible to understand what exactly is implied by the question in ts current form.

If taken literally, the question has an obvious and immediate answer: the parent's version is called if the parent's implementation is the final overrider for the function in question, i.e. if the child provides no implementation of its own

class parent {
public:
  virtual void foo() { /* whatever */ }
};

class child : parent {
public:
  void bar() {
    foo(); /* call the parent's implementation, as requested */
  }
};

So, here's your answer.

Of course, it's intuitively obvious to anyone that most likely that's not what was implied by the question. Quite likely it was implied that the child class overrides the parent's function. In that case there's another obvious answer: the parent's version will be called if the child uses a fully-qualified name of the function

class parent {
public:
  virtual void foo() { /* whatever */ }
};

class child : parent {
public:
  virtual void foo() { /* whatever */ }
  void bar() {
    parent::foo(); /* call the parent's implementation, as requested */
  }
};

Another possible answer is that the object for which the function is called actually has parent type (since nowhere in the question it says that the child should call it for this object)

class parent {
public:
  virtual void foo() { /* whatever */ }
};

class child : parent {
public:
  virtual void foo() { /* whatever */ }
  void bar() {
    parent p;
    p.foo(); /* call the parent's implementation, as requested */
  }
};

Again, it feels intuitively that this is not what the question is about. Most likely, the question was intended to be about virtual calls made from constructors and destructors

class parent {
public:
  parent() { 
    foo(); /* always calls `parent::foo` */
  }
  virtual void foo() { /* whatever */ }
};

class child : parent {
public:
  child() : parent() /* `parent::parent` will call `parent::foo` */
    {}
  virtual void foo() { /* whatever */ }
};

However, for that the question is incorrectly worded. In the last example at the moment of the call, the child object does not exist yet. The memory for it is already allocated but its lifetime hasn't started yet. It is incorrect to say that the call to the virtual function is performed by the child object. It is performed by the parent object.

So, to resume the above: the question is so ambiguously and vaguely worded, that it doesn't make any sense in its current form.

AndreyT
+1  A: 
  • When the base class's scope is explicitly used ( Base::f(); )
  • Inside the base class's constructor (because the derived object's constructor hasn't been entered yet)
  • Inside the base class's destructor (because the derived object has already been destructed)
Shmoopty
A: 

Answer has already been provided, this may happen during construction:

It might also be a funny source of run-time errors, so pay special attention to constructors & pure virtual methods calls in the base class ;)

http://support.microsoft.com/kb/125749

   class A;

   void fcn( A* );

   class A
   {
   public:
       virtual void f() = 0;
       A() { fcn( this ); }
   };

   class B : A
   {
       void f() { }
   };

   void fcn( A* p )
   {
       p->f();
   }

   // The declaration below invokes class B's constructor, which
   // first calls class A's constructor, which calls fcn. Then
   // fcn calls A::f, which is a pure virtual function, and
   // this causes the run-time error. B has not been constructed
   // at this point, so the B::f cannot be called. You would not
   // want it to be called because it could depend on something
   // in B that has not been initialized yet.

   B b;

   void main()
   {
   }