amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > C++: Klassen "dynamisch" laden [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- [ - Beitrag schreiben - ]

22.02.2005, 14:29 Uhr

_PAB_
Posts: 3016
Nutzer
Hallo zusammen,

ich suche nach einer Möglichkeit in C++ eine Klasse zu laden, die zur Zeit der Kompilierung noch nicht feststeht.
Konkret sieht das so aus:
Es gibt eine abstrakte Klasse "Kernel", die alle gemeinsamen Methoden implementiert und sonst nur virtuell ist.
Dann existieren von "Kernel" abgeleitete Klassen "KernelA", "KernelB", etc.
Der Benutzer soll im Programm auswählen können: "KernelB" (und zwar mit Namen zB. in einem Eingabefeld oder einer Konfigurationsdatei).

Jetzt sollte im Hauptprogramm die entsprechende Klasse geladen werden:
...
String kernelName = "KernelB";
Kernel *kern = NULL;
kern = ladeKernel (kernelName);
if (!kern) { printf ("Kernel nicht gefundenn"); exit (1); }
...

Wie kann die Methode "ladeKernel" in der Realität aussehen und ist es möglich auch nachträglich noch einen KernelX zu compilieren (mit "g++ -c KernelX.cpp") und zu verwenden, ohne die Methode "ladeKernel" ändern zu müssen.

Hier noch eine weiterführende Frage:
Ich habe jetzt im *kern einen Zeiger auf die Mutter-Klasse "Kernel".
Ist es möglich eine Methode, die in KernelX überladen wurde, aufzurufen, ohne genau zu wissen, daß man tatsächlich KernelX instanziert hat ?
Normalerweise scheint nur die nicht-überladene Methode aufgerufen zu werden, wenn man den Zeiger nicht explizit in einen Zeiger auf KernelX castet.

[ - Antworten - Zitieren - Direktlink - ]

22.02.2005, 15:10 Uhr

Solar
Posts: 3680
Nutzer
C++ hat keine Bordmittel für dynamisch nachgeladenen Code. Du müßtest hier tief in die Trickkiste der Compiler-Spezifika greifen, OS-spezifische Erweiterungen oder Frameworks benutzen.

Evtl. kommst Du eher zum Ziel, wenn Du statt "C++-Klassen" und "Kernel" in Bahnen "Bibliothek" denkst - Bibliotheken, die eine gemeinsabe LibraryBase und einen gemeinsamen Namensstamm haben; die Usereingabe entscheidet dann, welche Bibliothek tatsächlich geladen werden soll...

Zu Deinem Überladungsproblem... kann es sein, daß Du in der Basisklasse "Kernel" das "virtual" vor den Funktionen vergessen hast?

Insgesamt riecht Dein Ansinnen etwas fischig. Worum soll's denn genauer gehen, vielleicht hast Du Dich schon zu weit in die Ecke gedacht...?

[ - Antworten - Zitieren - Direktlink - ]

22.02.2005, 17:13 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von _PAB_:
Wie kann die Methode "ladeKernel" in der Realität aussehen und ist es möglich auch nachträglich noch einen KernelX zu compilieren (mit "g++ -c KernelX.cpp") und zu verwenden, ohne die Methode "ladeKernel" ändern zu müssen.

Wie Solar schon sagte, gibt es keine Bordmittel in C++, um das zu erreichen. Wenn Du dagegen erst einmal diese Hürde überwunden hast, ist es theoretisch möglich, neue Unterklassen zu übersetzen, ohne das Programm zu ändern.
Ob das allerdings auch mit anderen Versionen des Compiler oder gar einem anderen Compiler funktioniert, hängt vom verwendeten Mechanismus ab.
Ein wirklich funktionierender Ansatz läuft meistens darauf hinaus, einen sprachunabhängigen Mechanismus, wie z.B. Amiga-Libraries, in C++ Klassen zu verpacken. Das kann eine ziemlich lästige Arbeit werden. Es gibt zwar Systeme, bei denen genau das eingeplant ist und bindings automatisch erzeugt werden können, aber selbst wenn es davon eine Amiga-Version gibt, sind sie wahrscheinlich für Deine Zwecke zu überdimensioniert.
Zitat:
Normalerweise scheint nur die nicht-überladene Methode aufgerufen zu werden, wenn man den Zeiger nicht explizit in einen Zeiger auf KernelX castet.
Das klingt auch für mich nach nicht-dynamischen Aufrufen, sprich fehlendem virtual.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ Dieser Beitrag wurde von Holger am 22.02.2005 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

22.02.2005, 20:49 Uhr

_PAB_
Posts: 3016
Nutzer
Danke für die Hinweise, jedoch sind Amiga-spezifische Libraries keine Option, da der Code auch auf Linux compilierbar sein muß.

Wegen dem "fehlenden Virtual": ja, die Methode, um die es geht, ist nicht virtual, weil es sonst eine Fehlermeldung gab: man kann keine Virtual-Methode in der Mutter-Klasse definieren und in einer Tochter-Klasse überladen. Ich dachte mehr in Richtung Scope-Operator, ob es eine Möglichkeit gibt, die Methode der tatsächlich instanzierten Klasse zu verwenden anstatt die Methode des Typs des Zeigers auf diese.

Worum es geht ?
Nichtlineare Regularisierungsverfahren - kommt doch zur Frühjahrstagung der DPG, da wird unser Multi-Kernel-Ansatz kurz vorgestellt.
;-)


