I'm asking if (and why) the following approach is a) legal and b) moral. I'm asking with emphasis on C++03, but notes on C++11 are welcome, too. The idea is to prevent derived classes that could themselves be default constructible from implementing stupid B::B(int foo) : A(foo) {} constructors.
class Base {
private:
int i;
Base(int i) : i(i) {}
protected:
Base() {}
public:
static Base* create(int i);
};
class Derived : public Base {
};
Base* Base::create(int i) {
Derived* d = new Derived();
Base* b = static_cast<Base*>(d);
delete b;
new(b) Base(i);
return d;
}
My gut is telling me, that something is fishy here. If any Derived class accesses Base members in its constructor, I want to be somewhere else, but otherwise I have trouble seeing valid reasons why the approach is bad.
Anyway, if you think this is an acceptable approach, how would to deal with reference members (something like int& Base::j)?
Note: This is a follow-up question to How can I fake constructor inheritance in C++03?.
Edit: I must have been distracted when posting the question. Of course, instead of delete b I meant b->~Base(). I blame low blood sugar!
The code is incorrect and triggers undefined behavior. Your
Baseclass does not have a virtual destructor, which means that thedelete bwill cause Undefined Behavior.The reasons for UB in the call to
deleterange from the fact that it will not release the derived resources (which seems to be the purpose of the code, ouch!), to the fact that it will try to release the allocated memory, which might work or not, depending on the layout of both objects. If it fails to deallocate the memory it will probably crash, if it succeeds the placement new call in the following line will try to initialize an object in memory that has already been released...Even if you changed the code (trying to avoid deallocation problems) to:
Where there is no
deleteand thus that particular source of Undefined Behavior is gone, the code is still undefined behavior (probably in too many ways to even mention). For once the call to the destructor is still UB, even if that was not, the fact that you recreated theBasetype means that dynamic dispatch for that object will probably consider the object to be aBaserather than aDerivedobject (in the case ofvtables, thevptrthat points to the RunTime Type information will refer toBase, rather thanDerived)And there are probably two or three other things that can go wrong and I cannot think of right now...