Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

C++ virtual functions

Posted on 2003-11-12
13
Medium Priority
?
506 Views
Last Modified: 2010-04-01
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())?
0
Comment
Question by:novakv
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
  • 3
  • +1
13 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 9730194
Make also destructors virtual:

virtual ~A()...

virtual ~B()...
0
 

Author Comment

by:novakv
ID: 9730227
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
 
LVL 48

Expert Comment

by:AlexFM
ID: 9730377
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 48

Expert Comment

by:AlexFM
ID: 9730388
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
 

Author Comment

by:novakv
ID: 9730412
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
 
LVL 9

Accepted Solution

by:
_ys_ earned 400 total points
ID: 9730413
> 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
 

Author Comment

by:novakv
ID: 9730427
>  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
 
LVL 9

Expert Comment

by:_ys_
ID: 9730451
> 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
 

Author Comment

by:novakv
ID: 9730456
Yes, that makes sense. Thanks.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 9730467
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
 

Author Comment

by:novakv
ID: 9730511
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 9730687
> 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
 
LVL 9

Expert Comment

by:_ys_
ID: 9730783
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

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.
Suggested Courses

618 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question