Consider below line of code
#include<iostream>
using namespace std;
class base
{
int i;
public:
void printb()
{
cout << "This pointer of base "<<this<<endl;
}
};
class derived: public base
{
int i;
public:
void printd()
{
cout << "This pointer of derived "<<this<<endl;
}
};
main()
{
derived d1;
d1.printd();
d1.printb();
}
After compiling with g++(4.8.4) in 64bit ubuntu machine result is
This pointer of derived 0x7ffe74697ac0
This pointer of base 0x7ffe74697ac0
As per my understanding both base and derived this pointer will be same since we are calling with single object.
I added virtual keyword to printd() function of derived class as below
#include<iostream>
using namespace std;
class base
{
int i;
public:
void printb()
{
cout << "This pointer of base "<<this<<endl;
}
};
class derived: public base
{
int i;
public:
virtual void printd()
{
cout << "This pointer of derived "<<this<<endl;
}
};
main()
{
derived d1;
d1.printd();
d1.printb();
}
output of above code is as below
This pointer of derived 0x7ffee969b1d0
This pointer of base 0x7ffee969b1d8
Here this pointer value is different in derived and base even if calling with single object.Every time i run the program there is difference of 1byte between derived this pointer and base this pointer.
Can anybody tell why this difference in this pointer and how virtual keyword affect this pointer.
By adding the virtual keyword, you made derived polymorphic. A common implementation of runtime polymorphism is to add a pointer to the start of the object. This vptr points to a table of functions that are dynamically dispatched (commonly known as a vtable).
As such, the base sub-object, which is not polymorphic, is offset inside the derived super-object by the hidden pointer.
You see the pointer adjusted automatically, because the compiler injects code to perform this adjustment upon calling a member function. This ensures that printb will access all the (potential) members of base in the correct location.
Related
I have two classes, base class and a derived class.
The base class has a virtual method.
Here is my test example:
class Base
{
public:
virtual void Hello() { cout << "-> Hello Base" << endl; }
};
class Derived: public Base
{
public:
void Hello() { cout << "-> Hello Derived" << endl; }
};
int main()
{
Base *mBase = new Base;
// something to do
....
Derived *mDerived = dynamic_cast<Derived*>(mBase);
mDerived->Hello();
return 0;
}
I'm looking to use the Hello() method of the class derived after the cast of mBase to mDerived.
But the problem is that when I try to use dynamic_cast it will crash the application, if not if I use reinterpret_cast the Hello() method of the Base class will be called.
Result in the case dynamic_cast:
Segmentation fault (core dumped)
Result in the case dynamic_cast:
-> Hello Base
dynamic_cast fails when cast a base class to derived class
This is what is supposed to happen. When you dynamic cast a pointer to an object whose dynamic type is not the casted type, then you get a null pointer as the result.
In your example, you indirect through the null pointer and attempt to call a member function which results in undefined behaviour.
When using dynamic cast, you must always check whether you got null or not.
if I use reinterpret_cast...
Then the behaviour will still be undefined because you'll be indirecting through a pointer to an object that does not exist. Unless you create an instance of the derived class, you cannot call its non static member function.
You can convert a base instance into a derived one like this for example:
Base b;
Derived d = b;
What happens is that the base sub object of the derived instance is copy initialised from b.
Two problems in your code: Base should have a virtual destructor so Dervied isntances can be properly destructed via a pointer to Base. Then, you are not constructing an object of type Derived, so the cast cannot succeed. dynamic_cast can fail and you should check its result for not being a nullptr. Also you forgot to delete the created object.
If you do create an instance of type Derived your code works:
#include <iostream>
using std::cout;
using std::endl;
class Base
{
public:
virtual void Hello() { cout << "-> Hello Base" << endl; }
virtual ~Base(){}
};
class Derived: public Base
{
public:
void Hello() { cout << "-> Hello Derived" << endl; }
};
int main()
{
Base* mBase = new Derived;
Derived *mDerived = dynamic_cast<Derived*>(mBase);
if (mDerived) mDerived->Hello();
delete mBase;
}
#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.
I create a base pointer and pass the address of the derived object to it. But an error displayed when I tried to access a function named fun() through that pointer. Why does this code give errors?
#include<iostream>
using namespace std;
class Base
{
public:
virtual void fun ()
{
cout << "Base::fun()"<< endl;
}
};
class Derived : public Base
{
public:
virtual void fun ( int x )
{
cout << "Derived::fun(), x = " << x << endl;
}
};
int main()
{
Derived d1;
Base *bp = &d1;
bp->fun(5);
return 0;
}
Because in your base class you only have a function fun(). It is only in your derived class that you have fun(int). You fun(int) is not overriding the fun() in the base class, rather it is creating a new function entirely - function signature is not only the name but the name and the parameters.
Since you are accessing the object through a base pointer, you can't access fun(int) but fun().
Consider the below code.
#include<iostream>
using namespace std;
class Base
{
public:
virtual void function1() {cout<<"Base:function1()\n";};
virtual void function2() {cout<<"Base:function1()\n";};
};
class D1: public Base
{
public:
virtual void function1() {cout<<"D1:function1()\n";};
virtual void function2() {cout<<"D1:function2()\n";};
};
int main()
{
Base *ptr= new D1;
ptr->function1();
ptr->function2();
return 0;
}
The ptr will be pointing to D1 obj.
so whenever i call ptr->function1(), the function address is fetched from virtual table of class D1. It works same way for ptr->function2() as well.
In this case the vtable[0] will have function pointer to function1(), vtable[1] will have function pointer to function2().
My question is how function call to vtable index mapping happens?
How ptr->function1() & ptr->function2() indexes to vtable[0] & vtable[1] respectively?
The first element of the class is usuaylly the (hidden) vtable pointer - vptr. For a polymorphic class, the vtable is first initialized to the vtable of base class in the base class constructor. Then, when the derived class constructor executes the same vtable pointer is initialized to point to the derived class vtable. Note that the base class vtable points to base version of function1 and function2 whereas derived class vtable points to derived version of function1 and function2.
Now, when a pointer to base class points to an instance of derived class, this is what 'typically may' happen:
class base
{
//int* vptr; //hidden vtable pointer, created by compiler for polymorphic class. vptr points to base class vtable for base clas objects
public:
virtual void function1(){std::cout <<"base::function1()"<<std::endl;}
virtual void function2(){std::cout <<"base::function2()"<<std::endl;}
};
class derived: public base
{
//int* vptr; //hidden vtable pointer, inherited from the base class. vptr points to derived class vtable for derived class objects
public:
virtual void function1(){std::cout <<"derived::function1()"<<std::endl;}
virtual void function2(){std::cout <<"derived::function2()"<<std::endl;}
};
int main()
{
typedef void (*vtableFnPtr)();
base* pBase;
base base_obj;
derived derived_obj;
pBase = &derived_obj; //base pointer pointing to derived object
//one of the several possible implementations by compiler
int* vtableCallBack = *(int**)&derived_obj; //read the address of vtable pointed by the hidden vptr in the derived_obj
//pBase->function1();
((vtableFnPtr)vtableCallBack[0])(); //calls derived::function1(), when application calls pBase->function1();
//pBase->function2();
((vtableFnPtr)vtableCallBack[1])(); //calls derived::function2(), when application calls pBase->function2();
pBase = &base_obj;
//one of the several possible implementations by compiler
vtableCallBack = *(int**)&base_obj; //base pointer pointing to base object
//pBase->function1();
((vtableFnPtr)vtableCallBack[0])(); //calls base::function1(), when application calls pBase->function1();
//pBase->function2();
((vtableFnPtr)vtableCallBack[1])(); //calls base::function2(), when application calls pBase->function2();
}
Note that the C++ compiler does not say anything about the implementation methodology to be used for achieving polymorphic behavior and hence it is completly upto the compiler to use vtable or any other implementation as long as the behavior is polymorphic. However, vtable remains one of the most widely used methods to achieve polymorphic behavior.
"All problems in computer science can be solved by another level of indirection"
I referred to excellent and detail blog post and have tried below to explain use of vtable for your simple example. See if you are read thorough it.
struct Base;
// enumerates all virtual functions of A
struct table_Base {
void (*function1)(struct Base *this);
void (*function2)(struct Base *this);
};
struct Base {
const struct table_Base *pvtable; // table maintains pointers to virtual functions. Eventually to implementations
int data;
};
void Base_function1(struct Base *this) {
std::cout << "Base:function1()" << std::endl;
}
void Base_function2(struct Base *this) {
std::cout << "Base:function2()" << std::endl;
}
// table data for Base
static const struct table_Base table_Base_for_Base = { Base_function1, Base_function2};
void Base_Ctor(struct Base *this) {
this->pvtable = &table_Base_for_Base;
this->data = 1;
}
// Now for class D1
struct D1;
struct table_D1 {
void (*function1)(struct D1 *this);
void (*function2)(struct D1 *this);
};
struct D1 {
struct Base base;
const struct table_D1 *pvtable;
int more_data;
};
void D1_function1(struct D1 *this) {
std::cout << "D1:function1()" << std::endl;
}
void D1_function2(struct D1 *this) {
std::cout << "D1:function2()" << std::endl;
}
// Important functions that do re-direction
void D1Base_function1(struct Base *this) {
D1_function1((struct D1*) this);
}
void D1Base_function2(struct Base *this) {
D1_function2((struct D1*) this);
}
// table data for D1
static const struct table_D1 table_D1_for_D1 = {D1_function1, D1_function2};
// IMPORTANT table
static const struct table_Base table_Base_for_D1 = {D1Base_function1, D1Base_function2};
// Constructor for derived class D1
void D1_Ctor(struct D1 *this)
{
Base_Ctor(&this->base); // Base class vtable is initialized.
// Now, Override virtual function pointers
this->base.vtbl = &table_Base_for_D1; // Replace the vtable
this->mode_data = 100;
}
Internally this is the logic followed by the compiler to achieve correct behavior for virtual functions.
ptr->function1();
ptr->function2();
You can trace the method calls above using vtable logic explained and see if it works.
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.