Hallo.
Kann ich den Kompiler irgendwie überzeugen rein virtuelle Methoden zu
zulassen, die erst in einer Unterklasse deklariert werden?
also: virtual void test() = 0;
Der Linker meckert nämlich: " undefined reference to
`__cxa_pure_virtual' "
Gruß.
Wieso willst du den Compiler überzeugen, wenn doch der Linker meckert?
Wenn der so meckert, fehlt irgendwo die nicht-virtuelle Methode in einer
Unterklasse. Virtuell linken kann der Linker nicht.
Oliver
@MBtechler: Danke für die Antwort, ich habe mir schon so etwas gedacht.
Als extern "C" wär eine Möglichkeit, löst aber mein Problem
wahrscheinlich nicht, da ich die virtuell deklarierte Methode in der
Oberklasse benutze, und zwei verschiedene Klassen mit unterschiedlichen
Implementierungnen der virtuellen Methoden existieren. Eventuell kann
ich das Problem aber mit einem Funktionszeiger umgehen.
>löst aber mein Problem>wahrscheinlich nicht, da ich die virtuell deklarierte Methode in der>Oberklasse benutze, und zwei verschiedene Klassen mit unterschiedlichen>Implementierungnen der virtuellen Methoden existieren. Eventuell kann>ich das Problem aber mit einem Funktionszeiger umgehen.
Wer hat Dir denn gesagt, dass Du keine virtuellen Methoden nutzen
kannst? '__cxa_pure_virtual' ist die Funktion, die angesprungen wird,
wenn duch einen Programmfehler eine rein virtulle ausgeführt wird. Da es
aber normaleweise nciht der Fall ist, sollte es keine Probleme geben,
wenn man diese einfach als extern "C" void __cxa_pure_virtual(){}
definiert
MfG Mark
Achso, jetzt wird es mir etwas klarer. Ich schau mir die Sache morgen
nochmal in Ruhe an, hab jetzt keinen Zugriff auf den Code. (vielleicht
hab ich wirklich einfach nur vergessen die virtuelle Methode in der
Unterklasse zu implementieren; bin heute den ganzen Tag schon etwas
verpeilt :)
Danke für die Hinweise!
Und wenn das nicht geht, dann kannst du der pure-virtuell
Funktion immer noch eine Implementierung verpassen.
pure heist nicht, dass die Funktion keine Implementierung
haben kann!
Hm, also irgendwie klappt das nicht. Ich habe folgende Oberklasse:
1
classStringbuffer
2
{
3
public:
4
charbuffer[BUFSIZE];
5
intact_position;
6
char*bufp;
7
virtualvoidflush()=0;
8
Stringbuffer();
9
voidput(charc);
10
};
mit einer Implementierung von put():
1
voidStringbuffer::put(charc){
2
if(bufp-buffer==(BUFSIZE-1))flush();
3
*bufp++=c;
4
}
und hier kommt eben das flush() vor, das erst in Unterklassen den Puffer
unterschiedlich an unterschiedliche Ausgabegeräte leeren soll.
eine z.B. die RS232 Schnittstelle:
class RS232 : public Stringbuffer
{
public:
RS232 ( );
void flush ( );
void print(char * text, int length);
};
1
voidRS232::flush(){
2
print(buffer,bufp-buffer);
3
bufp=buffer;
4
}
Mit extern "C" void __cxa_pure_virtual(){} kann ich zwar kompilieren,
beim Aufruf von flush springt er aber ins Leere (call @r14 ; wobei r14 =
0)
Mit einer leeren Implementierung von flush (virtual void flush(){};)
passiert dasselbe.
Vielleicht sollte ich doch lieber in C weitermachen...
Maddin wrote:
> Mit extern "C" void __cxa_pure_virtual(){} kann ich zwar kompilieren,> beim Aufruf von flush springt er aber ins Leere (call @r14 ; wobei r14 => 0)>
Schwer zu sagen, mit nur diesem Ausschnitt.
Du hast nicht zufällig irgendwo einen Fall von Slicing.
Slicing wäre, wenn du dein RS232 Objekt irgendwo irrtümlich
auf ein Stringbuffer Objekt zurück-castest. Also zb so was
void foo( Stringbuffer Output )
{
...
Output.flush();
}
Der Fehler ist hier die vergessene Referenz in der Argumentliste
void foo( Stringbuffer& Output )
{
...
Output.flush();
}
> Mit einer leeren Implementierung von flush (virtual void flush(){};)> passiert dasselbe.
leere Implementierung in welcher Klasse? Stringbuffer oder RS232
>> Vielleicht sollte ich doch lieber in C weitermachen...
Stell mal ein Minimalbeispiel nur mit diesen beiden Klassen
zusammen, damit man mal handfesten Code hat. Ich kann mir
nicht vorstellen, dass der Compiler/Linker virtuelle Funktionen
nicht richtig hinkriegst.
Was ist, wenn du die Funktion nicht pure machst?
Oliver wrote:
> Und nochmal:>> Polymorphismus funktioniert nur beim Zugriff über Pointer.
oder Referenzen
>>
1
voidStringbuffer::put(charc){
2
>if(bufp-buffer==(BUFSIZE-1))flush();
3
>*bufp++=c;
4
>}
> geht nicht. Da wird die Methode flush von Stringbuffer aufgerufen, und> die gibt es eben nicht, da virtuell.
Wo hast du denn den Unsinn her?
>>
1
voidStringbuffer::put(charc){
2
>if(bufp-buffer==(BUFSIZE-1))this->flush();
3
>*bufp++=c;
4
>}
> hat den benötigten Pointer, und sollte funktionieren.
Auch in der Originalversion ist der Pointer vorhanden.
flush();
ist implizit für
this->flush();
macht also keinen Unterschied.
Ich habe den Quellcode mal angehängt. Es sollen ein paar
Ausgabefunktionen der IO Stream Bibliothek nachgebaut werden...
Die Vererbungshierarchie ist Stringbuffer <- O_Stream <- RS232
OK.
Das Programm ist soweit in Ordnung.
Das der Compiler mit virtuellen Funktionen grundsätzlich
nicht klar kommt halte ich für eher unwahrscheinlich. Vielleicht
irgendein Compilerswitch?
Nochmal die Frage: Hast du schon mal versucht was passiert,
wenn du flush() nicht pure machst?
Oder so:
1
classStringbuffer
2
{
3
public:
4
charbuffer[BUFSIZE];
5
intact_position;
6
char*bufp;
7
8
virtualvoidflush()=0{// Ooops, should never be called }
9
Stringbuffer();
10
voidput(charc);
11
};
Du die Funktion zwar pure machst, aber trotzdem eine
Implementierung dafür angibst.
Maddin wrote:
> Meinst du so:> virtual void flush(){};> ?> Das funktioniert auch nicht.
Schlecht.
OK. Zeit für ein minimalistisches Testprogramm.
Kannst du mal folgendes durch den Compiler jagen.
Ja, mit lokal angelegtem Objekt funktioniert der Code wunderbar.
Wie bekomm ich nun das Objekt global zugänglich?
Lokal in main() anlegen, und globaler Zeiger darauf??
Maddin wrote:
> Ja, mit lokal angelegtem Objekt funktioniert der Code wunderbar.
Mehr als seltsam.
>> Wie bekomm ich nun das Objekt global zugänglich?> Lokal in main() anlegen, und globaler Zeiger darauf??
Ist ne Möglichkeit.
Zwar nicht schön, aber der Zweck heiligt ... und so.
Ok, das mit dem this war Blödsinn.
Aber dann noch eine dumme Frage:
Hat der msp-430-gcc eine vollständige libg++?
Etwas googlen findet:
>g++ v3.x generates references to a function __cxa_pure_virtual()>whenever the code contains pure virtual functions. This is a>placeholder used while constructing an object, and the function>should never actually get called. There is a default>implementation in libsupc++ ...
Egal, gibt man ihm im main.cpp mit
1
extern"C"void__cxa_pure_virtual(){}
das, was er anmeckert, linkt er zumindest ohne Fehler. Ob es dann auch
läuft, kann ich nicht probieren.
Oliver
Womit linkst du? Mit gcc oder mit g++? Es muß g++ sein.
Kann auch ein Compiler-Problem sein. Ich kenne mich mit dem mspgcc nicht
so aus. Evtl wird der Startup-Code für den Aufruf der Konstruktoren bei
globalen Variablen nicht generiert. So klingt es jetzt zumindest für
mich.
Ups sorry den letzten Post bitte vergessen, hab den vorhin getippt,
vergessen abzuschicken, und gerade auf Absenden geklickt...
Ja richtig ich linke mit dem msp430-gcc, da ich mit msp430-g++ das
Problem habe, dass er die libstdc++ einbinden will, die es nicht gibt.
(msp430-ld: cannot find -lstdc++)
Gibt es da evtl ein g++ Flag, mit dem er nicht probiert diese Lib
einzubinden.
> Ja richtig ich linke mit dem msp430-gcc, da ich mit msp430-g++ das> Problem habe, dass er die libstdc++ einbinden will, die es nicht gibt.
Scheinbar ist der msp430-g++ noch schlechter gewartet als der für den
avr. Dort wird die nicht existente libstdc++ und libsupc++ per default
wenigstens nicht gelinkt.
> (msp430-ld: cannot find -lstdc++)> Gibt es da evtl ein g++ Flag, mit dem er nicht probiert diese Lib> einzubinden.
Es gibt -nostdlib, aber ich glaube, das beinhaltet auch die
C-Standardlib. Du könntest versuchen, eine leere Datei mit dem Namen
libstdc++.a im Verzeichnis deines Programms anzulegen und - falls noch
nicht vorhanden - ein -L. an die Linker-Kommandozeile hängen.