anoneironaut
anoneironaut

Reputation: 1868

virtual function call in constructor use case

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:

  1. Parse gets called in the base class to parse out what should be common to all these input strings.
  2. The derived parse should get the data that is specific to the derived class.

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

Answers (5)

James Kanze
James Kanze

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

AnT stands with Russia
AnT stands with Russia

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

Gui13
Gui13

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

Jason
Jason

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

Andrew
Andrew

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

Related Questions