Virtual Functions Calls Inside Constructors

M

Marcelo De Brito

Hi!

I have read that only the local version (overriden) of a virtual
function is available to be called inside a constructor of a class
that inherits from another (base) class (which owns the "base" virtual
function overriden by the derived one).

But the code I have written compiles fairly. See it:

#include <iostream>
using namespace std;

class b1 {
public:
b1() { cout << "b1::b1()" << endl; }
virtual void f() { cout << "b1::f()" << endl; }
};

class d1 : public b1 {
public:
d1() : b1() {
cout << "d1::d1()" << endl;
b1::f(); //Calls the base class "f()" function. Shouldn't it
generate an error?
f(); //Calls the local class "d1::f()" function
}
void f() {cout << "d1::f()" << endl;}
};

int main()
{
d1 objd1;
}

I got the following return:

b1::b1()
d1::d1()
b1::f()
d1::f()

I thought the base class "b1::f()" function would be unavailable for
calling inside the derived class' constructor and only the local
version "d1::f()" could be called.

I appreciate your comments, suggestions, etc.

Thank You!

Marcelo
 
N

Neelesh

Hi!

I have read that only the local version (overriden) of a virtual
function is available to be called inside a constructor of a class
that inherits from another (base) class (which owns the "base" virtual
function overriden by the derived one).

No. Its exactly the reverse way - If a derived class object is being
constructed and in that process the base class constructor calls a
virtual function on the object-being-constructed, then the base's
local version is dispatched.
But the code I have written compiles fairly. See it:

#include <iostream>
using namespace std;

class b1 {
  public:
    b1() { cout << "b1::b1()" << endl; }
    virtual void f() { cout << "b1::f()" << endl; }

};

class d1 : public b1 {
  public:
    d1() : b1() {
      cout << "d1::d1()" << endl;
      b1::f();  //Calls the base class "f()" function. Shouldn't it
generate an error?

It is not an error, because the "base" part is completely constructed,
and hence base::f() is available. Further, you are explicitly
qualifying the function call with the class name, indicating that
static binding should be used (i.e. the call to f() should not be
resolved dynamically). Hence this will print b1::f()
      f();        //Calls the local class "d1::f()" function

True, because f() is same as this->f(), which gets resolved
dynamically.
 
M

Marcelo De Brito

Hi, Neelesh!

Thank you very much for your explanation. But I am still a little
confused, although I got the important message of constructors and
virtual functions: Don't call virtuals inside constructors. :)

Thank You!

Marcelo
 
A

acehreli

class b1 {
public:
b1() { cout << "b1::b1()" << endl; }
virtual void f() { cout << "b1::f()" << endl; }

};

class d1 : public b1 {
public:
d1() : b1() {
cout << "d1::d1()" << endl;
b1::f(); //Calls the base class "f()" function. Shouldn't it
generate an error?

You are calling b1::f() on a complete b1 object. No error there.
f(); //Calls the local class "d1::f()" function

I don't remember whether calling a virtual function in the constructor
defined, undefined, or unspecified; but I would definitely not want
d1::f() called at that point during construction.

The reason is, unless the constructor body is completed, there isn't
an object of d1 to speak of. d1::f() likely depends on d1 being a
complete object, and might not work in most cases.

Only after that closing brace we have a d1 object.

Ali
 
N

Neelesh

You are calling b1::f() on a complete b1 object. No error there.


I don't remember whether calling a virtual function in the constructor
defined, undefined, or unspecified; but I would definitely not want
d1::f() called at that point during construction.

The behavior is well-defined by 12.3/7
When a virtual function is called directly or indirectly from a
constructor ... 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’s own class or in one of its bases, but not
a function overriding it in a class derived from the constructor’s
class, or overriding it in one of the other base classes of the most
derived object

Thus, d1::f(), when called from within the constructor of the derived
class, will get resolved to the version of f() available with the
derived class.
The reason is, unless the constructor body is completed, there isn't
an object of d1 to speak of. d1::f() likely depends on d1 being a
complete object, and might not work in most cases.


Only after that closing brace we have a d1 object.

True. Just to quote the standard (because I have it open right now) -
3.8/1

The lifetime of an object of type T begins when:
— storage with the proper alignment and size for type T is obtained,
and
— if T is a class type with a nontrivial constructor, the constructor
call has completed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top