goldeneyes1987 schrieb:> testDevice[0] = &(myDevice);
Das ist eine Anweisung. Sie kann nur innerhalb einer Funktion oder
Methode stehen, was bei dir aber nicht der Fall ist.
Simon K. schrieb:> Eine Zuweisung außerhalb einer Funktion/Methode? Ist das erlaubt?
Nein.
Hi,
warum ist in deiner Basisklasse der Konstruktor "protected"? Die
Subklasse kann doch damit gar nicht auf den Konstruktor der Basisklasse
zugreifen, oder seh ich jetzt was nicht? :)
Gruß
Stefan
Natürlich nicht! Ach man, immer diese Burn Out's :-)
Vielen Dank!
Aber noch eine Frage in diesem Zusammenhang!
In wie weit macht die Kombination von virtual und inline einen Sinn?
goldeneyes1987 schrieb:> In wie weit macht die Kombination von virtual und inline einen Sinn?
Die hat keinen Sinn, denn die tatsächlich zutreffende Methode kann ja
bei late binding zwangsweise erst zur Laufzeit ermittelt werden.
Damit ist es dem Compiler unmöglich, sie bereits zur Compile-Zeit
inline einzufügen.
In Konstruktor und Destruktor schon. Da gilt das late binding nicht.
Abgesehen davon kann ich mir Optimierungen vorstellen, die das sinnvoll
machen. Beispielsweise wenn per Profiling festgestellt wird, dass 95%
der Aufrufe eine bestimmte Implementierung betreffen und der Compiler
entsprechende Zweige einbaut.
Jörg Wunsch schrieb:> goldeneyes1987 schrieb:>> In wie weit macht die Kombination von virtual und inline einen Sinn?>> Die hat keinen Sinn, denn die tatsächlich zutreffende Methode kann ja> bei late binding zwangsweise erst zur Laufzeit ermittelt werden.> Damit ist es dem Compiler unmöglich, sie bereits zur Compile-Zeit> inline einzufügen.
Sofern der Compiler an der Stelle eines Aufrufs den tatsächlichen Typ
erkennen kann, kann er das durchaus inlinen.
A. K. schrieb:> Im Konstruktor schon. Da gilt das late binding nämlich nicht.
Doch, aber in seiner Klassenhierarchie ist es erst bis zu der Klasse, zu
der der Konstruktor gehört, erzeugt, und deshalb arbeitet das late
binding an der Stelle nicht weiter, als bis zu dieser Klasse.
Auch dann, wenn der tatsächliche Datentyp bekannt ist, kann es sinnvoll
sein eine virtual inline zu machen.
void foo()
{
RadioControl i; // an dieser Stelle haben wir es immer mit
// einer RadioControl zu tun
i.fcn();
}
Der Compiler kann hier problemlos inlinen, selbst wenn die Funktion
virtual ist.
Rolf Magnus schrieb:> Doch, aber in seiner Klassenhierarchie ist es erst bis zu der Klasse, zu> der der Konstruktor gehört, erzeugt, und deshalb arbeitet das late> binding an der Stelle nicht weiter, als bis zu dieser Klasse.
Eben. Und da der Compiler an dieser Stelle deshalb genau weiss, welche
Basisklasse welche virtuelle Methode selbst implementiert, kann er die
direkt aufrufen. "late binding" ist das daher nicht.
A. K. schrieb:> Rolf Magnus schrieb:>>> Doch, aber in seiner Klassenhierarchie ist es erst bis zu der Klasse, zu>> der der Konstruktor gehört, erzeugt, und deshalb arbeitet das late>> binding an der Stelle nicht weiter, als bis zu dieser Klasse.>> Eben. Und da der Compiler an dieser Stelle deshalb genau weiss, welche> Basisklasse welche virtuelle Methode selbst implementiert, kann er die> direkt aufrufen. "late binding" ist das daher nicht.
Für Aufrufe direkt aus dem Konstruktor heraus kann der Compiler das
natürlich entsprechend optimieren. Sobald du aber aus dem Konstruktor
eine Funktion aufrufst, die dann wiederum eine virtuelle Membefunktion
des Objekts aufruft, hast du sehr wohl late binding, aber eben nur bis
zu der Klasse, zu der der Konstruktor gehört.
Ich wollte damit nur sagen, daß late binding nicht etwa komplett
abgeschaltet ist, nur wei das Objekt gerade erzeugt oder zerstört wird.
Das wird nämlich oft fälschlicherweise angenommen. Hier noch ein
Beispiel:
Was willst Du eigentlich bezwecken?
Willst Du den Polymorphismus benutzen, um aufgrund einer virtuellen
Basisklasse ein Array anzulegen, dass auf Objekte unterschiedlicher
abgeleiteter Klasse zeigen soll?
Ansonsten habe ich das Thema körperlose Klasse so verstanden, dass man
in den abgeleiteten Klassen die Funktion mit Anweisungen versehen muß.
Das kann man aus Deinem Post nicht erkennen.
goldeneyes1987 schrieb:> virtual void fcn() = 0;
Warum willst Du einer Funktion in der körperlosen Klasse eine Null
zuweisen?
Hattest Du da im Hinterkopf, einen Funktionspointer mit 0 zu
initialisieren. Wenn fcn hier ein Prototyp ist, dann empfiehlt sich eine
void in den Klammern. Muß man nicht, hift aber ungemein.
Die Zuweisung eines Wertes auf einen Funktionsprototypen dürfte der
Compiler nicht akzeptieren.
Hier mal mein Verständnis:
/*#abstrakte Klasse ###########################*/
class IDevice
{
/*Konstruktoren und destruktoren denkt ihr hier euch mal.
Ansonsten gilt die default-Konst / Destruktor. */
public:
void ZeigMal(void);
}
/*#Klasse ###########################*/
clase Bildschirm : IDevice
{
/*Konstruktoren und destruktoren denkt ihr hier euch mal.
Ansonsten gilt die default-Konst / Destruktor. */
public:
void Zeigmal(void);
}
/*#Klasse ###########################*/
class Lautsprecher
{
/*Konstruktoren und destruktoren denkt ihr hier euch mal.
Ansonsten gilt die default-Konst / Destruktor. */
public:
void Zeigmal(void);
}
/*############################*/
void Bildschirm::Zeigmal(void)
{
cout << "Ich bin ein Bildschirm\r\n";
}
/*############################*/
void Lautsprecher::Zeigmal(void)
{
cout << "Ich bin ein Lautsprecher\r\n";
}
/* globales Array mit Typ abstrakte Basisklasse könnte
auch in einer Klasse als private - Variable angegeben sein. */
IDevice* Liste[2];
int main(void)
{
Liste[1] = new Bildschirm;
Liste[2] = new Lautsprecher;
Liste[1]->ZeigMal();
Liste[2]->ZeigMal();
/* dynamisch erzeugte Speichervariablen freigeben. */
}
Wenn jetzt main abgearbeitet wird, sollte Folgendes herauskommen.
Ich bin ein Bildschirm
Ich bin ein Lautsprecher
So habe ich das mit den abstrakten (körperlosen) Klassen verstanden und
mehrfach mit der Umsetzung des Polymorphismus (Vielgesichtigkeit)
erfolgreich eingesetzt.
Bitte nagelt mich jetzt nicht, wenn ich oben Fehler habe. Ich wollte nur
das Prinzip zeigen...
Sorry habe das virtual vergessen. Meine OOP-Erfahrungen sind schon etwas
angestaubt.
Hier mal mein Verständnis:
/*#abstrakte Klasse ###########################*/
class IDevice
{
/*Konstruktoren und destruktoren denkt ihr hier euch mal.
Ansonsten gilt die default-Konst / Destruktor. */
public:
virtual void ZeigMal(void);
}
/*#Klasse ###########################*/
clase Bildschirm : IDevice
{
/*Konstruktoren und destruktoren denkt ihr hier euch mal.
Ansonsten gilt die default-Konst / Destruktor. */
public:
void Zeigmal(void);
}
/*#Klasse ###########################*/
class Lautsprecher
{
/*Konstruktoren und destruktoren denkt ihr hier euch mal.
Ansonsten gilt die default-Konst / Destruktor. */
public:
void Zeigmal(void);
}
cskulkw schrieb:> goldeneyes1987 schrieb:>> virtual void fcn() = 0;>> Warum willst Du einer Funktion in der körperlosen Klasse eine Null> zuweisen?
um sie als pure zu markieren.
'pure' ist wohl das, was du als 'körperlos' bezeichnest.
> class IDevice> {>> /*Konstruktoren und destruktoren denkt ihr hier euch mal.> Ansonsten gilt die default-Konst / Destruktor. */>> public:> void ZeigMal(void);>> }
Und wenn du diese Funkion jetzt auch noch pure machst,
void ZeigMal(void) = 0;
dann lässt dich der Compiler kein Objekt der Klasse IDevice anlegen,
eben weil die Klasse selbst dadurch pure gemacht wurde. De facto zwingt
man dadurch eine davon abgeleitete Klasse, die Funktion zu
implementieren. Tut man es nicht, dann ist auch die Ableitung wieder
pure und man kann kein Objekt davon erzeugen. Erst durch das
Implementieren der Funktion ZeigMal in Bildschirm wird die Klasse
Bildschirm un-pure und man kann auch Bildschirmobjekte erzeugen.
Es läuft also darauf hinaus, dass eine Klasse von sich sagen kann: Du
kannst von mir ableiten, aber wenn du das tust, dann MUSST du diese und
jene Funktion implementieren.
> So habe ich das mit den abstrakten (körperlosen) Klassen verstanden und> mehrfach mit der Umsetzung des Polymorphismus (Vielgesichtigkeit)> erfolgreich eingesetzt.
Nur dass deine IDevice Klasse eben nicht formal abstrakt (=pure) ist. In
C++ gibt es dafür ein Sprachmittel, mit dem man das auch so ausdrücken
kann, dass es der Compiler überwachen kann. Und das ist immer besser,
als wie wenn man sich auf Konventionen verlassen muss.
Übrigens bedeutet pure nicht, dass die Funktion keine Implementierung
haben kann. Sie kann, aber sie muss nicht.
> Das kann man aus Deinem Post nicht erkennen.
Eigentlich kann man das sehr gut erkennen. Ist ein klassischer
Polymorphie-Ansatz, der auf einer abstrakten Basisklasse als
Interface-Beschreibung aufbaut.
Wow, nicht eine einzige brauchbare Antwort
IDevice* testDevice[10];
RadioControl myDevice;
testDevice[0] = ( IDevice* ) &myDevice;
wenn schon denn schon typecast
Frank schrieb:> Wow, nicht eine einzige brauchbare Antwort>
*) doch, gab es.
ausführbare Anweisungen gehören in eine Funktion und nicht einfach
nur irgendwie freistehend ausserhalb.
*) deine ist aber auch nicht brauchbarer:
> IDevice* testDevice[10];> RadioControl myDevice;>> testDevice[0] = ( IDevice* ) &myDevice;>> wenn schon denn schon typecast
No. Genau diesen Cast willst du nicht haben. Er ist komplett unnötig.
Und unnötige Casts sind Zeitbomben.
Ein RadioControl IST EIN IDevice
Karl Heinz Buchegger schrieb:> um sie als pure zu markieren.
Besser "pure virtual" (also "rein virtuell") oder "abstract" schreiben.
"pure" alleine verwechselt man sonst evtl mit dem
"pure"-Funktionsattribut (==Seiteneffektsfrei), das der GCC z.B. für die
Optimierung verwendet.
(Offtopic:
mit dem Prototyp
1
intmy_strlen(char*)__attribute__((pure));
darf der Compiler dann z.B.
1
intx=my_strlen(a)+my_strlen(a);
als
1
intx=2*my_strlen(a);
compilieren, und einen Funktionsaufruf wegsparen
)
Εrnst B✶ schrieb:> Karl Heinz Buchegger schrieb:>> um sie als pure zu markieren.>> Besser "pure virtual" (also "rein virtuell") oder "abstract" schreiben.>> "pure" alleine verwechselt man sonst evtl mit dem> "pure"-Funktionsattribut (==Seiteneffektsfrei), das der GCC z.B. für die> Optimierung verwendet.
Merci.
Werds mir merken. Guter Punkt.
Εrnst B✶ schrieb:> Karl Heinz Buchegger schrieb:>> um sie als pure zu markieren.>> Besser "pure virtual" (also "rein virtuell") oder "abstract" schreiben.
Memberfunktionen können rein virtuell sein. Eine Klasse, die solche hat,
ist abstrakt.
cskulkw schrieb:> körperlose Klasse
Google-Treffer: drei. Zwei religiöse und dein Posting.
Kannst du nicht einfach mal darauf verzichten, Begriffe selbst zu
erfinden?
cskulkw schrieb:>> virtual void fcn() = 0;>> Warum willst Du einer Funktion in der körperlosen Klasse eine Null> zuweisen?> Hattest Du da im Hinterkopf, einen Funktionspointer mit 0 zu> initialisieren. Wenn fcn hier ein Prototyp ist, dann empfiehlt sich eine> void in den Klammern. Muß man nicht, hift aber ungemein.
Lern doch einfach erstmal C++.
Das ist die ganz normale Syntax, um rein virtuelle Methoden zu
vereinbaren.
Und ja, sie ist so gewählt worden, weil sie syntaktisch an die Zuweisung
eines Nullpointers erinnern soll.
Wenn wir schon beim nörgeln sind:
> Wenn fcn hier ein Prototyp ist, dann empfiehlt sich eine> void in den Klammern. Muß man nicht, hift aber ungemein.
Nicht .... wirklich.
Anders als in C hat eine leere Argumentliste in C++ keine
Sonderbedeutung. Die Funktion nimmt keine Argumente. Aus - Punkt. Egal
ob da void drinnen steht oder nicht.
Was aber tatsächlich ein aus Programmierersicht wichtiger Punkt gewesen
wäre:
1
classIDevice
2
{
3
public:
4
virtualvoidZeigMal(void);
5
6
}
7
8
claseBildschirm:IDevice
9
{
10
public:
11
voidZeigmal(void);
12
}
wenn eine Funktion in der Basisklasse virtual ist, dann ist es eine
extrem gute Idee, sie auch in den abgeleiteten Klassen ebenfalls
explizit als virtual zu markieren. Du musst es nicht tun, der Compiler
vererbt das virtual aus einer Basisklasse automatisch an die jeweiligen
Funktionen. Aber: Wenn sich das über mehrere Hierarchieebenen hinzieht,
schwöre ich dir, dass du dich irgendwann nicht mehr auskennst, welche
Funktionen jetzt virtual sind und welche nicht.
(Das ist auch einer meiner heftigsten Kritikpunkte an C++: Die
Behandlung des virtual Keywords und das es kein Fehler ist, wenn in
einer abgeleiteten Klasse das entsprechende virtual fehlt. Fehler an
dieser Stelle können heftig ins Auge gehen und zu Problemen führen, die
man nur sehr schwer findet)
> Was aber tatsächlich ein aus Programmierersicht wichtiger Punkt> gewesen wäre:
Und natürlich, dass IDevice einen virtual Destruktor braucht. Da du CTor
und DTor aber ausgespart hast, belasse ich es im Moment dabei.