Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Gelöschter Benutzer

unregistriert

1

01.03.2013, 19:30

[C++] Casten zwischen Klassen mit virtuellen Methoden

Guten Abend,
ich habe folgendes Problem:

Vorab mein Code:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;

class CVehicle
{
public:
    virtual void method ( void ) = 0;
};

class CHeli : public virtual CVehicle
{
public:
    virtual void heliMethod ( void ) = 0;
};

class CVehicleSA : public virtual CVehicle
{
public:
    void method ( void )
    {
        cout << "method called" << endl;
    }
};

class CHeliSA : public virtual CHeli, public virtual CVehicleSA
{
public:
    void heliMethod ( void )
    {
        cout << "heliMethod called" << endl;
    }
};


int main()
{
    CVehicleSA* pVehicleSA = new CVehicleSA;
    CVehicle* pVehicle = (CVehicle*)pVehicleSA;
    
    CHeli* pHeli = reinterpret_cast<CHeli*>(pVehicle);
    pHeli->heliMethod();

    delete pVehicleSA;
    system("pause");
    return 0;
}


Ich habe eine Instanz der Klasse "CVehicle" und muss nun irgendwie zu CHeli* casten, um Zugriff auf "heliMethod" zu bekommen.
Durch das Casten mit reinterpret_cast und einen Aufruf von "heliMethod" wird in Wirklichkeit CVehicle(SA)::method aufgerufen. Meine Vermutung ist, dass CVehicle::method das erste Element in der vtable von pVehicle ist (und das echte heliMethod gar nicht vorhanden ist). Die Frage ist nur: Komme ich überhaupt auf eine "richtige" Instanz von CHeli und falls ja, wie? (möglichst ohne etwas am Layout der oben definierten Klassen zu ändern)

Viele Grüße

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

01.03.2013, 19:36

pVehicle ist kein CHeli, sondern ein CVehicleSA! Die beiden sind nicht verwandt.
Das kann also nicht funktionieren. Aktivier mal RTTI und dann bekommst du eine Cast-Exception zur Laufzeit.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

birdfreeyahoo

Alter Hase

Beiträge: 756

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

3

01.03.2013, 20:07

Außerdem würde ich dir diese Klassenhierarchie nicht empfehlen, das ist ein Diamant des Todes. CVehicle könnte eine komplexe Klasse sein, die viel Physik und Berechnung beinhaltet.
CHeliSA erbt von CHeli und CVehicleSA.
Damit auch 2 mal von CVehicle. Also hast du möglicherweise doppelt Daten drinnen die möglicherweise sehr groß sind und einfach reichen.

Es ist deswegen gut, immer nur von einer Klasse zu erben (Schnittstellen ausgenommen), was Java zum Beispiel so macht.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

01.03.2013, 20:12

Java bietet aber auch echte Interfaces. Den Diamanten meckert bei C++ der Compiler (zumindest VC) z.B. schon an, auch wenn nur rein abstrakte Methoden über verschiedene Wege geerbt wurden. Das würde bei Java nie passieren. Also... Insgesamt kann so eine Struktur natürlich in C++ gefährlich sein, aber man bekommt da oft eben schon Warnungen sogar dann, wenn man ganz harmlos mit Interfaces arbeiten wollte. Genau das ist in seinem Beispiel ja sogar der Fall.
Sein einzig echter Fehler ist falsches Casting.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »BlueCobold« (01.03.2013, 20:18)


Gelöschter Benutzer

unregistriert

5

01.03.2013, 20:15

Danke für die schnellen Antworten. Das habe ich mir schon fast gedacht. CHeli und CVehicle sind hier die modulübergreifenden Schnittstellen.
Das Problem ist, dass ich am Layout der Klassen nichts großartiges verändern kann (dreht sich um ein mittlerweile größeres Open-Source Projekt).
An mehr als eine Instanz von CVehicle komme dabei definitiv nicht dran. Dann muss ich die 3 Funktionen, die ich eigentlich als Member von CHeli(SA) schreiben wollte, wohl doch nach CVehicle(SA) verschieben.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

6

01.03.2013, 20:22

Ich glaub Du musst Dich nochmal mit wichtigen Grundlagen beschäftigen, wenn Du versuchst etwas in eine Klasse zu casten, die sie nicht ist. abwärts casten ist immer ok. Aufwärts casten ist ok, wenn die erzeugte Instanz wirklich vom Zieltyp ist. Du castest aber quer in etwas, was die Instanz einfach nicht ist.
Eine Katze bringt ja man ja auch nicht zum Bellen, indem man sie Bello nennt und mit ihr Gassi geht.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

02.03.2013, 01:54

Die Frage, die du dir hier stellen solltest, ist nicht, wie du diesen Cast irgendwie hinbekommst. Die Frage sollte sein, wieso in Gottes Namen du casten musst. Der Cast ist nur ein Symptom eines viel fundamentaleren Problems. In dem Moment, wo du einen Pointer auf eine Basisklasse in einen Pointer auf eine abgeleitete Klasse casten willst (egal auf welche Art), zeigt sich ein prinzipieller Widerspruch im Design der Software. Denn überleg mal, was das bedeutet: Du hast hier ein Stück Code, das mit einem generischen Interface zu arbeiten versucht, welches sich zur Lösung der Aufgabe aber als nicht geeignet erweist. Das bedeutet, dass entweder das Interface nicht zu deiner Problemstellung passt oder der Code das falsche Interface verwendet: Die Struktur der postulierten Lösung passt nicht zur Struktur des Problems. Um das Problem zu lösen, wirst du entweder dem Stück Code, in dem das Problem auftritt, das passende Interface übergeben oder deine Abstraktion (deine Interfaces) überdenken müssen. Wenn du auf dieses Problem stoßt, dann ist das die Chance, etwas über das Problem zu lernen, das du vorher nicht wusstest, denn sonst würde das Problem nicht auftreten. Symptombehandlung ist maximal eine temporäre Lösung; Refactoring ist eine gute Sache. Stell die richtige Frage und du dein Design wird besser als du je gedacht hättest... ;)

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »dot« (02.03.2013, 02:09)


Werbeanzeige