Archived

This topic is now archived and is closed to further replies.

virtual functions from constructors

This topic is 5026 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

This is something I've never understood, and I'm having a real hard time coping with now, so I thought I'd ask about.
class Base
{
    public:
        Base() { v(); }
        virtual void v()=0;
};

class Derived : public Base
{
    void v() {  } 
}; 

/*
This is illegal, the call to v is not allowed in the constructor 
of base.  I know that were the call to v() in a function other 
than the constructor, it'd work.  So I change Base:
*/

class Base
{
    public:
        Base() { v_hack(); }
        void v_hack() { v(); }
        virtual void v()=0;
};

//and this works.


Why the first version of Base illegal? it seems like it should work fine to me. And if it should be illegal then shouldn't the v_hack version? This is really bothering me, I've come across this in the past and worked around it, but I have a special need for code that does this, the workaround seems ridiculous to me. EDIT: I figured out why the first version is illegal, but why does the second work? Is the compiler just not catching it? edit: wrap comments [edited by - cozman on April 13, 2004 7:14:52 PM] [edited by - cozman on April 13, 2004 7:24:35 PM]

Share this post


Link to post
Share on other sites
Thanks Oluseyi, I guess I was editing while you were posting. After reading about the problem w/ virtuals within constructors & the vtable I figured that something like that was going on.

Share this post


Link to post
Share on other sites
Both definitions of Base fall under what the C++ Standard calls undefined behaviour. (10.4 paragraph 6 pg 179 in TC1)

Basically the reason why it's like that is because at the point where the constructor for the base class is called, the constructors for the member variables in derived classes have not been called, so any virtual function that uses those member variables will have undefined behaviour. This is significant enough that compilers will flag it as an error whenever they can detect it.

Incidently, your second definition of Base doesn't actually work portably. I tried feeding it into MSVC .NET 2003 and it did failed to actually invoke the override in the derived class.

The best work around for this kind of behaviour is to make creation of objects derived from base only available through a factory method that will call the needed virtual function after construction is finished.

edit: darn I'm slow today.

[edited by - SiCrane on April 13, 2004 7:28:21 PM]

Share this post


Link to post
Share on other sites
Instead of just saying "but it's in the spec", I'll explain what the problem is... (edit: when I started, there was just the first reply... hopefully my explanation still helps)

When you make a class Derived, memory is allocated, the Base constructor runs, then the Derived constructor runs, then the pointer is returned. Good so far.

Now we introduce your virtual call v(). If we call it in Base's constructor, or any function called from Base's constructor, Derived's constructor has not yet run. The variables of Derived are in an uninitialized, undefined state. You should be able to see the problem here, I hope.

Problem Case:
allocation
base ctor
base v_hack
derived's v function (called before ctor!)
derived ctor

Now, when you call v in the constructor, the compiler can tell, for sure, 100% of the time that it's wrong.

When you call v in v_hack, it can't warn you, or atleast no easily. The constructor is calling v_hack which is a valid function for this class. v_hack is calling v which is another valid function. The compiler doesn't see that by calling v_hack, it's calling v, which should be flagged as an error.


[edited by - namethatnobodyelsetook on April 13, 2004 7:39:01 PM]

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites
quote:
Original post by petewood
I don''t believe it is undefined behaviour. It is quite clearly defined what will happen.


He''s referring to the behavior for calling an non-pure virtual function from a constructor. If the function is pure virtual (as in this example), the standard specifically says it''s undefined behaviour. Again, see 10.4 paragraph 6 pg 179 in TC1.

Share this post


Link to post
Share on other sites
thanks for the more thorough explanation Namethatnobodyelsetook, It makes a lot of sense. Also SiCrane, I''m glad to hear that it''s caught by newer compilers, the prerelease version of gcc 3.2 I have installed w/ Cygwin didn''t catch it.

Share this post


Link to post
Share on other sites