Re: Virtual functions in constructors. Is it possible?
Werner ha scritto:
On Jul 2, 11:25 am, Anonymous <anonym...@no.net> wrote:
no, because init() is called from a destructor of an object passed as
argument to the constructor. From top down, if init() throws an
exception, then the destruction fails, then the construction fails..
Init() may not fail by throwing, since it's called from a
destructor, and throwing would imply terminating (15.2.3).
Kind Regards,
Werner
Ok, after all I think that if necessary init() might handle failures
inside its body.
class VirtualBase {
protected:
class Initializer;
friend class Initializer;
class Initializer {
public:
Initializer() {
std::cout << "Initializer" << std::endl;
p = 0;
}
~Initializer() {
std::cout << "~Initializer" << std::endl;
if (p)
p->Init(); // call the virtual function
}
// might be private if VirtualBase is declared as friend...
void Register(VirtualBase* b) const {
p = b;
}
private:
mutable VirtualBase* p;
// private and not implemented
Initializer(const Initializer&);
void operator =(const Initializer&);
};
public:
VirtualBase(const Initializer& i) {
std::cout << "VirtualBase" << std::endl;
i.Register(this);
}
private:
virtual void Init() = 0;
// will be called immediately after the constructor
// of the most derived class
};
// This is the actual hierarchy
class Base : public virtual VirtualBase {
public:
Base(const VirtualBase::Initializer& i = Initializer()) :
VirtualBase(i) {
std::cout << "Base" << std::endl;
}
~Base() {
std::cout << "~Base" << std::endl;
}
void Init() {
std::cout << "Base::Init()" << std::endl;
}
};
class Derived : public Base {
public:
// Derived() : Base() {} // compile-time error as wanted
Derived(const VirtualBase::Initializer& i = Initializer()) :
Base(i), /* Base(i) is optional...*/
VirtualBase(i)
{
std::cout << "Derived" << std::endl;
}
~Derived() {
std::cout << "~Derived" << std::endl;
}
void Init() {
std::cout << "Derived::Init()" << std::endl;
}
};
int main() {
Base x; // calls Base::Init
Derived y ; // calls Derived::Init
return( 0 ) ;
}