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


von Christoph S. (mixer) Benutzerseite


Lesenswert?

Hallo,

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

Wie muss ich also diese Funktion implementieren?


MFG Mixer

von (prx) A. K. (prx)


Lesenswert?

Die Funktion in die Deklaration der abgeleitete Klasse neu 
reinschreiben:
1
class Neu: public Basis{
2
  int a;
3
public:
4
  virtual int get(void);
5
};

von Christoph S. (mixer) Benutzerseite


Lesenswert?

Hallo,

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

MFG Mixer

von Sebastian H. (sebihepp)


Lesenswert?

>was bringt dann die virtuelle Funktion in der Basisklasse?

Nur damit geht der Polymorphismus

von (prx) A. K. (prx)


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.

von Karl H. (kbuchegg)


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.

1
class Neu: public Basis{
2
int a;
3
};
> 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.

von Christoph S. (mixer) Benutzerseite


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

von (prx) A. K. (prx)


Lesenswert?

Mixer S. schrieb:

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

Richtig.

von Markus K. (inok)


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

von Klaus W. (mfgkw)


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.

von Klaus W. (mfgkw)


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

von Karl H. (kbuchegg)


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.
1
class Basis{
2
public:
3
  virtual int get() = 0;
4
  virtual void put( int ) = 0;
5
};
6
7
int Basis::get()
8
{
9
  std::cout << "should not be called, but it is ok for now\n";
10
  return 0;
11
}
12
13
int Basis:put( int i )
14
{
15
  std::cout << "should not be called, but it is ok for now\n";
16
  std::cout << "will do default working\n";
17
  return 0;
18
}

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
1
class Basis{
2
public:
3
  virtual ~Basis() {}
4
5
  virtual int get() = 0;
6
  virtual void put( int ) = 0;
7
};

von Klaus W. (mfgkw)


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

von Hermann-Josef (Gast)


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

von Karl H. (kbuchegg)


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.

von Mark B. (markbrandis)


Lesenswert?

Karl heinz Buchegger schrieb:
> Übrigens: Ein weit verbreiteter Irrtum besteht darin anzunehmen, dass
> pure Functions keine Implementierung haben können.
>
>
1
> class Basis{
2
> public:
3
>   virtual int get() = 0;
4
>   virtual void put( int ) = 0;
5
> };
6
> 
7
> int Basis::get()
8
> {
9
>   std::cout << "should not be called, but it is ok for now\n";
10
>   return 0;
11
> }
12
>
>
> 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...

von Klaus W. (mfgkw)


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:
1
#include <iostream>
2
3
class ABC
4
{
5
public:
6
  virtual void tuwas() = 0;
7
  virtual ~ABC(){}
8
};
9
10
void ABC::tuwas()
11
{
12
  std::cout << "ABC tut nix" << std::endl;
13
}
14
15
class DEF: public ABC
16
{
17
public:
18
  virtual void tuwas()
19
  {
20
    ABC::tuwas();
21
    std::cout << "DEF tut was!" << std::endl;
22
  }
23
};
24
25
26
int main( int nargs, char **args )
27
{
28
  DEF    einDEF;
29
  einDEF.tuwas();
30
}

von Klaus W. (mfgkw)


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?

von Karl H. (kbuchegg)


Lesenswert?

1
class ABC
2
{
3
public:
4
  virtual void tuwas() = 0
5
  {
6
    std::cout << "ABC tut nix" << std::endl;  
7
  }
8
  virtual ~ABC(){}
9
};

@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 :-)

von Klaus W. (mfgkw)


Lesenswert?

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

von Andreas F. (aferber)


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:
1
struct A {
2
        virtual void M();
3
};
4
5
void A::M() { }
6
7
struct B : public A {
8
        virtual void M() = 0;
9
};

Andreas

von Klaus W. (mfgkw)


Lesenswert?

Andreas Ferber schrieb:
> Geht nicht.

Danke!

von Karl H. (kbuchegg)


Lesenswert?

Andreas Ferber schrieb:

> Geht nicht.

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

von Klaus W. (mfgkw)


Lesenswert?

Offenbar.

Dieser Quelltext:
1
#include <iostream>
2
3
class Basis
4
{
5
public:
6
  virtual int Basis::get() = 0   // hier Fehler!!!!!!!!!!!!
7
  {
8
    std::cout << "should not be called, but it is ok for now\n";
9
    return 0;
10
  }
11
};
12
13
class Abl : public Basis
14
{
15
public:
16
  virtual int get()
17
  {
18
    Basis::get();
19
    std::cout << "Hols dir doch selber!" << std::endl;
20
    return 0;
21
  }
22
};
23
24
25
int main( int nargs, char **args )
26
{
27
  Abl    abl;
28
  abl.get();
29
30
  return 0;
31
}
kompiliert in VC++ (VS2005) anstandslos, der g++ spuckt dazu aus:
1
get.cpp:6: error: pure-specifier on function-definition
2
get.cpp:6: error: extra qualification ‘Basis::’ on member ‘get’

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.