virtual function call from base class
Asked Answered
N

9

66

Say we have:


class Base
{   
    virtual void f() {g();};
    virtual void g(){//Do some Base related code;}
};

class Derived : public Base
{   
    virtual void f(){Base::f();} override;
    virtual void g(){/*Do some Derived related code*/} override;
};

int main()
{
    Base *pBase = new Derived;
    pBase->f();
    return 0;  
}

Which g() will be called from Base::f()? Base::g() or Derived::g()?

Thanks...

Nebula answered 29/12, 2008 at 9:48 Comment(2)
please use the button with the 1/0'ers on it to format your code nicely. (i edited it, but the OP rollback'ed it. so i won't edit it a second time myself)Oxalate
Please mind you presented an example with a memory leak. You have a forgotten delete in main.Formenti
O
64

The g of the derived class will be called. If you want to call the function in the base, call

Base::g();

instead. If you want to call the derived, but still want to have the base version be called, arrange that the derived version of g calls the base version in its first statement:

virtual void g() {
    Base::g();
    // some work related to derived
}

The fact that a function from the base can call a virtual method and control is transferred into the derived class is used in the template method design pattern. For C++, it's better known as Non-Virtual-Interface. It's widely used also in the C++ standard library (C++ stream buffers for example have functions pub... that call virtual functions that do the real work. For example pubseekoff calls the protected seekoff). I wrote an example of that in this answer: How do you validate an object’s internal state?

Oxalate answered 29/12, 2008 at 9:52 Comment(2)
Interesting, I found an issue with GCC 4.8.2: Base *pBase = (Base*)(void*)new Derived; tried to call my pure virtual functions from my Base class.Thankyou
if call in constructor, the g() base class will be called, because the derived class is not constructed now.Lanceted
A
19

It is the Derived::g, unless you call g in Base's constructor. Because Base constructor is called before Derived object is constructed, Derived::g can not logically be called cause it might manipulate variables that has not been constructed yet, so Base::g will be called.

Arenaceous answered 19/9, 2013 at 4:18 Comment(1)
Good clarification about what happens in a constructor.<br/>Scott Meyers says linkLeoleod
H
7

pBase is a pointer to a base. pBase = new Derived returns a pointer to a Derived - Derived is-a Base.

So pBase = new Derived is valid.

pBase references a Base, so it will look at Derived as if it were a Base.

pBase->f() will call Derive::f();

Then we see in the code that:

Derive::f() --> Base::f() --> g() - but which g??

Well, it calls Derive::g() because that is the g that pBase "points" to.

Answer: Derive::g()

Hydrokinetics answered 28/5, 2010 at 20:56 Comment(0)
R
2

Well... I'm not sure this should compile. The following,

Base *pBase = new Derived;

is invalid unless you have:

Class Derived : public Base

Is it want you meant? If this is want you meant,

pBase->f();

Then the call stack would go like this:

Derived::f()
    Base::f()
        Derived::g()
Rountree answered 29/12, 2008 at 19:20 Comment(0)
L
1

As you have defined g() to be virtual, the most derived g() will be looked up in the vtable of the class and called regardless of the type your code is currently accessing it.

See the C++ FAQ on virtual functions.

Lashing answered 29/12, 2008 at 10:15 Comment(0)
B
1

Actually running your code shows that Derived::g() is called.

Balbur answered 30/12, 2008 at 7:30 Comment(0)
L
1

g() of derived class will be called if in member function.

g() of base class will be called if in constructor or destructor.

https://www.geeksforgeeks.org/calling-virtual-methods-in-constructordestructor-in-cpp/

// calling virtual methods in constructor/destructor
#include<iostream> 
using namespace std; 

class dog 
{ 
public: 
    dog()  
    { 
        cout<< "Constructor called" <<endl; 
        bark() ; 
    } 

    ~dog() 
    {  
        bark();  
    } 

    virtual void bark() 
    {  
        cout<< "Virtual method called" <<endl;  
    } 

    void seeCat()  
    {  
        bark();  
    } 
}; 

class Yellowdog : public dog 
{ 
public: 
        Yellowdog()  
        { 
            cout<< "Derived class Constructor called" <<endl;  
        } 
        void bark()  
        { 
            cout<< "Derived class Virtual method called" <<endl;  
        } 
}; 

int main() 
{ 
    Yellowdog d; 
    d.seeCat(); 
} 

output:

Constructor called
Virtual method called
Derived class Constructor called
Derived class Virtual method called
Virtual method called
Lanceted answered 3/5, 2020 at 9:58 Comment(0)
H
0

I think you trying to invent Template Method Pattern

Humorist answered 29/12, 2008 at 10:6 Comment(0)
R
0

The derived class' method will be called.

This is because of the inclusion of vtables within classes that have virtual functions and classes that override those functions. (This is also known as dynamic dispatch.) Here's what's really going on: a vtable is created for Base and a vtable is created for Derived, because there is only one vtable per class. Because pBase is calling upon a function that is virtual and overrode, a pointer to the vtable for Derived is called. Call it d_ptr, also known as a vpointer:

int main()
{
    Base *pBase = new Derived;
    pBase->d_ptr->f();
    return 0;  
}

Now the d_ptr calls Derived::f(), which calls Base::f(), which then looks at the vtable to see what g() to use. Because the vpointer only knows g() in Derived, that's the one we use. Therefore, Derived::g() is called.

Roof answered 23/6, 2016 at 1:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.