0
#include<iostream>
using namespace std;
int main(){
    class c1{

        public:
         int func(){
            cout<<"in the  c1";
         }

    };

    class c2:public c1{

        public:
        int func(){
            cout<<" in c2";
        }
    };


c1* a;
c2 b;

a=&b;
a->func();

}

I Know i should have used virtual functions to get the desired result but i want to know what is going on in the above code.i.e Why is the call to c1::func() is being made instead of c2::func()?

Also please explain what happens when virtual is used that is different from this case.

4
  • 1
    You declared your a as c1 *. So, when you call a->func(), it calls c1::func(). That's how it works without virtual. Oct 31, 2017 at 0:14
  • @AnT i want to what different happens when virtual is used?
    – rooni
    Oct 31, 2017 at 0:15
  • @rimiro the virtual keyword is explained adequately in many places on the web and in books. Oct 31, 2017 at 0:17
  • @PaulRooney but they dont seem to address my query
    – rooni
    Oct 31, 2017 at 0:19

3 Answers 3

4

When a member function is not virtual, the function called is determined only by the type of the expression to the left of the dot (.) or arrow (->) operator. This is called the "static type".

When a member function is virtual, the function called is determined by the actual most derived type of the object named by the expression left of the dot (.) or pointed to by the expression left of the arrow (->). This is called the "dynamic type".

Note that when a variable, member, parameter, or return type used to the left of a dot has a plain class type, the static type and dynamic type are always the same. But if a variable, member, parameter, or return type is a pointer or reference to a class type, the static type and dynamic type can be different.

3
  • Can you please give one example to illustrate this ," But if a variable, member, parameter, or return type is a pointer or reference to a class type, the static type and dynamic type can be different."
    – rooni
    Oct 31, 2017 at 0:34
  • @rimiro Derived d; Base& b = d; d.virtual_fun();. This will call virtual_fun() in Derived, not in Base (so the static type and dynamic type are different in this case). If you just declare Base b = d; then you end up with object slicing, and the call will be to the base Base::virtual_fun(), even if the latter is marked virtual.
    – vsoftco
    Oct 31, 2017 at 0:38
  • 1
    @rimiro Your original post is an example. The variable a has a type which is a pointer to class type. And (as of the last statement), the static type of *a is c1, and the dynamic type of *a is c2.
    – aschepler
    Oct 31, 2017 at 0:41
1

See http://www.cs.technion.ac.il/users/yechiel/c++-faq/dyn-binding.html , And I quote:

Non-virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object.

In contrast, virtual member functions are resolved dynamically (at run-time). That is, the member function is selected dynamically (at run-time) based on the type of the object, not the type of the pointer/reference to that object. This is called "dynamic binding." Most compilers use some variant of the following technique: if the object has one or more virtual functions, the compiler puts a hidden pointer in the object called a "virtual-pointer" or "v-pointer." This v-pointer points to a global table called the "virtual-table" or "v-table."

0

It may help to see virtual and non-virtual functions implemented in C style.

struct bob {
  int x;
  static int get_x_1( bob* self ){ return self->x; }
  int get_x_2() { return this->x; }
};
inline int get_x_3( bob* self ){ return self->x; }

all 3 of the above are basically the same thing (minor details like calling convention -- which registers or stack location arguments go on -- can differ).

Non virtual member functions are just functions that take a semi-secret pointer called this. Semi-secret because it is right there on the left of the method name.

This is important to understand. Non-virtual calls are just fancy function calls. Instances of the class don't store pointers to its methods, or anything like that. They are just syntactic sugar for humdrum function calls.


Now virtual member functions are different.

Here is roughly how we'd implement this:

class bob{
public:
  virtual int get_x(){ return x; }
  int x;
};

without using virtual:

struct bob;
using get_x=int(bob*);
struct bob_vtable {
  get_x* get_x=0;
};
inline int get_x_impl( bob* self );
bob_vtable* get_bob_vtable(){
  static bob_vtable vtable{ get_x_impl };
  return &vtable;
}
struct bob {
  bob_vtable* vtable=0;
  int x;
  int get_x(){ return this->vtable->get_x(this); }
  bob(): vtable(get_bob_vtable()) {}
};
inline int get_x_impl( bob* self ){ return self->x; }

lots of stuff going on.

First we have get_x_impl, which is a lot like the non-virtual get_xs above.

Sexond, we have a table of function pointers (here dontainig just one) called a vtable. Our bob contains a pointer to a vtable as its first entry. In it we have a function pointer pointing at our get_x_impl. Finally, bob has a get_x method that forwards calls through the vtable, through the function pointer, into the get_x_impl.

A derived type can, during construction, change the vtable pointer to point to a different table of functions, with a different implementation of get_x.

Then when ypu have a pointer to bob and call get_x, it will follow the pointer in the changed vtable and call your replacement implementation.

When you create a virtual function, machinery like the above is written for you. When you inherit and override, code that replaces the parent vtable pointer with the derived is injected into the constructors of the derived type.

All of this is basically implementing what people in C could do before C++ existed. They just hid the details and wrote the glue code for you in C++.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.