Vinnaren i pepparkakshustävlingen!
  • 4
  • 5
2016-10-19, 23:41
  #49
Medlem
enowens avatar
Citat:
Ursprungligen postat av WbZV
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.

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(TgameObject)
        {
            
constexpr bool isBox std::is_same<TBox>::value;
            
constexpr bool isGround std::is_same<TGround>::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(TgameObject)
        {
            
constexpr bool isBox std::is_same<TBox>::value;
            
constexpr bool isGround std::is_same<TGround>::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.
Citera
2016-10-20, 19:55
  #50
Medlem
Citat:
Ursprungligen postat av enowen
Allt de där kan lösas under compile time:
Det går bara för att du har ett statiskt programflöde som kan instansieras när main-funktionen kompilerar. I det allmänna fallet med ett dynamiskt flöde behöver vi polymorfism för att hantera heterogena listor och algoritmer som arbetar på basklasser. I princip är onCollision(a, b) en binär funktion som tar två argument av basklassens typ. Som jag tidigare försökt förklara erbjuder kompilatorn en dynamisk nedkastning av a genom att vi kan skriva a.onCollision(b), men för att kunna implementera metoden behöver vi kunna göra motsvarande nedkastning av b. I grunden en symmetrisk funktion där vi har samma krav på a och b oavsett vilken parameter som står till vänster och vilken som står till höger.

Citat:
Man kommer inte ifrån att dynamic_cast är helt enkelt ett måste ibland.
Åtminstone är alternativen ofta sämre. En insikt som gjorde att dynamic_cast infördes i språket utan att ha varit med från början.
Citera
2016-10-20, 21:50
  #51
Medlem
enowens avatar
Citat:
Ursprungligen postat av WbZV
Det går bara för att du har ett statiskt programflöde som kan instansieras när main-funktionen kompilerar. I det allmänna fallet med ett dynamiskt flöde behöver vi polymorfism för att hantera heterogena listor och algoritmer som arbetar på basklasser. I princip är onCollision(a, b) en binär funktion som tar två argument av basklassens typ. Som jag tidigare försökt förklara erbjuder kompilatorn en dynamisk nedkastning av a genom att vi kan skriva a.onCollision(b), men för att kunna implementera metoden behöver vi kunna göra motsvarande nedkastning av b. I grunden en symmetrisk funktion där vi har samma krav på a och b oavsett vilken parameter som står till vänster och vilken som står till höger.


Åtminstone är alternativen ofta sämre. En insikt som gjorde att dynamic_cast infördes i språket utan att ha varit med från början.

Jo jag är mycket väl medveten om varför det fungerar, jag menade att man lika gärna kunde lösa det på de sättet om man skulle göra så som chig gjorde. Hade vart annorlunda om vi skulle spara detta i en vector kanske.
Citera
  • 4
  • 5

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback