Forum: Compiler & IDEs mspgcc C++ rein virtuelle Methoden


von Maddin (Gast)


Lesenswert?

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ß.

von Oliver (Gast)


Lesenswert?

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

von MBtechler (Gast)


Lesenswert?

Das liegt daran, daß es für avr-g++ keine libsupc++ gibt. Versuche mal, 
diese Funktion als leere Funktion mit extern "C" zu definieren.

von Maddin (Gast)


Lesenswert?

@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.

von mork (Gast)


Lesenswert?

>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

von Maddin (Gast)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

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!

von Maddin (Gast)


Lesenswert?

Hm, also irgendwie klappt das nicht. Ich habe folgende Oberklasse:
1
class Stringbuffer
2
{
3
public:  
4
  char buffer[BUFSIZE];
5
  int act_position;
6
  char * bufp;
7
  virtual void flush() = 0;
8
  Stringbuffer ( );
9
  void put (char c );
10
};
mit einer Implementierung von put():
1
void Stringbuffer::put (char c ) {
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
void RS232::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...

von Oliver (Gast)


Lesenswert?

[c]if(bufp - buffer == (BUFSIZE - 1)) this->flush();8]

Oliver

von Oliver (Gast)


Lesenswert?

arrgh

Nochmal:
1
if(bufp - buffer == (BUFSIZE - 1)) this->flush();
Oliver

von Karl H. (kbuchegg)


Lesenswert?

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?

von Oliver (Gast)


Lesenswert?

Und nochmal:

Polymorphismus funktioniert nur beim Zugriff über Pointer.
1
void Stringbuffer::put (char c ) {
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.
1
void Stringbuffer::put (char c ) {
2
  if(bufp - buffer == (BUFSIZE - 1)) this->flush();
3
  *bufp++ = c;
4
}
hat den benötigten Pointer, und sollte funktionieren.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Oliver wrote:
> Und nochmal:
>
> Polymorphismus funktioniert nur beim Zugriff über Pointer.

oder Referenzen

>
>
1
void Stringbuffer::put (char c ) {
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
void Stringbuffer::put (char c ) {
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.

von Maddin (Gast)


Angehängte Dateien:

Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
class Stringbuffer
2
{
3
public:  
4
  char buffer[BUFSIZE];
5
  int act_position;
6
  char * bufp;
7
8
  virtual void flush() = 0   { // Ooops, should never be called }
9
  Stringbuffer ( );
10
  void put (char c );
11
};
Du die Funktion zwar pure machst, aber trotzdem eine
Implementierung dafür angibst.

von Maddin (Gast)


Lesenswert?

Meinst du so:
virtual void flush(){};
?
Das funktioniert auch nicht.

von Maddin (Gast)


Lesenswert?

Achso Moment, im Header = 0 lassen, und zusätzlich eine leere 
Implementation?

von Maddin (Gast)


Lesenswert?

Fehler beim linken:
undefined reference to `__cxa_pure_virtual'

von Karl H. (kbuchegg)


Lesenswert?

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.
1
class a
2
{
3
  public:
4
    virtual void foo();
5
    void bar();
6
};
7
8
void a::foo()
9
{
10
   // mach was, zb eine LED ein
11
}
12
13
void a::bar()
14
{
15
  foo();
16
}
17
18
class b : public a
19
{
20
  public:
21
    virtual void foo();
22
};
23
24
void b::foo()
25
{
26
  // mach was anderes, zb eine andere LED
27
}
28
29
int main()
30
{
31
  b myB;
32
33
  myB.bar();
34
}

Im Endeffekt muss b::foo() aufgerufen werden.

von Maddin (Gast)


Lesenswert?

Hm, wenn ich das RS232 Objekt nicht global, sondern lokal in main() 
erzeuge, dann kann er auch das flush() aufrufen...

von Maddin (Gast)


Lesenswert?

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??

von Karl H. (kbuchegg)


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

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.

von Maddin (Gast)


Lesenswert?

Ich glaube das Problem liegt daran, dass die Konstruktoren von globalen 
Objekten im Startup Code nicht aufgerufen werden.

von Maddin (Gast)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Maddin (Gast)


Lesenswert?

Mit leerer libstdc++.a klappt das linken mit dem msp430-g++, aber 
offensichtlich wird der Konstruktor dennoch nicht ausgeführt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.