Please see my example:
#include <iostream>
using namespace std;
class base {
public:
base() {}
~base() {}
virtual void funcBase() {
cout << "funcBase in class derived" << endl;
}
};
class derived : public base {
public:
derived() {}
~derived() {}
virtual void funcBase() {
cout << "funcBase in class derived" << endl;
}
virtual void funcDerived() {} // I add virtual keyword to make sure funcDerived method is added in vtable of class
};
int main()
{
base* obj = new derived();
obj->funcBase(); // will print funcBase in class derived -> it's normal
obj->funcDerived(); // error: 'class base' has no member named 'funcDerived'
return 0;
}
So my question is, why can't I access the funcDerived method? I think the memory is of the derived class, so, the vpointer of class derived will point to vtable of it and this is ok!
Am I missing anything about the vtable and vpointer? What will be added to the vtable? Why is it restricted by pointer type?
CodePudding user response:
obj
is a pointer to base
.
You can only call methods declared in base
through it, even if the actual object pointed by it is a derived
.
If these methods are polymorphic (i.e. virtual
) the actual implementation that will be called will be that of derived
(as you observed).
funcDerived
is not declared in base
and therefore cannot be accessed through a base
pointer. The compiler issues an error because it cannot determine at compile time that the object is actually a derived
one.
You can use dynamic_cast
to cast the pointer to a derived
one and then call funcDerived
.
Note that dynamic_cast
can fail at run time and return nullptr
if the object pointer is not actually a pointer to derived
(or any class derived from it):
derived* obj_as_derived = dynamic_cast<derived*>(obj);
if (obj_as_derived)
{
obj_as_derived->funcDerived();
}
else
{
// Handle error ...
}
A side note: better to avoid using namespace std
- see here Why is "using namespace std;" considered bad practice?.
CodePudding user response:
base* obj = (something blah blah);
[...]
obj->funcDerived(); // error: 'class base' has no member named 'funcDerived'
The above code won't compile because the compiler (in general) has no way of guaranteeing that a base *
pointer (like obj
) actually points to an object of class derived
. For all the compiler knows, obj
might point to a bare base
object, or some other subclass of base
that doesn't have a funcDerived()
method defined; in either of those cases, trying to call a method that doesn't exist would be an error.
If you want to be able to call a virtual method via a base-class pointer, you'll need to declare that virtual method in the base class (as well as overriding it in the subclass; like what you did with funcBase()
). That will let the compiler know that the method will always be present for any base
object (or subclass thereof).