C++ virtual functions

Hi, look at the simple test:

#include <iostream>

class A
{
public:
  A(){
    std::cout << "A::A()\n";
  };
  ~A(){
    std::cout << "A::~A()\n";
    f();
  }

  virtual void f()
  {
    std::cout << "A::f()\n";
  }
};

class B : public A {
public:
  B(){
    std::cout << "B::B()\n";
  }
  virtual void f()
  {
    std::cout << "B::f()\n";
  }

};

void main()
{
  A *a = new A;
  B *b = new B;

  delete a;
  delete b;
}

The output I get is:
A::A()
A::A()
B::B()
A::~A()
A::f()
A::~A()
A::f()

but when f() is defined as virtual, i'm expected this output:
A::A()
A::A()
B::B()
A::~A()
A::f()
A::~A()
B::f()

who knows, where the error is and how to fix it (i need to call B::f())?
novakvAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AlexFMCommented:
Make also destructors virtual:

virtual ~A()...

virtual ~B()...
0
novakvAuthor Commented:
But I didn't define ~B(), so ~A() is called instead. And that's what I actually wanted. Why B::f() is not called?
0
AlexFMCommented:
Every class should have it's own destructor, and destructor should be virtual.
Virtual function f() is called according to class type, if you call it using pointer.

A *a = new A;
B *b = new B;

a->f();
b->f();


0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

AlexFMCommented:
Every class should have his own destructor to ensure that class clean-up code is executed. Destructor should be virtual to ensure that right destructor is called according to destroyed object type.
0
novakvAuthor Commented:
I think I understand the idea of destructors. but my questions is more about virtual functions:

Why B::f() is not called?

look at this:
~A(){
    std::cout << "A::~A()\n";
    f();
}

that's the same as

~A(){
    std::cout << "A::~A()\n";
    this->f();
}

the function f() is called using pointer and thus it should be found through the table of virtual functions.
0
_ys_Commented:
> But I didn't define ~B(), so ~A() is called instead.
You may not have defined ~B( ), but the compiler sure would have. Destructors of base classes should be declared virtual.

As for your problem, it's by design. Within the body of a destructor all function calls are local - virtual status is ignored.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
novakvAuthor Commented:
>  Within the body of a destructor all function calls are local - virtual status is ignored.

I din't know that, do you know why is that so?
0
_ys_Commented:
> I din't know that, do you know why is that so?
Think about it for a second. Where is the base destructor being called from ... the derived destructor - meaning the derived's destruction process has already started. It doesn't make sense to be able to invoke a method on that object, since it's already in the process of being destroyed.
0
novakvAuthor Commented:
Yes, that makes sense. Thanks.
0
itsmeandnobodyelseCommented:
The problem is that destruction is done reverse to construction and that the destructor of A cannot call virtual functions (because B isn't valid anymore).

So, if B is destructed, first the destructor of B is called (explictly if defined or automatically if not defined) and then the destructor of A. A virtual function call is always ignored here, i. e. you can only call local class members.

Regards, Alex
0
novakvAuthor Commented:
I was looking at the destruction this way:

first the destructors are called in the reverse order. If there is no defined constructor for an inherited class, then the one from the parent is called instead (this is probably wrong).

But the object actually persists in the memmory until the last destructor is called (now i'm not sure about the virtual functions table), so there should not be a problem to call virtual functions.

Well I will do it the "usual" way, but you can correct my ideas if you want to make it clear
0
itsmeandnobodyelseCommented:
> If there is no defined constructor for an inherited class, then the one from the parent is called instead (this is probably wrong).

I think you mean 'destructor' and not 'constructor' but indeed you are wrong. The destructor is called anyway of any class or baseclass, whether it is explicitly defined by you or implicitly by the compiler. Last, only memory get freed.
Virtual destructors mean, that you may delete a baseclass pointer of a derived class instance and both destructors are called:

        B*  pB = new B;
        A* pA  = pB;

        delete pA;   // both destructors are called if ~A() is virtual.

You may look to article 'Using destructors' in Microsoft's knowledge base to learn more.

> But the object actually persists in the memmory until the last destructor is called (now i'm not sure about the virtual functions table), so there should not be a problem to call virtual functions.

The fact that virtual functions can not be called from baseclass destructors is not for simple allocation reasons. The main
point is, that members of your derived class has been already destructed when the baseclass destructor is called. So,
the virtual function would not be able to use any class members because they are all invalid to that time.

Regards, Alex



0
_ys_Commented:
Just to add , with the aid of source code.

For a constructor Derived ( ) { ... }, the compiler synthesises a call to the base class (if you haven't already provided one):

Derived ( )
: Base ( )
{ ... }

For a destructor ~Dervied ( ) { ... }, again the compiler synthesies a call to the base class

~Derived ( )
{
   ...
   ~Base ( );
}

Notice that the invocation to ~Base ( ) is at the _end_ of the Dervied destructor - all member variables have already been cleaned up.

Hope this helps.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.