What is the expected behaviour of initialization using polymorphism in C++?
This should be a simple 100-level question, but I'm seeing something I don't expect in my project, and web searches have failed me, so I thought I'd ask here. Suppose I have the following C++ code:
class开发者_JS百科 BaseClass {
public:
BaseClass() {
this->Initialize();
}
int foo() {
return this->foo_;
}
protected:
virtual int GetInitialValue() {
return 1;
}
private:
void Initialize() {
this->foo_ = this->GetInitialValue();
}
int foo_;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass() {
}
protected:
virtual int GetInitialValue() {
return 2;
}
};
What should be the return value of DerivedClass::foo()
? Will BaseClass::GetInitialValue()
ever get called, or will it always be DerivedClass::GetInitialValue()
that gets called? Where should I have searched, and what search terms should I have used to find the answer?
GetInitialValue()
isn't virtual so there isn't dynamic dispatch anyway.
In your situation, the expected value of foo()
would be 1
, as the value of _foo
is set in the BaseClass
constructor. The derived class's version isn't called as the BaseClass
constructor is called first, and the DerivedClass
members haven't been initialized yet.
This is also item #9 in Effective C++, and that snippet is in this page from artima:
http://www.artima.com/cppsource/nevercall.html
The summary from that article is:
Things to Remember
Don't call virtual functions during construction or destruction, because such calls will never go to a more derived class than that of the currently executing constructor or destructor
#include <iostream>
class Base {
public:
Base() { this->initialize(); }
void initialize() { this->_foo = this->getInitial(); }
virtual int getInitial() { return 1; }
int _foo;
};
class Derived : public Base {
public:
Derived() : Base() {}
virtual int getInitial() { return 2;}
};
int main()
{
Base* dp = new Derived();
std::cout << dp->_foo << std::endl;
}
This code outputs 1
.
During the execution of constructors and destructors, the dynamic type is the constructed/destructed type, so in this case, the dispatch won't be to the derived version. In something like
struct Base {
virtual void f() { std::cout << "Base::f()\n"; }
};
struct D1: Base {
D1() { f(); }
virtual void f() { std::cout << "D1::f()\n"; }
};
struct D2: D1 {
D2() { name = "D2";
virtual void f() { std::cout << name << "::f()\n"; }
std::string name;
};
the construction of an object of type D2 display "D1::f()" because the call the f() occurs during the construction of the D1 base.
To understand the reason, consider what would happen if D2::f() was called, the name member isn't constructed yet...
I just noticed a problem with your code. You're indirectly calling virtual
function from constructor which is very very bad bad idea.
Read this article by Scott Meyers :
Never Call Virtual Functions during Construction or Destruction
Also read this FAQ:
When my base class's constructor calls a virtual function on its this object, why doesn't my derived class's override of that virtual function get invoked?
I know I should be answering the question myself, but I can't do better than this:
Never Call Virtual Functions during Construction or Destruction http://www.artima.com/cppsource/nevercall.html
Quote from that article:
During base class construction, virtual functions never go down into derived classes. Instead, the object behaves as if it were of the base type. Informally speaking, during base class construction, virtual functions aren't.
The process is like this :
1) The constructor or Derives is called
2) It calls the base class constructor
3) The base class constructor sets ist vtable
4) The base class constructor body is executed (in this constructor, base class vtable is used)
5) The derives constructor sets it vtable
6) The constructor is called, at this (in this constructor, the derives vtable i used)
Google: c++ virtual method constructor
For example: http://www.artima.com/cppsource/nevercall.html
Otherwise, you could search in the C++ standard draft (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/#mailing2011-02) 12.7 4
"When a virtual function is called […] from a constructor […] or from a destructor, and the objct to which the call applies is the object under construction or destruction the function called in the one defined in the constructor or destrutor's own class or in one of its bases but not a function overriding in a class derived"
精彩评论