我正在努力克服C ++中的多态性。我有2个班级,Hero
和MainPlayer
。 Hero
是基类,MainPlayer
派生自Hero
。在Hero
我有一些变量和方法,MainPlayer
有一些额外的变量和方法。我正在尝试创建多态指针,如:
Hero *player = new MainPlayer(constructor);
然后使用播放器我只能访问Hero
类中的方法,否则会出现编译错误。我想问一下是否有可能
通过这个多态指针使用MainPlayer
方法和变量:player
。
我的代码:
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;
}
答案 0 :(得分:3)
有可能。这是一个例子。 h2指向Hero,但它使用的是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;
}
打印:
The Hero
The Main Player
答案 1 :(得分:2)
当通过指向MainPlayer
的指针访问Hero
时,唯一公开的接口是Hero
的接口,并且编译器只能利用{{1}已知的功能}。
如何解决这个问题(按个人喜好排序):
在需要Hero
附加功能的情况下,避免与MainPlayer
作为Hero
进行互动。 MainPlayer
攻击并受到伤害(或多或少,由于可能会被覆盖),就像其他人一样,但如果MainPlayer
MainPlayer
只能SwingFromChandelier
,则只应提供MainPlayer
有机会这样做。在这种情况下,MainPlayer
的大部分时间都已作为MainPlayer
提供。
摘要需要公开其他功能。例如,也许MainPlayer::fun
可以调用MainPlayer::fun2
来执行额外的MainPlayer
内容。 MainPlayer
覆盖Hero::Attack
可以调用BerserkRampage
专业攻击函数,无需向任何人公开BerserkRampage
。
Hero
的接口可能未指定。考虑使用其他虚拟功能扩展Hero
。
dynamic_cast
Hero *
至MainPlayer *
,验证结果不是nullptr
,并在新建的MainPlayer
上调用MainPlayer *
功能
答案 2 :(得分:2)
从指向基类Hero
的指针,您只能调用函数并访问Hero
类的成员。
这有一个重要的例外,即在派生类中重写的基类的虚函数(具有与派生类MainPlayer
中描述的相同的签名),它将调用执行的派生类(即使它不包含关键字override
)。
最后,从Hero
创建的指向MainPlayer
的指针可以转换回MainPlayer
的指针,然后您可以调用函数并从MainPlayer
访问成员,如下例所示:
Hero * h2 = new MainPlayer();
MainPlayer * h3 = dynamic_cast<MainPlayer*>(h2);
if (h3 != nullptr)
{
h3->fun2();
}
delete h2;
最后不要忘记删除已分配的指针
编辑:
override
说明符虽然不是必需的,但可以帮助您确保覆盖基类中的函数。如果基类未声明具有相同签名的虚函数,则程序将无法编译。以下是此概念的一个简单示例:
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
};