Citat:
Att basklassen räknar upp alla subklasser är absolut worst-case för att sprida beroenden. Rubbet måste byggas om ifall du lägger till en ny subklass. Värre än så kan det inte bli.
Man kommer inte ifrån att man någonstans måste skriva kod som knyter ihop säcken genom att känna till de olika subklasserna, men så lite som möjligt bör vara beroende av den koden. Det är så man undviker att sprida sina typer, inte genom att arbeta bort dynamic_cast i kod där man ändå måste känna till typen man kastar till.
Man kommer inte ifrån att man någonstans måste skriva kod som knyter ihop säcken genom att känna till de olika subklasserna, men så lite som möjligt bör vara beroende av den koden. Det är så man undviker att sprida sina typer, inte genom att arbeta bort dynamic_cast i kod där man ändå måste känna till typen man kastar till.
Håller med, även om det va jag som förvirrade honom med ett dåligt exempel så gjorde han de allra sämsta av situationen. Allt de där kan lösas under compile time:
Kod:
#include <iostream>
#include <string>
#include <type_traits>
class Box;
class Ground;
class GameObject
{
public:
GameObject() = default;
virtual std::string getName() = 0;
virtual ~GameObject() = default;
};
class Box : public GameObject
{
public:
Box()
{}
template <typename T>
void onCollision(T& gameObject)
{
constexpr bool isBox = std::is_same<T, Box>::value;
constexpr bool isGround = std::is_same<T, Ground>::value;
if (isBox)
{
std::cerr << "Box collision with: " << gameObject.getName() << std::endl;
// And do some other shit as well
}
else if (isGround)
{
std::cerr << "Box collision with: " << gameObject.getName() << std::endl;
// And do some other shit as well
}
}
std::string getName() override
{
return "box";
}
};
class Ground : public GameObject
{
public:
Ground()
{}
template <typename T>
void onCollision(T& gameObject)
{
constexpr bool isBox = std::is_same<T, Box>::value;
constexpr bool isGround = std::is_same<T, Ground>::value;
if (isBox)
{
std::cerr << "Ground collision with: " << gameObject.getName() << std::endl;
// And do some other shit as well
}
else if (isGround)
{
std::cerr << "Ground collision with: " << gameObject.getName() << std::endl;
// And do some other shit as well
}
}
std::string getName() override
{
return "ground";
}
};
int main()
{
Ground g;
Box b;
b.onCollision(b);
b.onCollision(g);
g.onCollision(b);
g.onCollision(g);
}
Man kommer inte ifrån att dynamic_cast är helt enkelt ett måste ibland.