为什么我们使用多态指针

Why do we use pointers with Polymorphism?

本文关键字:多态 指针 我们 为什么      更新时间:2023-10-16

我正在YouTube上观看来自新波士顿的教程,我对多态性几乎没有疑问。这是他的代码:

#include <iostream>
using namespace std;
class Enemy{

   protected:
   int attackPower;
public:
    void setAttackPower(int a){
    attackPower=a;
    }
};
class Ninja:public Enemy{
public:
    void attack(){
    cout<<"I am a ninja,ninja chop! -"<<attackPower<<endl;}
};
class Monster:public Enemy{
public:
void attack() {
cout<<"monnster must eat you!!! -"<<attackPower<<endl;
}
};
int main()
{
    Ninja n;
    Monster m;
    Enemy *enemy1=&n;
    Enemy *enemy2=&m;
    enemy1->setAttackPower(29);
    enemy2->setAttackPower(99);
    n.attack();
    m.attack();
}

我的问题是:我可以像这样在main()中编写代码吗(或者我不应该和为什么??

Ninja n;
Monster m;
//Enemy *enemy1=&n;
//Enemy *enemy2=&m;
//enemy1->setAttackPower(29);
//enemy2->setAttackPower(99);
n.setAttackPower(99);
m.setAttackPower(29);
n.attack();
m.attack();

我可以像这样用main()编写代码吗 [...]

当然,你可以!这样做的原因是您的新示例不使用多态行为。与原始示例不同,原始示例从编译时代码中隐藏了Enemy对象的运行时类型的知识,重写的代码使类型保持可用。

以下是没有指针或引用将无法正常工作的内容:

void setPowerAndAttack(Enemy enemy, int power) {
//                     ^^^^^^^^^^^
//  This is not going to work without pointer/reference
    enemy.setAttackPower(power);
    attack();
}
...
Ninja n;
Monster m;
setPowerAndAttack(n, 99);
setPowerAndAttack(m, 29);

即使代码可以编译,Enemy setPowerAndAttack也不会由于对象切片而表现出多态行为。

您需要enemy成为指针或引用以保持多态行为:

void setPowerAndAttack(Enemy& enemy, int power)
//                          ^

非常重要:您需要在Enemy类中virtual attack函数,以便具有任何多态行为。从观看视频中看不出这一点:

class Enemy {
protected:
   int attackPower;
public:
    void setAttackPower(int a) {
        attackPower=a;
    }
    virtual void attack();      // <<== Add this line
    virtual ~Enemy() = default; // <<== Add a virtual destructor
};

为什么我们使用多态指针?

因为间接寻址是实现动态多态性所必需的。指针是一种间接形式,引用也用于多态性。

我可以像这样在main()中编写代码吗(或者我不应该和为什么??

你可以,而且你应该这样做。中显示的类层次结构是非多态继承的一个示例。间接寻址不会增加任何有用的内容。

您的示例未使用多态性。

多态性可以简化为通过通用接口提供不同的功能。想想USB设备:键盘和闪存驱动器共享相同的USB端口,但提供不同的功能。

此示例将使用多态性:

#include <iostream>
using namespace std;
class Enemy
{
protected:
    int attackPower;
public:
    virtual ~Enemy() = default;
    virtual void attack() = 0;
    void setAttackPower(int a) { attackPower = a; }
};
class Ninja : public Enemy
{
public:
    void attack() 
    { 
        cout << "I am a ninja,ninja chop! -" << attackPower << endl; 
    }
};
class Monster : public Enemy
{
public:
    void attack() 
    { 
        cout << "monnster must eat you!!! -" << attackPower << endl; 
    }
};
int main()
{
    Ninja n;
    Monster m;
    Enemy* enemy1 = &n;
    Enemy* enemy2 = &m;
    enemy1->setAttackPower(29); // not polymorphism: interface and functionality are from Enemy
    enemy2->setAttackPower(99); // not polymorphism: interface and functionality are from Enemy
    enemy1->attack(); // polymorphism: interface of Enemy, functionality of Ninja
    enemy2->attack(); // polymorphism: interface of Enemy, functionality of Monster
}