Reputation: 1868
So I know from various online sources that it is generally a no-no to call a virtual function from within a constructor. I realize that the problem here is that the base class will be constructed first and C++ will call the Base class' version of the function first. However I have a unique use case that might be okay with this. I'd appreciate some comments. Consider this situation.
class Base
{
public:
Base(string data)
{
Parse(data);
}
~Base(){}
private:
virtual Parse(string data);
}
class Derived : public Base
{
public:
Derived(string data)
{
Parse(data);
}
~Derived();
private:
Parse(string data);
}
Let's say I have a setup like this and my expected behavior of each derived class is that:
Does it make sense to use virtual functions in the constructor in this case? Or am I forced to make "parse" public and call it each time I construct this class? Or are there other suggestions.
I hope this makes sense, and please forgive any syntactical errors above, I'm just trying to express a general idea.
Upvotes: 1
Views: 241
Reputation: 153919
The simplest solution to this is to use the strategy pattern: define an
abstract base class Parser
, with a pure virtual function parse
, and
have the derived classes pass a pointer to an instance of their parser
to the base class constructor; i.e.:
class Base
{
protected:
class Parser
{
public:
virtual ~Parser() {} // Probably not necessary, since no
// one is going to dynamically
// allocate any of these, but better
// safe than sorry.
virtual void parse( std::string const& data ) const = 0;
};
Base( Parser const& derivedClassParser, std::string const& data )
{
derivedClassParser.parse( data );
}
public:
// ...
};
Each of the derived classes will define its parser, derived from
Base::Parser
, define a static instance of it, and pass the address of
this static instance down to the base class.
There is another possibility; it doesn't necessarily work correctly if
you have temporary instances of the objects, but it can be useful if for
some reason you cannot use the above pattern. Basically, you define a
special class which calls the virtual function in its destructor, and
has an implicit conversion from std::string
(and probably from char
const*
as well, to support passing string literals), and declare your
constructors to take an instance of this class; e.g.:
class Base
{
public:
class CallVirtual
{
std::string myData;
mutable Base* myOwner;
friend class Base;
public:
CallVirtual( std::string const& data )
: myData( data )
, myOwner( NULL )
{
}
~CallVirtual()
{
if ( myOwner != NULL ) {
myOwner->Parse( myData );
}
}
};
Base( CallVirtual const& dataArg )
{
dataArg.myOwner = this;
// ...
}
virtual void Parse( std::string const& data ) ...
};
The derived classes should also take a CallVirtual const&
as argument.
Then, when you create an instance of the derived class:
Base* p = new Derived( someString );
, the string is automatically converted to a temporary CallVirtual
,
whose destructor will be called at the end of the full expression.
Upvotes: 0
Reputation: 320501
There's absolutely nothing wrong with using virtual functions in constructors, as long as it works for you. It is just important to remember that polymorphic behavior of virtual functions, when invoked from constructor, is always limited to the already constructed subset of the entire hierarchy. (Similar rule applies to destructors).
If this restricted virtual behavior is appropriate for your purposes, they use it by all means.
The "no-no" argument you must be referring to is a well-known fake argument, based on the artificial premise about the user expecting the function of the [not-yet-constructed] derived class to be called. Why some people translate that invented false premise into the conclusion that virtual functions should not be called from constructors is beyond me. I haven't seen a credible explanation yet.
Upvotes: 1
Reputation: 13551
The solution is quite simple:
class Base
{
public:
Base(string data)
{
Parse(data);
}
~Base(){}
private:
void Parse(string data);
}
class Derived : public Base
{
public:
Derived(string data)
{
ParseMore(data);
}
~Derived();
private:
void ParseMore(string data);
}
When Derived
is constructed, the constructor of Base
is called before you enter the constructor of Derived
.
So the parsing taking place in Base will be finished, and you can finish the parsing in your Derived constructor.
Upvotes: 0
Reputation: 32510
Or am I forced to make "parse" public and call it each time I construct this class?
Actually, in this scenario, since you want to avoid polymorphic behavior, I don't see exactly why you have to make Parse
a virtual method, or even a non-static method of the class since it does not modify any data-members of the class itself ... For instance, you could have Parse
as a private static
method and then simply call ClassType::Parse()
in the constructor of each object, and you'd get the same functionality.
Upvotes: 1
Reputation: 24846
Don't call virtual functions from constructor. You will not get polymorphic behavior, since Base class virtual table will be used.
If you don't need polymorphic behavior - don't make function virtual
Upvotes: 0