0

Consider the following code:

#include <iostream>

class Entity
{
private:
    int entityInt_;

public:
    Entity()
        : entityInt_(0)
    {}

    virtual void print() const
    {
        std::cout << "This is Entity class\n";
    }
};

class Player : public Entity
{
private:
    int playerInt_;

public:
    Player()
        : playerInt_(0)
    {}

    void print() const
    {
        std::cout << "This is Player class\n";
    }
};

class Enemy : public Entity
{
private:
    int enemyInt_;
    double enemyFloat_;

public:
    Enemy()
        : enemyInt_(0), enemyFloat_(0.0)
    {}

    void exclusiveEnemy() const
    {
        std::cout << "This is an exclusive method of Enemy class\n";
    }

    void print() const
    {
        std::cout << "This is Enemy class\n";
    }
};

int main(int argc, const char* argv[])
{
    Entity* actuallyPlayer = new Player();
    Enemy* enemy = static_cast<Enemy*>(actuallyPlayer);

    enemy->print();
    enemy->exclusiveEnemy();
}

As far as I understand, in the line:

Entity* actuallyPlayer = new Player();

the underlying object which actuallyPlayer pointer is pointing to is a Player. Player does not contain exclusiveEnemy method. Hence, I expected that, after casting the Entity class into an Enemy class and calling that method, the program would crash (because actuallyPlayer is actually pointing to a Player and not to an Enemy). However, the program works fine and prints:

This is Enemy class

This is an exclusive method of Enemy class

I would like to understand why is this code not crashing.

  • 1
    Undefined behavior means anything can happen, including crashing. Also, much more dangerous, appearing to work instead of crashing. – Stephen Newell Sep 11 '21 at 22:56
  • Just wondering here. It could be the code is optimized because you don't actually use any member in that exclusive function. I would do several tests. Try to print the double value in the exclusive function would be one. Defining an instance of Enemy and printing the address of the exclusive method for both the instance and the pointer to the instance would be another one. – rturrado Sep 11 '21 at 23:00
  • 1
    *"I expected that, after [X], the program would crash"* -- A crash is almost never guaranteed. Sometimes luck steps in and your program avoids the landmine. In this case, the luck probably used the fact that your member functions do not try to access `*this`. – JaMiT Sep 11 '21 at 23:02
  • I can't see either why the print method is working so I would also do some tests for that. But as @StephenNewell said, this looks like playing with UB. – rturrado Sep 11 '21 at 23:03
  • As for why execution did not meet your expectations, that is the specialty of undefined behavior. See [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/questions/2397984). From the accepted answer: *"Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to [other options including crashing]."* Looks like the behavior was to ignore the situation. – JaMiT Sep 11 '21 at 23:06
  • 1
    Thank you all for your answers! I have tried to print the values of enemyInt_ and enemyFloat_ inside the exclusiveEnemy() and print() methods and I have found that enemyInt_ is 0 but enemyFloat_ gets a random number every time I run the program. – David Pérez Sánchez Sep 12 '21 at 10:21

0 Answers0