60

Why the following example prints "0" and what must change for it to print "1" as I expected ?

#include <iostream>
struct base {
   virtual const int value() const {
      return 0;
   }
   base() {
      std::cout << value() << std::endl;
   }
   virtual ~base() {}
};

struct derived : public base {
   virtual const int value() const {
      return 1;
   }
};

int main(void) {
   derived example;
}
Giovanni Funchal
  • 8,934
  • 13
  • 61
  • 110
  • [See this question also](http://stackoverflow.com/questions/390997/when-virtual-doesnt-work) – richq Jan 30 '09 at 17:42

7 Answers7

96

Because base is constructed first and hasn't "matured" into a derived yet. It can't call methods on an object when it can't guarantee that the object is already properly initialized.

Sean Bright
  • 118,630
  • 17
  • 138
  • 146
  • 3
    Another way of seeing it is that, in the constructor of 'base', the virtual pointer is pointing to the virtual table of 'blase' class, and it does not point to 'derived' until the construction of 'base' is done and it enters in the constructor of 'derived' – Jorge González Lorenzo Jun 18 '14 at 08:53
  • Is there a way to circumvent this behavior. I know it is bad design in general, but sometimes it can be useful for rapid prototyping. – Willem Van Onsem Nov 16 '14 at 08:14
  • Yes, there are a few ways. See [C++ Lite](https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctor-idiom). – Julian Apr 04 '16 at 03:09
20

When a derived object is being constructed, before the body of the derived class constructor is called the base class constructor must complete. Before the derived class constructor is called the dynamic type of the object under construction is a base class instance and not a derived class instance. For this reason, when you call a virtual function from a constructor, only the base class virtual function overrides can be called.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • After the base class ctor completes, `this` and virtual function table pointer will be set to derived class, and virtual function calls will dynamically select the derived override via `this->fn();`. So that last sentence is only true if the call is made from within the base class ctor. – Don Slowik Sep 29 '21 at 12:56
9

Actually, there is a way to get this behavior. "Every problem in software can be solved with a level of indirection."

/* Disclaimer: I haven't done C++ in many months now, there might be a few syntax errors here and there. */
class parent
{
public:
     parent( ) { /* nothing interesting here. */ };
protected:
     struct parent_virtual
     {
         virtual void do_something( ) { cout << "in parent."; }
     };

     parent( const parent_virtual& obj )
     {
          obj.do_something( );
     }
};

class child : public parent
{
protected:
     struct child_virtual : public parent_virtual
     {
         void do_something( ) { cout << "in child."; }
     };
public:
      child( ) : parent( child_virtual( ) ) { }
};
Tanveer Badar
  • 5,438
  • 2
  • 27
  • 32
  • 1
    This method is very limited since it can't access the class members, only the struct members. The texts should therefore be `"in parent_virtual"` and `"in child_virtual"` respectively. – HelloGoodbye Sep 27 '12 at 12:37
  • 1
    That is easily remedied. You can make them friend of various classes/structs as needed and pass this pointer. – Tanveer Badar Sep 17 '13 at 05:10
  • So how do you use these classes? What would your main function corresponding to the one in the question look like? You haven't provided any example or directions. – HelloGoodbye Sep 17 '13 at 19:36
  • this stil prints out "in parent". I believe we want to print out "in child" – VarsMolta Mar 16 '15 at 14:24
4

The question of how it works is a FAQ item.

Summarizing, while class T is being constructed, the dynamic type is T, which prevents virtual calls to derived class function implementations, which if permitted could execute code before the relevant class invariant had been established (a common problem in Java and C#, but C++ is safe in this respect).

The question of how to do derived class specific initialization in a base class constructor is also a FAQ item, directly following the previously mentioned one.

Summarizing, using static or dynamic polymorphism on may pass the relevant function implementations up to the base class constructor (or class).

One particular way to do that is to pass a “parts factory” object up, where this argument can be defaulted. For example, a general Button class might pass a button creation API function up to its Widget base class constructor, so that that constructor can create the correct API level object.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Cool. I read the other answers, didn't like them, re-invented what you say (pass the relevant function implementations up to the base class constructor), then saw your answer. I came around this problem while translating a Java program to C++. In my case, a class-specific static function was enough; I passed its pointer up to base class constructor. – iavr May 29 '15 at 23:04
3

You should not polymorphically call the virtual methods from constructor. Instead you can call them after construction of object.

Your code can be re written as follows

struct base {
   virtual const int value() const {
      return 0;
   }
   base() {
      /* std::cout << value() << std::endl; */
   }
   virtual ~base() {}
};

struct derived : public base {
   virtual const int value() const {
      return 1;
   }
};

int main(void) {
   derived example;
   std::cout << example.value() << std::endl;
}
pasha
  • 2,035
  • 20
  • 34
Vinay
  • 4,743
  • 7
  • 33
  • 43
  • 1
    This is utterly bad as you would have to write this code every time you have created one of these objects as opposed to only one time when using `Tanveer Badar`'s method. – HelloGoodbye Sep 27 '12 at 12:33
  • 2
    **−1** Really Bad Advice™ for the cases that are of interest (even though it's good advice for the uninteresting case of a call that would naturally be after the initialization, and just unnaturally and for no sane reason had been moved to the constructor). – Cheers and hth. - Alf May 12 '16 at 09:59
  • What if you don't want the users of the class to have to worry about an extra step? – flarn2006 Oct 13 '20 at 19:40
0

The general rule is you don't call a virtual function from a constructor.

Hank Gay
  • 70,339
  • 36
  • 160
  • 222
  • 1
    No, it's safe to do that, but you do need to know which version you're getting. – David Thornley Jan 30 '09 at 17:58
  • 3
    I think you mean it's "legal C++" to do that. "Safety" is a subjective word here and most coding standards recommend not calling a virtual function from a ctor - explicitly because it's hard to know "which version you're getting". Also - it's undefined behaviour to call a pure virtual function. – Richard Corden Jan 30 '09 at 19:15
  • 3
    It's very easy to know which version you're getting, since you know all of your parent classes. The only problematic aspect is that many developers simply forget this exceptional case. But there's nothing inherently unsafe about it. – Tom Jan 31 '09 at 15:52
  • 1
    @Richard: The version of the virtual function that is called is the one in the class in which the constructor that calls the virtual function is defined. Constructors and destructors, unlike methods and operators, are not derived by the subclasses but stay in the class in which they are defined. The default constructor for the superclass is implicitly called in the beginning of the construction of a subclass object, unless a constructor for the superclass is explicitly called as an initializer in the subclass constructor. – HelloGoodbye Sep 17 '13 at 19:50
-4

In C++, you cannot call a virtual / overriden method from a constructor.

Now, there is a good reason you can do this. As a "best practice in software", you should avoid calling additional methods from your constructor, even non virtual, as possible.

But, there is always an exception to the rule, so you may want to use a "pseudo constructor method", to emulate them:

#include <iostream>

class base {
   // <constructor>
   base() {
      // do nothing in purpouse
   }
   // </constructor>

   // <destructor>
   ~base() {
      // do nothing in purpouse
   }
   // </destructor>

   // <fake-constructor>
   public virtual void create() {
      // move code from static constructor to fake constructor
      std::cout << value() << std::endl;
   }
   // </fake-constructor>

   // <fake-destructor>
   public virtual void destroy() {
      // move code from static destructor to fake destructor
      // ...
   }
   // </fake-destructor>

   public virtual const int value() const {
      return 0;
   }

   public virtual void DoSomething() {
      // std:cout << "Hello World";
   }
};

class derived : public base {
   // <fake-constructor>
   public override void create() {
      // move code from static constructor to fake constructor
      std::cout << "Im pretending to be a virtual constructor," << std::endl;
      std::cout << "and can call virtual methods" << std::endl;
   }
   // </fake-constructor>


   // <fake-destructor>
   public override void destroy() {
      // move code from static destructor to fake destructor
      std::cout << "Im pretending to be a virtual destructor," << std::endl;
      std::cout << "and can call virtual methods" << std::endl;
   }
   // </fake-destructor>

   public virtual const int value() const {
      return 1;
   }
};

int main(void) {
   // call fake virtual constructor in same line, after real constructor
   derived* example = new example(); example->create();

   // do several stuff with your objects
   example->doSomething();

   // call fake virtual destructor in same line, before real destructor
   example->destroy(); delete example();
}

As a plus, I recommend programmers to use "struct" for only fields structures, and "class" for structures with fields, methods, constructors, ...

umlcat
  • 4,091
  • 3
  • 19
  • 29
  • @umlcat -3 downvotes, no explanation !!! – umlcat Sep 14 '15 at 15:22
  • I didn't downvote, but as written, this is false. You _can_ call a virtual method from a ctor. It's perfectly valid C++. The real problem is that it doesn't necessarily do what most people expect, since it calls the method for the class whose ctor is currently executing, not whatever dynamic type this object will have _later, after_ it's constructed. Also, 'don't call methods in ctor' seems like bad advice, and `class` vs `struct` makes no real difference. – underscore_d May 21 '17 at 13:03