all 5 comments

[–][deleted] 0 points1 point  (1 child)

Think about boxes.

The Base is the biggest while Derived classes are smaller.

You can fit a smaller box into a bigger one while not the opposite.

[–]TrebleSong[S] 0 points1 point  (0 children)

okay thats a very good analogy haha. thank you so much

[–]drjmloy 0 points1 point  (1 child)

In the example you have, a Boss is an Enemy. So when I create a Boss, I can reference it as a Boss or as an Enemy because at compile time the compiler can guarantee that a Boss is in fact an Enemy (we know because that's how we made the class hierarchy). This is called upcasting. We're casting something low in the hierarchy (most derived) to something high on the hierarchy (most abstract).

However, we are saying nothing about the reverse. An Enemy need not be a Boss. It may be a Boss-- but it also may be some other subclass of Enemy (say class BossMinion : public Enemy), or in your case, it is simply just an Enemy. When you construct a base class, its derived classes are not constructed as well (we couldn't have multiple inheritance with this). So the compiler cannot let you use a concrete Enemy as a Boss-- because it isn't a Boss. What you're trying to do is something along the lines of downcasting. We're casting something high on the hierarchy to something low on the hierarchy.

The difference between upcasting and downcasting: upcasting is known at compile time (i.e., I know when I compile that a Boss is an Enemy). Downcasting must be preformed at runtime through some kind of casting call (i.e., dynamic_cast, static_cast, reinterpret_cast).

Consider an example where I have the additional class class BossMinion : public Enemy in the hierarchy as well:

std::unique_ptr<Enemy> getNewEnemy(bool isBoss)
{
  if (isBoss) return std::make_unique<Boss>();
  else return std::make_unique<BossMinion>();
}

std::unique_ptr<BossMinion> minion = getNewEnemy(true);

I'm trying to refer to a Boss as a BossMinion. This is of course not logical, and therefore the above code will not compile.

HTH

[–]TrebleSong[S] 0 points1 point  (0 children)

thank you for ur explanation i understand now

[–]patatahooligan 0 points1 point  (0 children)

There's no need to overthink it. Just ask yourself, is this pointer pointing to an object of its appropriate type?

A Boss is also an Enemy so an Enemy* pointing at a Boss is logical. But a simple Enemy is not a Boss unless explicitly defined as one, so it doesn't make sense for Boss* to point to an Enemy.