www.mikrocontroller.net

Forum: PC-Programmierung C++ rein virtuelle Funktionen implementieren


Autor: Christoph S. (mixer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich habe eine Basisklasse:
class Basis{
public:
  virtual int get(void)=0;
  virtual void put(int)=0;
};
und eine abgeleitete Klasse:
class Neu: public Basis{
int a;
};
Wenn ich jetzt z.B. die Funktion get für die abgeleitete Klasse 
implementieren will, dann geht das über
int Neu::get(void){
return a;
}
nicht. Laut g++ gibts keine Funktion get in Neu.

Wie muss ich also diese Funktion implementieren?


MFG Mixer

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Funktion in die Deklaration der abgeleitete Klasse neu 
reinschreiben:
class Neu: public Basis{
  int a;
public:
  virtual int get(void);
};

Autor: Christoph S. (mixer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

was bringt dann die virtuelle Funktion in der Basisklasse?
Glaub ich steh grad auf m Schlauch...

MFG Mixer

Autor: Sebastian Hepp (sebihepp)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>was bringt dann die virtuelle Funktion in der Basisklasse?

Nur damit geht der Polymorphismus

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mixer S. schrieb:

> was bringt dann die virtuelle Funktion in der Basisklasse?
> Glaub ich steh grad auf m Schlauch...

Bei einer Datenstruktur wie beispielsweise einer Liste, deren 
verschiedenartige Elemente alle von "Basis" abgeleitet sind, kannst du 
über diese Liste nur auf Funktionen zugreifen, die in "Basis" deklariert 
wurden.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mixer S. schrieb:
> Hallo,
>
> was bringt dann die virtuelle Funktion in der Basisklasse?

Auch die Basisklasse kann ja seine eigenen Vorstellungen davon haben, 
wie die Funktion get() zu implementieren ist.

class Neu: public Basis{
int a;
};
> Wenn ich jetzt z.B. die Funktion get für die abgeleitete Klasse
> implementieren will nicht. Laut g++ gibts keine Funktion get in Neu.

Recht hat er. In der Klasse Neu gibts tatsächlich keine eigene Funktion 
get(). Die Klasse Neu würde die Funktion aus Basis erben, wenn du nichts 
unternimmst. Wenn du aber willst, dass Neu seine eigene Version von 
get() hat, dann musst du das auch bekannt geben (in Form der Deklaration 
in der Klasse).

Alles was nicht explizit in einer abgeleiteten Klasse in der Deklaration 
drinnen steht, wird stillschweigend von der Basisklasse geerbt und 
bleibt so, wie es die Basisklasse vorgegeben hat.

Autor: Christoph S. (mixer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Recht hat er. In der Klasse Neu gibts tatsächlich keine eigene Funktion
> get(). Die Klasse Neu würde die Funktion aus Basis erben, wenn du nichts
> unternimmst. Wenn du aber willst, dass Neu seine eigene Version von
> get() hat, dann musst du das auch bekannt geben (in Form der Deklaration
> in der Klasse).

Dann gibts z.B. rein virtuelle Methoden nur, damit man eine abgeleitete 
Klasse dazu zwingt diese zu implementieren?

MFG Mixer

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mixer S. schrieb:

> Dann gibts z.B. rein virtuelle Methoden nur, damit man eine abgeleitete
> Klasse dazu zwingt diese zu implementieren?

Richtig.

Autor: Markus K. (inok)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey,

aber man muss doch nicht die Methode in der abgeleiteten Klasse (class 
Neu : public Basis) auch als virtual deklarieren, oder irre ich mich da?
Nur wenn diese Methode von einer weiteren Klasse (z.B. class GanzNeu : 
public Neu) eigens implementiert werden soll/kann.

Gru0
inok

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus K. schrieb:
> aber man muss doch nicht die Methode in der abgeleiteten Klasse (class
> Neu : public Basis) auch als virtual deklarieren

Musst du nicht; eine Methode ist virtuell in allen abgeleiteten
Klassen, sobald sie es in einer Basis ist.
Aber es erhöht die Lesbarkeit der abgeleiteten Klasse deutlich, wenn
man es dort auch hinschreibt.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus K. schrieb:
> Nur wenn diese Methode von einer weiteren Klasse (z.B. class GanzNeu :
> public Neu) eigens implementiert werden soll/kann.

Das kann man mit oder ohne virtual, egal wo.

Der Unterschied ist wie schon seinerzeit Sebastian Hepp sagte:
Man braucht es für Polymorphismus.
Solange man ohne auskommt, kann man virtual weglassen.
(Nicht sehr OO-like, kann aber auf Controllern viel Platz und
Laufzeit sparen.)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mixer S. schrieb:

> Dann gibts z.B. rein virtuelle Methoden nur, damit man eine abgeleitete
> Klasse dazu zwingt diese zu implementieren?


Gehts nur mir so?
Klaus, wie machst du das in deinen Kursen?
Nennst du 'pure' Functions im Deutschen 'reine' Funktionen? Wenn man es 
weiß ist es ok, umgangssprachlich hat aber 'rein virtuell' eine 
Doppelbedeutung. So wie 'rein weiß' (also nicht grau) im Gegensatz zu 
'reinem Rot'.
Ich finde die Bezeichnung nicht so glücklich.


Übrigens: Ein weit verbreiteter Irrtum besteht darin anzunehmen, dass 
pure Functions keine Implementierung haben können.
class Basis{
public:
  virtual int get() = 0;
  virtual void put( int ) = 0;
};

int Basis::get()
{
  std::cout << "should not be called, but it is ok for now\n";
  return 0;
}

int Basis:put( int i )
{
  std::cout << "should not be called, but it is ok for now\n";
  std::cout << "will do default working\n";
  return 0;
}

Von einer Klasse, die pure Functions enthält und die nicht mit nicht 
puren Functions überschrieben wurden, kann kein Objekt erzeugt werden. 
Das ist alles was pure Functions bewirken. Das impliziert natürlich, 
dass alle pure Functions einer Basisklasse mit nicht-puren Varianten 
spätestens am Ende der Klassenhierarchie überschrieben werden müssen.

Mittels pure Functions baut man sich in C++ zb das auf, was in Java ein 
"Interface" ist. Also eine Basisklasse, die nur einen einzigen Zweck 
hat: Zu definieren, welche Funktionen eine andere Klasse implementieren 
muss, um als von einem bestimmten Typ zu gelten.

Und noch etwas. Wenn deine Klasse mindestens 1 virtuelle Funktion hat 
(egal ob pure oder nicht), ist das dein deutliches Indiz dafür, dass 
Polymorphismus beabsichtigt ist. In dem Fall ist es eine extrem gute 
Idee, auch einen virtuellen Destruktor zu machen
class Basis{
public:
  virtual ~Basis() {}

  virtual int get() = 0;
  virtual void put( int ) = 0;
};

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Nennst du 'pure' Functions im Deutschen 'reine' Funktionen?

Nein, das halte ich für eine kranke Eindeutschung.

Genau genommen ist es ja in C++ nur eine etwas schrullige Schreibweise
für eine ABC (abstract base class); letztlich spart man sich mit dem
=0 ein neues Schlüsselwort abstract.

Deshalb erkläre ich im Zweifelsfall erst, was eine ABC ist und wozu
man sie brauchen kann.
Dann kann man kurz erwähnen wie es in anderen Sprachen gehandhabt
wird (Schlüsselwort abstract in Java bspw.) und dann nenne ich
ich einfach die Schreibweise in C++.
Ist dann einfach so und fertig.

Dass man dann eine so deklarierte und mit Absicht nicht definierte
Methode pure virtual nennt, ist nur noch der Name für die
Schreibweise. Das Konzept dahinter ist ABC.

Eindeutschen würde ich das pure virtual nicht.
Und wenn schon, wären es nicht "reine Funktionen", sondern
"rein virtuelle Methoden".

Autor: Hermann-Josef (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
@9:26:
>
> Das kann man mit oder ohne virtual, egal wo.
>

ja schon aber es gibt noch einen weiteren Unterschied, ohne das virtual 
wird immer die zur Compile-Zeit bekannte Methode gerufen, sonst eben die 
letzte in der Hierarchie (late binding). Das ist der Vorteil des 
Polymorphismus. Die einzige Ausnahme ist der Konstruktur einer 
Basisklasse, hier ist es nicht möglich, Methoden abgeleiteter Klassen zu 
rufen. Tut man es doch und die Methode der Basis-Klasse ist außerdem 
noch 'pure virtual' (... = 0;), gibt es eine Exception (pure virtual 
method call).

Ich stelle mir das technisch immer so vor, mit dem virtual wird der 
Compiler instruiert, eine Sprungtabelle anzulegen, sobald ein Objekt 
einer abgeleiteten Klasse instanziert wird, werden die Einträge mit der 
jeweils passenden Signatur mit den Adressen der Methoden in der 
abgeleiteten Klasse (so existent) überschrieben.

Gruß
Hermann-Josef

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Karl heinz Buchegger schrieb:
>> Nennst du 'pure' Functions im Deutschen 'reine' Funktionen?
>
> Nein, das halte ich für eine kranke Eindeutschung.

Gut das ich nicht alleine bin.
pure und virtual sind nun mal 2 Konzepte die nichts miteinander zu tun 
haben, auch wenn sie oft gemeinsam verwendet werden. Die deutsche 
Wortschöpfung 'rein virtuell' trägt dem aber nicht Rechnung. 'rein 
virtuell' im Gegensatz zu 'irgendwie anders virtuell'.

Der Schlüssel ist das Verständnis, das pure und virtual 2 
unterschiedliche Paar Schuhe sind. Deinen Ansatz, die Thematik über den 
Begriff der ABC anzugehen finde ich gut.

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Übrigens: Ein weit verbreiteter Irrtum besteht darin anzunehmen, dass
> pure Functions keine Implementierung haben können.
>
>
> class Basis{
> public:
>   virtual int get() = 0;
>   virtual void put( int ) = 0;
> };
> 
> int Basis::get()
> {
>   std::cout << "should not be called, but it is ok for now\n";
>   return 0;
> }
> 
>
> Von einer Klasse, die pure Functions enthält und die nicht mit nicht
> puren Functions überschrieben wurden, kann kein Objekt erzeugt werden.

Äähhh... das heißt doch aber, dass man eine solche Methode niemals 
aufrufen kann, weil man kein Objekt erzeugen kann auf das man sie 
anwenden könnte. Wozu ist dann die Implementierung in der abstrakten 
Basisklasse gut?
Hm, es sei denn vielleicht es gäbe sowas Kurioses wie eine
static virtual void irgendwas() = 0; Methode...

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann für ein Objekt einer abgeleiteten Klasse auch explizit
eine Methode der Basisklasse aufrufen.
Das kann man beispielsweise nutzen, um gemeinsamen Code
dort zu deponieren und z.B. von einer in der Ableitung
re-implementierten Methode aus aufzurufen.
Dazu muß kein Objekt der Basisklasse existieren.

Komplettes Beispiel:
#include <iostream>

class ABC
{
public:
  virtual void tuwas() = 0;
  virtual ~ABC(){}
};

void ABC::tuwas()
{
  std::cout << "ABC tut nix" << std::endl;
}

class DEF: public ABC
{
public:
  virtual void tuwas()
  {
    ABC::tuwas();
    std::cout << "DEF tut was!" << std::endl;
  }
};


int main( int nargs, char **args )
{
  DEF    einDEF;
  einDEF.tuwas();
}

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ich aber nicht weiß ist: wie bekommt man die Definition von
ABC::tuwas in die Klasse selbst rein (also nicht außerhalb, wie
oben geschrieben sondern innerhalb der class, ähnlich wie
DEF::tuwas())?

Hat da jemand eine Idee?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
class ABC
{
public:
  virtual void tuwas() = 0
  {
    std::cout << "ABC tut nix" << std::endl;  
  }
  virtual ~ABC(){}
};

@Mark
Das eine pure Funktion eine Implementierung haben kann und wozu man 
sowas brauchen kann hat Klaus ja schon aufgezeigt.
Aber es geht auch noch viel banaler:
Will man eine Klasse einfach nur pure haben, dann macht man gerne den 
Destruktor pure. Aber jede Klasse hat immer einen Destruktor :-)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Tip, aber das hatte ich natürlich schon probiert:
t.cpp:6: error: pure-specifier on function-definition
(in der Zeile mit dem =0)

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Was ich aber nicht weiß ist: wie bekommt man die Definition von
> ABC::tuwas in die Klasse selbst rein (also nicht außerhalb, wie
> oben geschrieben sondern innerhalb der class, ähnlich wie
> DEF::tuwas())?

Geht nicht. Steckt als Notiz zwischen zwei Beispielen im Standard 
("Note: a function declaration cannot provide both a pure-specifier and 
a definition"), ausserdem in der Grammatik-Zusammenfassung im Anhang 
ersichtlich.

Karl heinz Buchegger schrieb:
> Übrigens: Ein weit verbreiteter Irrtum besteht darin anzunehmen, dass
> pure Functions keine Implementierung haben können.

Auch nicht besonders "intuitiv", aber erlaubt:
struct A {
        virtual void M();
};

void A::M() { }

struct B : public A {
        virtual void M() = 0;
};

Andreas

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Ferber schrieb:
> Geht nicht.

Danke!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Ferber schrieb:

> Geht nicht.

Dann hab ich eine Erweiterung im VC++ entdeckt.
Habs natürlich vorher ausprobiert und der VC++ machts

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Offenbar.

Dieser Quelltext:
#include <iostream>

class Basis
{
public:
  virtual int Basis::get() = 0   // hier Fehler!!!!!!!!!!!!
  {
    std::cout << "should not be called, but it is ok for now\n";
    return 0;
  }
};

class Abl : public Basis
{
public:
  virtual int get()
  {
    Basis::get();
    std::cout << "Hols dir doch selber!" << std::endl;
    return 0;
  }
};


int main( int nargs, char **args )
{
  Abl    abl;
  abl.get();

  return 0;
}
kompiliert in VC++ (VS2005) anstandslos, der g++ spuckt dazu aus:
get.cpp:6: error: pure-specifier on function-definition
get.cpp:6: error: extra qualification ‘Basis::’ on member ‘get’

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.