[ Dieser Beitrag wurde von _PAB_ am 23.02.2005 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

23.02.2005, 01:13 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von _PAB_:
Wegen dem "fehlenden Virtual": ja, die Methode, um die es geht, ist nicht virtual, weil es sonst eine Fehlermeldung gab: man kann keine Virtual-Methode in der Mutter-Klasse definieren und in einer Tochter-Klasse überladen.

Was meinst Du?
Meinst Du überschreiben, das muß funktionieren, das ist schließlich der Sinn der Sache.
Oder meinst Du überladen, also eine andere Signatur verwenden? Dann geht das, was Du machen willst, ja grundsätzlich nicht.
Zitat:
Ich dachte mehr in Richtung Scope-Operator, ob es eine Möglichkeit gibt, die Methode der tatsächlich instanzierten Klasse zu verwenden anstatt die Methode des Typs des Zeigers auf diese.
Genau das ist der Sinn und Zweck von "virtual". Die Methoden der tatsächlichen Klasse verwenden. Wenn Du keine mit "virtual" deklarierten Methoden benutzt, gibt es überhaupt keine Laufzeitinformationen über die tatsächliche Klasse, die man auswerten könnte.
Zitat:
Worum es geht ?
Nichtlineare Regularisierungsverfahren - kommt doch zur Frühjahrstagung der DFG, da wird unser Multi-Kernel-Ansatz kurz vorgestellt.
;-)

Wann und wo findet die statt?

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

23.02.2005, 14:30 Uhr

_PAB_
Posts: 3016
Nutzer
@Holger:
Meine Definition ist so:
überschreiben = überladen mit der gleichen Signatur
Hier ein einfaches Beispiel:

code:
class Kernel {
    double ValueFirst (int x, int y) {
        return Value (x,y);
    }

    virtual double Value (int x, int y) = 0;
}

class KernelA {
    double Value (int x, int y) {
        return x*y;
    }
}

class KernelB {
    double ValueFirst (int x, int y) {
        return 1.0;
    }

    double Value (int x, int y) {
        return x+y;
    }
}


Im Hauptprogramm mache ich:

code:
Kernel *kernel;
kernel = NULL;
switch (typ) {
    case 1:
        kernel = new KernelA ();
        break;
    case 2:
        kernel = new KernelB ();
        break;
}


So, wähle ich typ = 1 geht alles klar, weil die Methode ValueFirst nicht überschrieben ist und von der Mutter-Klasse verwendet wird.
Wähle ich dagegen typ = 2 bekomme ich immernoch den Wert von Value zurück, wenn ich ValueFirst aufgerufen habe. Das liegt daran, daß der Zeiger auf den kernel vom Typ "Kernel" ist und nicht "KernelB", obwohl die Instanz von kernel in der Realität vom Typ "KernelB" ist.
Jetzt nochmal die Frage: kann man nicht irgendwie (ohne expliziten Cast) die Methode vom Typ des instanzierten Objekts aufrufen ?
Ich würde mir sowas wie ":::ValueFirst (x,y);" wünschen.

PS:
DPG Frühjahrstagung 2005

