Vererbung, abstrakte Klassen und virtuelle Funktionen

Hallo,

ich bin gerade dabei C++ zu lernen und versuche zu begreifen wie Interfaces in dieser Sprache definiert und benutzt werden. Jedoch bin ich bis jetzt kläglich gescheitert. D.h. ich sehe meinen Fehler einfach nicht.
Angenommen ich habe die Klasse PersistierungsIntArtikel, die das Interface mit Hilfe von virtuellen Funktionen abbildet (abstrakte Klasse mit Funtkionen wie: virtual void tuWas(void) =0;). Dann habe ich noch die Klasse PersistIntAdapt Artikel, die das Interface durch Vererbung implementiert.
Doch wie rufe ich diese auf? Ich komme aus der Java Welt und bin da anscheinend etwa verwirrt.
Hier ein Beispiel mit Code.

Die Header Datei des Interfaces:
Code:
#ifndef PersisiterungsIntArtikel_h
#define PersisiterungsIntArtikel_h
#include <vcl.h>

class PersistierungsIntArtikel 
{

public:
        virtual AnsiString Reserviere(AnsiString text) =0 ; 

};
#endif

----------------------------------------------------------------------------------------------------

Die Header Datei der Datei, die das Interface implementiert:

Code:
#ifndef PersistIntAdaptArtikel_h
#define PersistIntAdaptArtikel_h
#include "PersistierungsIntArtikel.h"
#include <vcl.h>

class PersistIntAdaptArtikel : PersistierungsIntArtikel {
         public: 
                AnsiString  Reserviere(AnsiString text);
};
#endif

----------------------------------------------------------------------------------------------------

Die zugehörige C++ Datei

Code:
#include "PersistierungsIntArtikel.h"
#include "PersistIntAdaptArtikel.h"
#include <vcl.h>

AnsiString PersistIntAdaptArtikel::Reserviere(AnsiString text)
{
        //...tu irgendwas...
        return "rueckgabe";
}

-----------------------------------------------------------------------------------------------------

Nun wird interessant. Wie spreche ich nun die Klasse PersistIntAdaptArtikel über das Interface PersistierungsIntArtikel an? Vielleicht habe ich da was mit den Zeigern nicht verstanden? Muss ich den "new" Operator benutzen? Oder ist das Überschreiben der Methode in dem Header der Klasse PersistIntAdaptArtikel schon falsch? Warum muss ich beim Überschreiben die Klasse des Interfaces angeben?

So geht das Aufrufen der Klasse jedenfalls nicht:

Code:
PersistierungsIntArtikel pIntA;

PersistIntAdaptArtikel *pIAA=&pIntA;

piAA->Reserviere("Text");


Könnte mir jemand helfen und einen Tip geben? Ich bin da etwas überfordert.

Viele Grüße,

Jens Hibbeler
 
Hi.

Du kannst keine Instanzen von abstrakten Klassen (Klassen mit rein virtuellen Funktionen) bilden. (erste Zeile in deinem letzten Codeschnipsel)

Code:
PersistIntAdaptArtikel IAA;

PersistierungsIntArtikel& IntA = IAA;
PersistierungsIntArtikel* pIntA = &IAA;

IntA.Reserviere("Text");
pIntA->Reserviere("Text");

Gruß
 
Moin,

Der Fehler liegt hier
Code:
PersistierungsIntArtikel pIntA;

PersistIntAdaptArtikel *pIAA=&pIntA;

piAA->Reserviere("Text");

Funkionieren müsste es mit
Code:
PersistIntAdaptArtikel *pIAA=new PersistIntAdaptArtikel;//Klasse anlegen

piAA->Reserviere("Text");//Klasse benutzen

delete pIAA;//Speicher freigeben nicht vergessen.
Durch die Vererbung werden die richtigen Stukturen aus der Basis klasse automatisch genutzt. Du hast da oben eine Basisklasse angelegt - die übrigens die Funktion Reserviere nicht hat, weil nicht implementiert - und anschliessend versucht das auf die Kind-Klasse umzumünzen. Man könnte höchstens was der Art
Code:
PersistierungsIntArtikel *pIntA = (PersistierungsIntArtikel *) piAA
machen. Das nennt man CAST und , da gilt: Jede abgeleitete Klasse ist auch eine BasisKlasse aber eine Basisklasse ist keine Abgeleitete Klasse.

Hoffe das hilft weiter...

Gruss Michael
 
Hi,

das hat mir sehr geholfen! Danke!
Ich dachte ich müsste das Interface ähnlich wie in Java ansprechen:

Code:
Interface meinInterface=new KlasseDieDasInterfaceImplementiert();

Das ich die virtuelle Methode in dem Header der von dem Interface abgeleiteten Klasse noch einmal definieren muss ist korrekt? Ich dachte durch Vererbung besitzt diese Klasse dann automatisch diese Methode? Oder ist das gerade der Klou?

Viele Grüße,

Jens
 
Virtuelle Funktionen sind nur Deklariert nicht aber Definiert.
Soll heissen: Die BasisKlasse besteht auf der Funktion programmiert diese aber nicht aus

Header BasisKlasse->Eintrag
CPP BasisKlasse->Kein Eintrag

Header AbgelKlasse->Kein Eintrag
CPP AbgelKlasse->Eintrag

Hab das zumindest so in Erinnerung. Schon lang her, das ich das nutzen durfte.

Hier ist noch was falsch:
Code:
Interface meinInterface=new KlasseDieDasInterfaceImplementiert();

Interface != KlasseDieDasInterfaceImplementiert

Da sollte der Compiler böse werden

Richtig ist:
Code:
KlasseDieDasInterfaceImplementiert meinInterface=new KlasseDieDasInterfaceImplementiert;

Im Prinzip kannst du die Basisklasse ganz vergessen, wenn einmal die AbgeleiteteKlasse implementiert ist.

Gruss Michael
 
Jens Hibbeler hat gesagt.:
Ich dachte ich müsste das Interface ähnlich wie in Java ansprechen:

Code:
Interface meinInterface=new KlasseDieDasInterfaceImplementiert();
In Java sind ja alle Variablen Referenzen (außer die primitiven Typen byte, char, int usw.). Das ist in C++ nicht so und wenn du schreibst
Code:
MeineKlasse obj;
dann wird automatisch ein Instanz der entsprechenden Klasse erstellt.

In C++ wird halt extra unterschieden zwischen "normalen" Variablen, Referenzen und Pointern.

Jens Hibbeler hat gesagt.:
Das ich die virtuelle Methode in dem Header der von dem Interface abgeleiteten Klasse noch einmal definieren muss ist korrekt? Ich dachte durch Vererbung besitzt diese Klasse dann automatisch diese Methode? Oder ist das gerade der Klou?
Also erstmal hast du die Methode in dem Header ja gar nicht definiert, sondern nur deklariert. Die Deklaration ist notwendig da du dem Compiler mitteilen mußt das du jetzt die rein virtuelle Funktion der Basisklasse implementieren wirst (es gibt halt keine syntaktische Unterscheidung von Interface und Implementierung wie in Java (abstract class bzw. class / interface und implements). Das könntest du schließlich auch lassen um z.B. noch andere Methoden zu der Klasse hinzuzufügen. Dann wäre allerdings auch die PersistIntAdaptArtikel eine abstrakte Klasse.
 
Zurück