* Christopher:
I am beginnign to get the impression this is a very bad idea. Since I
have begun deriving classes my program is doing extremely odd things,
like mysteruiously exiting without ever throwing an exception, or
jumping to code that it shoudln't.
Can someone explain what happens when you call a virtual function or a
pure virtual function from a base class constructor?
If you call an ordinary virtual function from a constructor of class T you get a
virtual call as usual (unless you qualify the call), but the type of the object
is T at this point, so you get the same effect as with any other T object.
If you call a pure virtual function you get UB.
Most compilers will however ensure that that call results in some run time
error, or if the call is sufficiently direct, detect at compile that you're
doing it.
How do you go about rearranging you code such that it does not do
this, when part of your intialization is going to require calling
methods of derived classes?
Oh, the problem of doing derived-class specific initialization.
It's just a matter of separating concerns in a proper way.
A few such ways are outlined in the FAQ (I once convinced Marshall to add it),
but the code below is the way I think is most generally useful:
<code>
#include <iostream>
#include <memory>
#include <string>
namespace api {
struct Widget
{
virtual ~Widget() {}
virtual std::string const typeName() const { return "Widget"; }
virtual std::string const text() const { return ""; }
};
struct Button: Widget
{
std::string myText;
Button( char const aText[] ): myText( aText ) {}
virtual std::string const typeName() const { return "Button"; }
virtual std::string const text() const { return myText; }
};
} // namespace api
namespace oo {
class Widget
{
private:
std::auto_ptr<api::Widget> myWidget;
Widget( Widget const& );
Widget& operator=( Widget const& );
protected:
api::Widget const& widget() const { return *myWidget; }
public:
class Init
{
public:
virtual ~Init() {}
virtual std::auto_ptr<api::Widget> newWidget() const
{
return std::auto_ptr<api::Widget>( new api::Widget );
}
};
Widget( Init const& initializer = Init() )
: myWidget( initializer.newWidget() )
{}
std::string const typeName() const { return myWidget->typeName(); }
};
class Button: public Widget
{
private:
Button( Button const& );
Button& operator=( Button const& );
public:
class Init: public Widget::Init
{
private:
std::string myText;
public:
Init( std::string const& aText ): myText( aText ) {}
virtual std::auto_ptr<api::Widget> newWidget() const
{
return std::auto_ptr<api::Widget>( new api::Button(
myText.c_str() ) );
}
};
Button( std::string const& text = "OK" ): Widget( Init( text ) ) {}
Button( Init const& initializer ): Widget( initializer ) {}
std::string text() const { return widget().text(); }
};
} // namespace oo
int main()
{
using namespace std;
oo::Button btn;
cout << btn.typeName() << " \"" << btn.text() << "\"" << endl;
}
</code>
Cheers, & hth.
- Alf