MortenM
31/08/2011 - 14:46

Lørdag 27. august var det igjen tid for årets høydepunkt i sykkelsesongen (...

C++ er et fleksibelt språk, noe som av og til fører til situasjoner som er vanskelige å feilsøke. Her om dagen lærte jeg noe nytt om dynamic_cast som jeg tenkte å dele.

dynamic_cast brukes når man run-time ønsker å behandle et objekt som en gitt type. Vanligvis dreier det seg om "down-casting", dvs man har en peker til et objekt av type SuperClass, og trenger å håndtere det som SubClass:

class SuperClass { ... }
class SubClass : public SuperClass { ... }

void foo(SuperClass* object)
{
    SubClass* specific = dynamic_cast<SubClass*>(object);
    if(specific != 0) {
        ...
    }
}

Java-programmerer kan nå tenke "instanceof". Slik down-casting kommer oftest av dårlig design, og bør i hovedsak unngås. Mitt problem oppsto da jeg kombinerte dynamic_cast med bruk av multippel arv, som gir en ytterligere kompleksitet. (Men nødvendig i mitt tilfelle, uten at jeg tenker å komme nærmere inn på det i dette innlegget!) Formålet er da å—gitt pekere av typen SuperClassA—behandle objekter som om de var av typen SuperClassB:

class  SuperClassA { ... }
class SuperClassB { ... }

class SubClassFoo : public SuperClassA, SuperClassB { ... }
class SubClassBar : public SuperClassA, SuperClassB { ... }

void bar(SuperClassA* object)
{
    SuperClassB* otherKind = dynamic_cast<SuperClassB*>(object);
    if(otherKind != 0) {
        std::cout << "It's another kind!n";
    }
}

int main()
{
    SubClassFoo* fooObject = SubClassFoo();
    bar(fooObject);
}
Her skulle man altså tror at objektet av typen SubClassFoo, som arver både SuperClassA og SuperClassB, skulle la seg dynamic_cast'es til hvilken som helst av dem. Den observante leser skjønner selvsagt at slik er det ikke, ellers hadde det jo ikke vært noe problem!

Problemet utløste seriøs grubling og tvil om kompilatorens egnethet, før det gikk opp for meg: jeg hadde glemt "public" før klassenavnet på den andre superklassen! Det rette skal altså være:
class SubClassFoo : public SuperClassA, public SuperClassB { ... }

Uten public ("is a"-arv) vil klassen arves privat ("is implemented in terms of"), og objektet kan ikke behandles som om det var av den superklassen—derfor feiler også dynamic_cast!

Så lærte vi noe den dagen også.

Itema as, Granåsveien 3 - N -7048 Trondheim - Telefon: +47 73 89 43 70 - email: firmapost@itema.no

""