Polymorphism calling a function from the base class - c++

So I have these classes:
class Base {
public:
Base() {cout << "made a base" << endl;}
virtual void getType() const { cout << "Im a base" << endl;
virtual ~Base() {}
//other members...
}
class Derived: public Base {
public:
Derived() {cout << "made a derived" << endl;
virtual void getType() const { cout << "Im a derived" << endl; }
virtual ~Derived() {}
//other memebrs...
}
int main() {
Base* test = new Derived();
test->getType();
return 0;
}
output:
made a base
made a derived
Im a derived
Now I know that the output is Im a derived because of polymorphism, however I would like to know how this works internally with Vftables, how can It call the correct function, the vtable inside test points to the Base class getType() function because of the type of test so how can it know that it is Derived::getType() and not Base::getType().in other words what does my program do at runtime when it see's this declaration test->getType()?
Thanks in advance.

When you do Base* test = new Derived():
The V-Table pointer of object test is set to point to the V-Table of class Derived.
Note that when the object is created - via new Derived() - you are explicitly calling a function (the constructor) of class Derived and not of class Base.
And when this function is called, it sets the v-table pointer of the new object to point to the V-Table of class Derived and not of class Base.
AFAIK, the actual V-Tables (of both classes), are generated by the linker past compilation.
Supplemental:
The program doesn't need to "know" that a function is virtual.
In case of a non-virtual function call, the compiler adds a JUMP instruction to a constant address (i.e., the address of the non-virtual function, which is resolvable during compilation).
In case of a virtual function call, the compiler adds a JUMP instruction to an address stored in (pointed by) a variable, whose value is resolved only during runtime.

Related

calling a base function on a derived object

class base{
public:
virtual void foo(){
std::cout << "base::foo was called" << std::endl;;
}
void bar(){
foo();
std::cout << "base::bar was called" << std::endl;;
}
};
class derived : public base {
public:
void foo() {
std::cout << "derived::foo was called" << std::endl;
}
};
int main() {
derived der;
der.bar();
// desired output = "base::foo was called" "base::bar was called"
// actual output = "derived::foo was called" "base::bar was called"
}
Am I missing something obvious here?
Why does the bar() function when called on an object of derived class call the derived::foo function, even though the function itself only exists in the base class.
When a member function in a derived class overrides a virtual member function in a base class like this, that means it entirely replaces the function definition for most purposes. So calling the function foo on the object der created in main will usually use the Derived::foo definition. This behavior is consistent whether the code calling foo is in a member of Derived, or a member of Base, or neither class.
The two major exceptions are:
If you use a "qualified-id" class_type::func_name syntax to call the function, that disables the virtual function logic and just calls the function you named (after normal name lookup and overload resolution).
So since you say you want the program to call base::foo, change base::bar like:
void bar() {
base::foo();
std::cout << "base::bar was called" << std::endl;
}
During a constructor or destructor of the base class, the function from the base class (or one of its bases) will be called, ignoring overriders in the derived class(es). The object is considered to not yet or no longer be an object of the derived type. (And if the derived function were called and uses any derived members which are not yet created or already destroyed, this would be trouble.)
base::foo is declared virtual, hence uses virtual dispatch. If you don't want that then call base::foo explicitly:
struct base{
virtual void foo(){
std::cout << "base::foo was called" << std::endl;;
}
void bar(){
base::foo();
std::cout << "base::bar was called" << std::endl;;
}
};
(note that all methods are private in your example, I suppose thats just a typo)
When you declare a function virtual, the compiler will generate a vtable for each object created, and in your case, since the object is a derived the function vtable will always point to derived::foo() for that instance.

Question about polymorphism & overloading

#include <iostream>
class X{
public:
virtual void f() {std::cout << "1";}
};
class Y : public X{
public:
void f() {std::cout << "2";}
void g() {std::cout << "3";}
};
class Z : public Y{
public:
virtual void f() {std::cout << "4";}
void g() {std::cout << "5";}
virtual void k() {std::cout << "6";}
};
void main()
{
X *x = new Z;
Y *y = new Z;
Z *z = new Z;
x->f(); // 4
y->f(); // 4
y->g(); // 3
z->f(); // 4
z->g(); // 5
z->k(); // 6
system("PAUSE");
}
Output: 443456.
I got confused, why did it not print '2' when doing 'y->f()'? f() inside Y class isn't a virtual function.
I'd like to know more about it, thank you for the help.
why did it not print '2' when doing 'y->f(x)'? f() inside Y class isn't a virtual function.
Y::f is a virtual function. If a base class has a virtual function by the same name, then the derived class function is implicitly virtual as well.
First of all, overloading isn't relevant here--you don't have any overloaded functions (which would be functions with the same name, but different signatures, at the same scope).
Second, you're not really dealing much with virtual functions either. One one hand, it's true that you've (quite correctly) declared f() as a virtual function in your base class (X).
You've also overridden that virtual function in your derived class Y.
But, the primary time a virtual function means something is when you invoke the virtual function in an object of a derived class via a pointer (or reference) to the base class:
#include <iostream>
class base {
public:
virtual void f() { std::cout << "base::f()\n"; }
void g() { std::cout << "base::g()\n"; }
};
class derived : public base {
public:
virtual void f() { std::cout << "derived::f()\n"; }
virtual void g() { std::cout << "derived::g()\n"; }
};
int main() {
base *b = new base; // first case: pointer to base, base object
base *d = new derived; // second case: pointer to base, derived object
derived *d2 = new derived; // third case: pointer to derived, derived object
b->f(); // invokes base::f
b->g(); // invokes base::g
d->f(); // invokes derived::f
d->g(); // invokes base::g
d2->f(); // invokes derived::f
d2->g(); // invokes derived::g
}
So, in the first case, we have a base pointer, referring to a base object. With this, the derived class might as well not exist--we always get the base class member functions, regardless of whether they're virtual.
The case you asked about is pretty much the same as the third case in this code: we have a pointer to the derived object referring to an object of the derived class. Here again, it doesn't matter whether a function is virtual or not. Since we're using a pointer to a derived, we always get the derived version of each function, regardless of whether it's virtual or not.
The case where virtual functions get interesting is the second one, where we have a pointer to the base class, but it's referring to an object of the derived class. In this case, g() (which isn't virtual) is statically bound, so the function that gets called depends on the type of the pointer. Since we're using a pointer to base, we get base::g() even though the pointer is actually referring to a derived object.
But, with f() (which is virtual), we get "late binding"--even though we're using a pointer to base, when we invoke f(), we invoke derived::f(), because the object being pointed at is a derived object.
So yes, in your code, derived::f() is virtual because it's declared virtual in base--but even if it wasn't virtual, since you used a pointer to the derived class, you'd still have gotten derived::f() even if f() wasn't virtual at all.

Accessing virtual base class function from a derived class

1.In the main function below, why does d.foo(9.5) not select the Base::foo(double) method from the base class? Doesn't the derived class inherit that method?
2.What causes the compile error?
class Base {
public:
virtual void foo(int){
cout << "Base::foo(int)" << endl;
}
virtual void foo(double){
cout << "Base::foo(double)" << endl;
}
};
class Derived : public Base {
public:
virtual void foo(int){
cout << "Derived::foo(int)" << endl;
}
};
void main() {
Derived d;
Base b, *pb = &d;
d.foo(9); // selects Derived::foo(int)
d.foo(9.5); // selects Derived::foo(int)
pb->foo(9); // selects Derived::foo(int)
pb->foo(9.5); // selects Base::foo(double)
Derived * d;
d->foo(9); // compile error
}
The compilation error is because of two variables with the same name in main().
As to your problem with inherited functions not being called for an instance of your Derived (except via pointer to Base)
The standard describes the "hiding rule", which makes this happen. Essentially, member functions declared in derived classes hide inherited functions with the same name but different signature inherited from the base class. The hiding rule is independent of whether the inherited functions are virtual or not.
The common solution is to introduce all inherited functions from the base class with using Base::foo. For example,
class Base {
public:
virtual void foo(int){
cout << "Base::foo(int)" << endl;
}
virtual void foo(double){
cout << "Base::foo(double)" << endl;
}
};
class Derived : public Base {
public:
using Base::foo;
virtual void foo(int){
cout << "Derived::foo(int)" << endl;
}
};
Another solution is to remember to explicitly override all inherited versions of the function (implement the derived class version to simply call the base class version of each function). This works with older compilers that do not support a using directive like the above. The catch is that it is necessary to explicitly do this with every inherited overload, and it is easy to miss one.
In the main function below, why does d.foo(9.5) not select the Base::foo(double) method from the base class? Doesn't the derived class inherit that method?
Yes, but it's hidden by the function with the same name in the derived class. You can unhide it with a using-declaration in the derived class:
using Base::foo;
What causes the compile error?
You're trying to declare a second variable called d. Change the name to something that's not already used; and initialise it to point to a valid object, otherwise you'll have a runtime error or other undefined behaviour.
Derived * pd = &d;
pd->foo(9); // selects Derived::foo(int)
Also, main has the wrong return type. It must return int.
1) Because this is exactly how polymorphism work. If a virtual function is redefined in a derived class, this (and only this) redefined version will be called. If the function is not virtual it's vice versa: only the base class function will be called.
//Example 1: non-virtual function
class Base
{
public:
void foo()
{
std::cout << "Base";
}
}
class Derived : public Base
{
public:
void foo()
{
std::cout << "Derived";
}
}
Base * base = new Base();
base->foo()//prints "Base"
Base * derived = new Derived();
derived->foo()//prints "Base", since the function is not virtual, and the version from the base class is called
//Example 2: virtual function
class Base
{
public:
virtual void foo()
{
std::cout << "Base";
}
}
class Derived : public Base
{
public:
void foo()
{
std::cout << "Derived";
}
}
Base * base = new Base();
base->foo()//prints "Base"
Base * derived = new Derived();
derived->foo()//prints "Derived", since the function is virtual, and the redefined version from Derived class is called
2) The compile error happens because you have a conflicting declaration - two objects are called d.
Derived * d;
d->foo(9); // compile error
You don't have instantiated the object:
Derived * d = new Derived;
If you not create the object the compiler use the previous declaration of d: Derived d that is not a pointer.

Confusion with virtual pointer of derived class

Base having a virtual function and Derived also having one virtual function like this,
class Base
{
private:
int i;
public:
Base(int data = 9):i(data)
{
cout << "In Base class constructor" << endl;
}
void display()
{
cout << "In Base class" << endl;
cout << "i = " << i << endl;
}
virtual ~Base()
{
cout << "In Base class destructor" << endl;
}
};
class Derived: public Base
{
private:
int j;
public:
Derived(int data = 10):Base(11),j(data)
{
cout << "In Derived class constructor" << endl;
}
virtual void display()
{
cout << "In Derived class" << endl;
cout << "j = " << j << endl;
}
~Derived()
{
cout << "In Derived class destructor" << endl;
}
};
Now in gdb I see the total size of the Derived class object is 16 bytes (int+int+_vptr+_vptr), but when I print each object in gdb I'm getting confused, for base class it's showing like this
$1 = {_vptr.Base = 0x401010, i = 11} and it's fine, but for derived it's showing something like this
$2 = {<Base> = {_vptr.Base = 0x401010, i = 11}, j = 10}
I'm not seeing the virtual pointer of the derived class. As per my understanding in addition to the base class virtual pointer which is inherited, there should be one more virtual pointer in the derived class that should point to it's own virtual table. Am I doing something wrong here or is there any other way to get it?
The derived class has its own vtable. So objects of that type have a single pointer to it. That vtable contains entries that point to Bases member functions if they aren't overridden. So there is no need for a pointer to Bases vtable in objects of type Derived.
The reason _vptr.Base appears in Derived is because you didn't override any functions. The compiler doesn't generate a vtable for Drived because it will just be a duplicate of Bases.
With single inheritance, there is typically just one virtual function pointer: it points to something like an array of function pointers. The number of entries contributed by the base class is known and the derived class just tags its own virtual functions to the end.
Of course, how the virtual function table actually works exactly depends on the respective ABI. You can have have a look, e.g., at the Itanium C++ ABI which is used on Linuxes and possibly on other systems.
The derived class doesn't have a separate, additional pointer to its vtable - rather, the vtable pointer inherited from the base class will be overwritten to point to the derived class's vtable as the derived class's constructor runs (and later reverted as the destructor runs).
That way, when operations are done on a Base* or Base& to the Base member embedded in a constructed derived object, the pointer to the VDT seen (at the usual offset into the Base object) allows dispatched to the derived class's methods.

Scope of pure virtual functions during derived class destruction - In C++

During destruction of the derived class object, i first hit the derived class destructor and then the base class destructor (which is as expected). But i was curious to find out - at what point does the functions of the derived class go out of scope (are destroyed).
Does it happen as soon as the control leaves the derived class destructor and goes toward the base? Or does it happen once we done with the base class destructor also.
Thanks
Once the destructor of the most derived class finishes, the dynamic type of the object can be considered that of the next less-derived-type. That is, a call to a virtual method in the base destructor will find that the final overrider at that point in time is at base level. (The opposite occurs during construction)
struct base {
base() { std::cout << type() << std::endl; }
virtual ~base() { std::cout << type() << std::endl; }
virtual std::string type() const {
return "base";
}
};
struct derived : base {
virtual std::string type() const {
return "derived";
}
};
int main() {
base *p = new derived;
std::cout << p->type() << std::endl;
delete p;
}
// output:
// base
// derived
// base
Functions don't get destroyed.
Virtual functions however get their entry in the v-table erased as soon as the derived destructor finishes so you can't call derived virtual functions from the base d'tor.