Reputation: 33
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
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
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.
Hero
s 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
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