4
votes

I know that within constructor of Base class - when calling virtual method - the Base method is called, not derived - see Calling virtual functions inside constructors.

My question is related to this topic. I've just wondered what happens if I call virtual method in Derived class constructor - but before constructing Base part. I mean calling virtual method to evaluate Base class constructor argument, See code:

class Base {
public:
  Base(const char* name) : name(name) {
    cout << "Base():" << name << endl;
  }
  virtual const char* getName() { 
    cout << "Base::getName()" << endl;
    return "Base";
  }
protected:
  const char* name;
};

class Derived : public Base {
public:
  Derived() : Base(getName()) {
    cout << "Derived():" << name << endl;
  }
  virtual const char* getName() { 
    cout << "Derived::getName()" << endl;
    return "Derived";
  }
};

int main() {
  Derived d;
}

Compiler g++ (4.3.x-4.5x versions) output is:

Derived::getName()
Base():Derived
Derived():Derived 

However I'd expect:

Base::getName()
Base():Base
Derived():Base

This does not look wrong - but consider this example, which produces segmentation fault:

class Derived : public Base {
public:
  Derived() : Base(getName()), name(new string("Derived")) {
    cout << "Derived():" << Base::name << endl;
  }
  virtual const char* getName() { 
    cout << "Derived::getName()" << endl;
    return name->c_str();
  }
private:
  string* name;
};

Please answer: Is this correct g++ behavior? What C++ standard says about that? Maybe it is undefined behavior?

[UPDATE1] I take into consideration Robert and Oli answers - and I changed my first example. Then it getName() is called "virtual" - and it produces Segmentation Fault. Please answer my question to this part too.

const char* virtualGetName(Base* basePtr)
{
  return basePtr->getName();
}

class Derived : public Base {
public:
  Derived() : Base(virtualGetName(this)) {
    cout << "Derived():" << Base::name << endl;
  }
  virtual const char* getName() { 
    cout << "Derived::getName()" << endl;
    return "Derived";
  }
};
2

2 Answers

11
votes

All of your examples exhibit undefined behavior. The C++ language standard states (C++11 ยง12.6.2/13):

Member functions (including virtual member functions) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator or of a dynamic_cast.

However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result of the operation is undefined.

You are calling the member function getName() from the initialization list (the ctor-initializer) of the Derived class constructor. This member function call must take place before the initializer for Base completes (the mem-initializer for Base) because it is an argument to the initializer itself.

Therefore, the behavior is undefined.

As a rule, Never Call Virtual Functions during Construction or Destruction.

1
votes

I've just wondered what happens if I call virtual method in Derived class constructor - but before constructing Base part.

It might look like you're doing this, but you're not.

In your first example, Derived::getName() does not depend on this, so the method call works. In your second example, Derived::getName() does depend on this. Since this->name is not yet set, it points to an undefined location and gives you a segfault.

this->name is not yet set, because the first thing the Derived constructor does is call the Base constructor. If you specify the parameters to pass to the Base constructor, it processes them first. Then it instantiates the member variables of the class by calling their constructors. The initializer list can be used to pass parameters to those constructors, but it cannot change the order in which they get called. This step is where name gets initialized. Finally, the body of the Derived constructor is executed.