[ Dieser Beitrag wurde von _PAB_ am 23.02.2005 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

23.02.2005, 15:38 Uhr

Solar
Posts: 3680
Nutzer
Zitat:
Original von _PAB_:

So, wähle ich typ = 1 geht alles klar, weil die Methode ValueFirst nicht überschrieben ist und von der Mutter-Klasse verwendet wird.
Wähle ich dagegen typ = 2 bekomme ich immernoch den Wert von Value zurück, wenn ich ValueFirst aufgerufen habe. Das liegt daran, daß der Zeiger auf den kernel vom Typ "Kernel" ist und nicht "KernelB", obwohl die Instanz von kernel in der Realität vom Typ "KernelB" ist.


Das liegt primär mal daran, daß ValueFirst in Kernel nicht virtuell ist...

Zitat:
Jetzt nochmal die Frage: kann man nicht irgendwie (ohne expliziten Cast) die Methode vom Typ des instanzierten Objekts aufrufen ?
Ich würde mir sowas wie ":::ValueFirst (x,y);" wünschen.


Das macht dann... was? Automagisch den tatsächlichen Typ des Objektes ermitteln und die in dieser Klasse überladene Methode aufrufen? Das gibt's schon, und nennt sich virtuelle Methode (siehe Value()...)!

Sorry, aber ich glaube Du bist bei dem einen oder anderen Detail der Klassenvererbung noch auf dem Holzweg...

[ - Antworten - Zitieren - Direktlink - ]

24.02.2005, 16:59 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von _PAB_:
Hier ein einfaches Beispiel:

...
Jetzt nochmal die Frage: kann man nicht irgendwie (ohne expliziten Cast) die Methode vom Typ des instanzierten Objekts aufrufen ?

In dem Du "virtual" benutzt. Genau dafür ist es ja da. (Ich weiß, ich wiederhole mich). Wenn bei Dir, wie Du sagst "virtual" ein Problem macht, dann poste doch ein Beispiel, mit dem dieses Problem reproduziert werden kann.
Dann können wir auch herausfinden, wie die Lösung aussieht.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

08.03.2005, 17:42 Uhr

_PAB_
Posts: 3016
Nutzer
Ich kann "ValueFirst" nicht als virtual definieren (Gründe siehe auch oben), da es generell in allen abgeleiteten Klassen "Value" aufrufen soll. Nur in einigen ganz speziellen Klassen soll "ValueFirst" etwas anderes machen. Auch will ich nicht in jeder abgeleiteten Klasse "ValueFirst" immer gleichlautend implementieren müssen (was ich bei der virtual-Definition tun müßte).

Das Problem ist, daß der Zeiger auf das instanzierte Objekt vom allgemeinen Typ "Kernel *" ist und daß ohne die virtual-Definition immer die ursprüngliche "ValueFirst" aufgerufen wird, egal, ob das instanzierte Objekt, auf welches der Zeiger zeigt nun ein "KernelX" oder "KernelY" ist.

Nochmal die Frage:
Kann man nicht irgendwie die Methoden der real instanzierten Klasse aufrufen, auch wenn man einen Zeiger auf den allgemeinen Typ der Mutter-Klasse hat ?

@Holger:
Das Beispiel steht haargenau da.
Mache ich im Hauptprogramm ein:
kernel.ValueFirst (x, y);
bekomme ich bei typ = 2 immernoch den Wert von x*y und nicht 1.0 zurück.


[ Dieser Beitrag wurde von _PAB_ am 08.03.2005 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

08.03.2005, 19:02 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von _PAB_:
Ich kann "ValueFirst" nicht als virtual definieren (Gründe siehe auch oben), da es generell in allen abgeleiteten Klassen "Value" aufrufen soll. Nur in einigen ganz speziellen Klassen soll "ValueFirst" etwas anderes machen. Auch will ich nicht in jeder abgeleiteten Klasse "ValueFirst" immer gleichlautend implementieren müssen (was ich bei der virtual-Definition tun müßte).

Wovon zur Hölle redest Du?
Schreib einfach "virtual" vor die Deklaration und ändere _nichts anderes_ an Deinem Code. Wo is jetzt das Problem?
Zitat:
@Holger:
Das Beispiel steht haargenau da.
Mache ich im Hauptprogramm ein:
kernel.ValueFirst (x, y);
bekomme ich bei typ = 2 immernoch den Wert von x*y und nicht 1.0 zurück.

Nein, Du hast gesagt, dass es ein Problem geben würde, wenn Du "virtual" hinschreiben würdest. Es steht aber nicht da. Wenn ich es hinschreiben würde, entsteht kein Problem. Also sieht Dein Code, bei dem der Compiler Probleme macht, anders aus.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

09.03.2005, 10:03 Uhr

Solar
Posts: 3680
Nutzer
Zitat:
Original von _PAB_:
Ich kann "ValueFirst" nicht als virtual definieren (Gründe siehe auch oben), da es generell in allen abgeleiteten Klassen "Value" aufrufen soll. Nur in einigen ganz speziellen Klassen soll "ValueFirst" etwas anderes machen.


Genau dafür ist "virtual" da.

Zitat:
Auch will ich nicht in jeder abgeleiteten Klasse "ValueFirst" immer gleichlautend implementieren müssen (was ich bei der virtual-Definition tun müßte).

Blödsinn. Das Kapitel zu "virtual" nochmal durchlesen - Du verwechselst anscheinend virtual foo() mit virtual foo() = 0!

Zitat:
Das Problem ist, daß der Zeiger auf das instanzierte Objekt vom allgemeinen Typ "Kernel *" ist und daß ohne die virtual-Definition immer die ursprüngliche "ValueFirst" aufgerufen wird, egal, ob das instanzierte Objekt, auf welches der Zeiger zeigt nun ein "KernelX" oder "KernelY" ist.

So ist das nun einmal bei nicht-virtuellen Funktionen.

Zitat:
Nochmal die Frage:
Kann man nicht irgendwie die Methoden der real instanzierten Klasse aufrufen, auch wenn man einen Zeiger auf den allgemeinen Typ der Mutter-Klasse hat ?


Ja, indem man die Funktion als "virtual" deklariert.

*kopfschüttel*

[ - Antworten - Zitieren - Direktlink - ]

09.03.2005, 17:23 Uhr

_PAB_
Posts: 3016
Nutzer
Hmm, bisher habe ich immer die Fehlermeldung:

Kernel.o(.gnu.linkonce.r._ZTV9Kernel+0x18):Kernel.cpp:21: undefined reference to 'Kernel::ValueFirst(unsigned, unsigned)'

erhalten, wenn ich virtual versucht habe, aber jetzt bei einem erneuten Versuch hat es einwandfrei funktioniert. Sorry wegen der Umstände und Danke für die Hilfe !

@Solar:
Der Unterschied zwischen virtual und der Nullfunktion ist mir bekannt.

[ - Antworten - Zitieren - Direktlink - ]

09.03.2005, 18:24 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von _PAB_:
Hmm, bisher habe ich immer die Fehlermeldung:

Kernel.o(.gnu.linkonce.r._ZTV9Kernel+0x18):Kernel.cpp:21: undefined reference to 'Kernel::ValueFirst(unsigned, unsigned)'

erhalten, wenn ich virtual versucht habe, aber jetzt bei einem erneuten Versuch hat es einwandfrei funktioniert. Sorry wegen der Umstände und Danke für die Hilfe !

Freut mich, daß es jetzt bei Dir funktioniert.
Trotzdem ein Tip für die Zukunft:
Versuch Dich auf das eigentliche Problem zu konzentrieren.
Wenn Du einen Linker-Fehler bekommst, versuch die Ursache für den Linker-Fehler zu finden, meinetwegen poste auch hier in der Form "hallo, folgender Code erzeugt einen Linker-Fehler...., woran könnte es liegen?".
Aber versuch nicht daraus irgendwelche irren Annahmen über die Programmiersprache C++ zu entwickeln und den Code umzuschreiben, um danach hier zu fragen, wie man jetzt das ursprüngliche Programm wiederherstellen kann, ohne die Programmiersprache so zu nutzen, wie sie eigentlich gedacht ist. Dann kann Dir auch keiner helfen.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

10.03.2005, 08:59 Uhr

Solar
Posts: 3680
Nutzer
Zitat:
Original von _PAB_:

@Solar:
Der Unterschied zwischen virtual und der Nullfunktion ist mir bekannt.


Dann solltest Du auch wissen, daß Du eine Funktion, die in der Basisklasse virtuell definiert ist, mitnichten in abgeleiteten Klassen nochmal nachimplementieren mußt.

[ - Antworten - Zitieren - Direktlink - ]


-1- [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > C++: Klassen "dynamisch" laden [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.