4

I have a class A as a base class of class B.

I have called the non-virtual function, abc(), within my virtual function, xyz(), as mentioned below.

Due to run-time polymorphism, B:xyz is called – I understand this.

However, I don't understand, why was it followed by B:abc and not A:abc, as abc is a non-virtual function.

Please note: I have come across the following question: Virtual function calling a non-virtual function. It mentions that calling abc() within the virtual function is equivalent to this->abc(), hence the output. However, I am not sure I understand this part.

Because, when I do the opposite (i.e. a non-virtual function calling a virtual function), that time correct run time polymorphism is displayed. What happens to the this pointer then?

//Virtual function calling non-virtual 
class A
{
  public:
  void abc()
  {
    cout<<"A:abc"<<endl;
  }

  virtual void xyz()
  {
    cout<<"A:xyz"<<endl;
    abc();
  }
};


class B: public A
{
  public:
  void abc()
  {
    cout<<"B:abc"<<endl;
  }

  void xyz()
  {
    cout<<"B:xyz"<<endl;
    abc();
  }
};

int main() {

  A *obj3 = new B;
  obj3->xyz();\
  return 0;
}
Output
B:xyz
B:abc
//Non-virtual calling virtual function
#include <iostream>
using namespace std;

class A
{
  public:

  void abc()
  {
    cout<<"A:abc"<<endl;
    xyz();
  }

  virtual void xyz()
  {
    cout<<"A:xyz"<<endl;
  }
};

class B: public A
{
  public:

  void abc()
  {
    cout<<"B:abc"<<endl;
    xyz();
  }

  void xyz()
  {
    cout<<"B:xyz"<<endl;
  }
};

int main() {

  A *obj3 = new B;
  obj3->abc(); 
  return 0;
}
Output
A:abc
B:xyz
2
  • 1
    Please clarify However I dont understand, why was it followed by B:abc and not A:abc as abc is a non-virtual function What do you mean my followed by B:abc? Far as I can tell B::abc is never invoked. Commented Apr 12, 2021 at 21:09
  • @user4581301 check the output of first case Commented Apr 12, 2021 at 21:15

1 Answer 1

5

Calls to your non-virtual abc function are resolved, effectively, at compile time: so, when that is called from within another member function of class B, the class B version of the function is called, and is passed a pointer (this) to the object from which it is being called; similarly, if called from within a class A function, then the class A definition will be used. That is to say, to the compiler, non-virtual functions associate with a class, rather than any particular instance of the class.

However, your virtual xyz function is handled differently by the compiler; in this case, a reference or pointer to the function is added to the class definition (this is generally added into what is known as a vtable, although the details are implementation-specific); when any objects of your class(es) are created, they include a copy of that function pointer and/or vtable. When the compiler sees code to call such a virtual function, it translates that into a call via the appropriate function pointer; so, the function 'travels with' the actual object: whether the function is called from the derived class or base class (in your code) is irrelevant – the function called is the one belonging to the object (instance) from which it is invoked.

In summary: calls to non-virtual functions are resolved at compile time, whereas calls to virtual functions are (conceptually) resolved at run time.

To see creation of this "vtable" in action, try compiling and running the following code:

#include <iostream>

class A {
public:
    int i;
    ~A() = default;
    void foo() { std::cout << i << std::endl; }
};

class B {
public:
    int i;
    virtual ~B() = default;
    virtual void foo() { std::cout << i << std::endl; }
};

int main()
{
    std::cout << sizeof(A) << std::endl;
    std::cout << sizeof(B) << std::endl;
    return 0;
}

The only difference between the two classes is that one has virtual functions and the other doesn't – yet that causes a significant difference in the size of class objects: the size of the vtable (with, possibly, some 'padding' for optimal alingment of data)! (On my 64-bit Windows, using MSVC, I get sizes of 4 and 16, but the actual values will vary between compilers and platforms.)

Sign up to request clarification or add additional context in comments.

6 Comments

So even when a virtual function is called from within a member function, the ‘actual object’ is used and not ‘this’?
The this pointer is still used (it is an 'invisible' parameter to any non-static member function calls); in fact, it is even more important, because that (i.e. this) points to the object that has the vtable.
Code 2: non virtual function of class A is called i.e. abc(). From within this member function of class A, a virtual function xyz is called. So within the member function of class A, if vptr is used to resolve then wouldn’t this->vptr of class A be used? How did it rightly called derived class function.
@SumaiyaA Read my answer again: the vtable is taken from each object at runtime and the this pointer in your Code 2 points to a B object (because it was created with new B). That is polymorphism working: the object (and its pointer) carries its virtual function with it, wherever it goes!
"whereas calls to virtual functions are (and can only be) resolved at run time". Optimizer might "de-virtualize" the code, following the as-if rule. From OP code, we "know" that dynamic type of obj3 is B.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.