Home > OS >  Why can't I access subclass's method using pointer of parent class?
Why can't I access subclass's method using pointer of parent class?

Time:07-16

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).

  •  Tags:  
  • c
  • Related