Hunteerq
Hunteerq

Reputation: 33

Polymorphic pointer

I am struggling with Polymorphism in C++. I have 2 classes, Hero and MainPlayer. Hero is base class and MainPlayer is derived from Hero. In Hero I have some variables and methodes, and MainPlayer has some additional variables and methods. I am trying to create polymorphic pointer just like:

Hero *player = new MainPlayer(constructor);

and then with the player I can only access the methods from Hero class, otherwise there is a compile error. I would like to ask if it is possible to use MainPlayer methods and variables via this polymorphic pointer: player.

My code:

class Hero
{
public:
    Hero();
    virtual void fun() = 0;
private:
    int a, b;
};

class MainPlayer:
public Hero
{   
public:
    MainPlayer();
    void fun();
    void fun2();
private:
    int c;
};

int main()
{
    Hero *player = new MainPlayer(constructor);
    player->fun(); // works
    player->fun2(); //doesn't work
    return 0;
}

Upvotes: 1

Views: 5266

Answers (3)

OriBS
OriBS

Reputation: 732

From the pointer to the base class Hero you can only call functions and access members of the Hero class.

This has the important exception, that a virtual function of the base class that is overridden in the derived class (with the same signature as described in the derived class MainPlayer), it will call to the implementation of the derived class (even if it doesn't contains the keyword override).

Finally a pointer to Hero created from MainPlayer, can be cast back to a pointer of MainPlayer, and then you can call functions and access members from MainPlayer, like in the following example:

Hero * h2 = new MainPlayer();
MainPlayer * h3 = dynamic_cast<MainPlayer*>(h2); 

if (h3 != nullptr)
{
    h3->fun2();
}

delete h2;

Finally don't forget to delete your allocated pointer


Edit:

The override specifier, while not necessary, help you to ensure that you are indeed overriding a function from the base class. If the base class doesn't declare a virtual function with the same signature, the program will not compile. Here is a simple example for this concept:

struct A
{
    virtual void foo();
    void bar();
};

struct B : A
{
    void foo() const override; // Error: B::foo does not override A::foo
                               // (signature mismatch)
    void foo() override; // OK: B::foo overrides A::foo
    void bar() override; // Error: A::bar is not virtual
};

Upvotes: 3

user4581301
user4581301

Reputation: 33931

When a MainPlayer is accessed through a pointer to a Hero the only exposed interface is that of Hero, and the compiler can only take advantage of functionality known to Hero.

How to get around this (in order of my personal preference):

Avoid interacting with a MainPlayer as a Hero in situations where MainPlayer's additional functionality is required. MainPlayer attacks and takes damage (more or less thanks to the possibility of an override) just like everyone else, but if only MainPlayer can SwingFromChandelier, only MainPlayer should be offered the opportunity to do so. Most of the time in this case MainPlayer will already be available as a MainPlayer.

Abstract away the need to expose additional functions. For example, perhaps MainPlayer::fun can call MainPlayer::fun2 to do extra MainPlayer stuff. MainPlayer's override of Hero::Attack could call the BerserkRampage specialty attack function, removing the need to expose BerserkRampage to anyone.

Heros interface may be under-specified. Consider expanding Hero with additional virtual functions.

dynamic_cast Hero * to MainPlayer *, verify that the result is not nullptr, and invoke MainPlayer functionality on the newly-minted MainPlayer *

Upvotes: 2

Killzone Kid
Killzone Kid

Reputation: 6240

It is possible. Here is an example. h2 is pointing to Hero however it is using method from MainPlayer.

#include <iostream>
#include <string>

class Hero
{
public:
    virtual std::string whoAmI() const { return "The Hero"; }
};

class MainPlayer : public Hero
{
public:
    std::string whoAmI() const override { return "The Main Player"; }
};

int main()
{

    Hero h1;
    std::cout << h1.whoAmI() << std::endl;
    Hero *h2 = new MainPlayer;
    std::cout << h2->whoAmI() << std::endl;

    return 0;
}

Prints:

The Hero
The Main Player

Upvotes: 3

Related Questions