views:

1626

answers:

6

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;
}
A: 

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

Hank Gay
No, it's safe to do that, but you do need to know which version you're getting.
David Thornley
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
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
+14  A: 

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
+3  A: 

See this question also

rq
+3  A: 

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.

Charles Bailey
A: 

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

Your code can be re writtern 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; }

Vinay
+2  A: 

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