when I want to execute this line of code, it doesn't compile
baseArray[1]->function5();
But in vtable of Derived 3, function5 should points to function5 in Derived1. so I think it should output Derived1::function5(). But it seems to find function5() in the Base class
I just wondering that Derived3 inherited from Derived1, why it still check if the called function exists in Base class?
Please refer to the following code. Thank you for your help!
#include <iostream>
using namespace std;
class Base {
public:
virtual void function1();
virtual void function2();
virtual void function3() = 0;
void function4();
};
class Derived1 : public Base {
public:
void function1();
virtual void function5();
void function6();
};
class Derived2 : public Base {
public:
void function2();
void function3();
void function4();
void function5();
};
class Derived3 : public Derived1 {
public:
void function3();
};
void Base::function1(){
cout << "Base::function1()" << endl;
}
void Base::function2(){
cout << "Base::function2()" << endl;
}
void Base::function4(){
cout << "Base::function4()" << endl;
}
void Derived1::function1(){
cout << "Derived1::function1()" << endl;
}
void Derived1::function5(){
cout << "Derived1::function5()" << endl;
}
void Derived1::function6(){
cout << "Derived1::function6()" << endl;
}
void Derived2::function2(){
cout << "Derived2::function2()" << endl;
}
void Derived2::function3(){
cout << "Derived2::function3()" << endl;
}
void Derived2::function4(){
cout << "Derived2::function4()" << endl;
}
void Derived2::function5(){
cout << "Derived2::function5()" << endl;
}
void Derived3::function3(){
cout << "Derived3::function3()" << endl;
}
int main(){
Base *baseArray[] = { new Derived2, new Derived3 };
baseArray[1]->function5(); //why the code doesn't compile when I call function5() here?
//in vtable of Derived 3, function5 should points to function5 in Derived1
//so I think it should output Derived1::function5()
dynamic_cast<Derived3*>(baseArray[1])->function5();
baseArray[1]->function6(); //same question, why it doesn't call function6 in Derived1?
//which vtable does baseArray[1] use?
dynamic_cast<Derived3*>(baseArray[1])->function6();
}
C++ is a statically typed language. That means references to types, members, variables, etc have to be known at compile-time.
The reason why baseArray[1]->function5();
and baseArray[1]->function6();
do not compile is because baseArray[1]
is declared as a Base*
but function5()
and function6()
are not members of Base
. Simple as that. This has nothing to do with vtables. That is just an implementation detail of how compilers may choose to implement the dispatching of virtual method calls at runtime, but this is not required by the C++ standard.
The compiler doesn’t know that the Base*
pointer is actually pointing at a Derived3
object. That fact is not determined until runtime. This is a key feature of polymorphism.
To call function5()
and function6()
correctly, you will need to type-cast the Base*
pointer to a derived type that has the member you want to access, as you have already discovered. Note that dynamic_cast
on a pointer will return nullptr
if the cast fails, which you are not checking for, eg:
// Derived1 and Derived2 are not related, but each has its own function5()...
if (Derived1 *d1 = dynamic_cast<Derived1*>(baseArray[index]))
d1->function5();
else if (Derived2 *d2 = dynamic_cast<Derived2*>(baseArray[index]))
d2->function5();
On the other hand, if you know the exact and correct type up front (as in your example), you can use static_cast
instead, eg:
static_cast<Derived1*>(baseArray[index])->function5();