mspgcc C++ rein virtuelle Methoden

Gast #720185
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
Gast #720277
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.
Gast #720282
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
Gast #720300
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!
Gast #720602
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...
#720643
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?
Gast #720673
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
#720699
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.
#720715
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.
#720734
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.
#720793
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.
Gast #720827
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
Gast #720832
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.
Gast #720907
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.
Gast #720915
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren