简体   繁体   中英

C++ Polymorphism setting derived classes to base class object

I am working on a game using C++ with the SDL library, and am having troubles with polymorphism. My project includes a lot of code so I will try to use an example as best as I can.

I have a base class Pawn and derived classes Knight and Mage . Pawn includes functions that are used by Knight and Mage , but Knight and Mage have functions specific to themselves.

Lets say Pawn has a function move() , and Knight and Mage each have a function attack() that does different things for each of them. I have created an object selectedPawn in order to click between the Knight and Mage and select each of them.

Knight* knight = new Knight();
Mage* mage = new Mage();
Pawn* selectedPawn = new Pawn();

selectedPawn = knight;
selectedPawn->move(); //This does not give me any errors and runs as it should.
selectedPawn->attack(); //Error: class "Pawn" has no member "attack"

My question is, is there a way of making this possible? If not, am I totally missing the purpose of polymorphism or executing it in the wrong manner?

Your base class defines your interface

struct Pawn
{
    virtual void move() = 0;
    virtual void attack(Pawn*) = 0;
    virtual ~Pawn() = default;
};

Your derived classes implement that interface, implementing their own specific details for each function

struct Knight : Pawn
{
    void move() override;
    void attack(Pawn*) override;
};

struct Mage : Pawn
{
    void move() override;
    void attack(Pawn*) override;
};

Now you can call those functions on a base class pointer, but because of polymorphism , the derived function will be called, and therefore the functionality specific to that derived instance

Pawn* piece1 = new Knight;
Pawn* piece2 = new Mage;

piece1->move(); // will call Knight::move
piece2->move(); // will call Mage::move

Where this becomes useful is you can have a function which takes a Pawn pointer, and it doesn't know if it's a Knight or Mage , but because of polymoprhism, the correct functions get called

void do_move(Pawn* piece)
{
    piece->move();
}

void do_attack(Pawn* aggressor, Pawn* piece)
{
    aggressor->attack(piece);
}

piece1->attack(piece2); // Knight attacks Mage
piece2->attack(piece1); // Mage attacks Knight 

You can't do this in C++ (you can do this in some Smalltalk-derived languages)

What you probably want to do is create another class Attacker, with the Attack method as a pure virtual method.

Make Knight and Mage derive from Attacker as well as Pawn.

Use the dynamic_cast operator on selectedPawn to try and get an Attacker pointer from it. If the Attacker* is non-null, you can use it to call attack() on the selectedPawn.

Attacker* attacker = dynamic_cast<Attacker*>(selectedPawn);
if (attacker) {
  attacker->attack();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM