开发者

Unexpected behaviour of virtual function?

When I run following C++ code with Visual Studio 2010, the program stucks at the deletion of variable if any of the derived class function is declared as virtual. Can someone explain it?

void testInheritance()
{
    class a
    {
        public :
            char x;
            void fn1()
            {
                std::cout<<"\n In Class A Function 1 : "<<x;
            }
            virtual void fn2()
            {
                std::cout<<"\n In Class A Function 2 : "<<x;
            }
            a()
            {
                x='A';
                std::cout<<"\n In A() : "<<x;
            }
            ~a()
        开发者_如何转开发    {
                std::cout<<"\n In ~A : "<<x;
            }
    };

    class b: public a
    {
        public :
            char y;
            virtual void fn1()
            {
                std::cout<<"\n In Class B Function 1 : "<<y;
            }
             void fn3()
            {
                std::cout<<"\n In Class B Function 3 : "<<y;
            }
            b()
            {
                y='B';
                std::cout<<"\n In B() : "<<y;
            }
            ~b()
            {
                std::cout<<"\n In ~B : "<<y;
            }
    };

    a* var = new b();
    delete var;
}

More Info :

I understand that to invoke b::fn1 and the destructor of class b, I need to declare them virtual in base class i.e. class a. But if I don't do that and don't even declare any function from class b ( and neither from class a) as virtual, it should call both fn1 and destructors of a, and that happens perfectly. But when, I declare the any member of b (but not a) to be virtual, be it a new member or a overloaded member, then it hangs when compiled with VS2010 and breaks when compiled with gcc4.4.4 on linux. It should have called either of the destructors and worked normally, but I couldn't understand the reason behind why program breaks.

Further when using Intellitrace in Visual Studio 2010, I try to break code at the point where it hangs , I get the following message:

The process appears to be deadlocked(or is not running any user-mode code). All threads have been stopped.


You are expecting Unexpected Behavior because you have created a Undefined Behavior in your program.

Deleting a derived class object using a pointer to a base class that has a non-virtual destructor results in Undefined Behavior. An Undefined Beahavor means anything can happen.

C++ Standard section 1.3.24 states:

Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

How to resolve the problem?

The destructor in Base class should be made virtual.


Your destructor isn't virtual do you aren't allowed to delete var as a base class pointer. Most likely you just got two sets of behavior depending on the presence of other virtual functions.


you need to declare destructor virtual


If "stuck" means, b::~b() is not called then the answer is that, a::~a() needs to be virtual.

You are using a base class (a) pointer to hold the object of class b. When you delete var;, it calls only a::~a() which is not virtual; by making it virtual; the destructors are called for a and b in proper order.

[Note: the other way it can be struck only, if you have put a breakpoint somewhere and you are not stepping through. :) ]


I am actually rather fed up of seeing in C++ tests, asking what the behaviour will be in this situation. They want you to answer that it will call the destructor of A but not of B.

This is not the guaranteed behaviour and you cannot rely on it. Undefined behaviour means that you cannot be certain what will happen, and that is the case here.

It is also an instance of "just don't do it..". In my last job I removed a test totally from the system that tested this behaviour on the grounds of it being irrelevant and off-topic.

An alternative option of making the destructor of a virtual is making it protected. This will also protect you in that main() will fail to compile as you cannot call delete var from there. You could not even invoke undefined behaviour in b by doing the same as what main does, because you may be surprised but delete to an a* will be inaccessible there too.

boost::shared_ptr<a>( new b );

safely as it will create a deleter for b not for a.

As a has another virtual function in it though you should almost certainly go for the option of making its destructor virtual.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