Klassen Templates


  • Mod

    Meine Variable a ist aber nicht konstant.

    Das ist hier völlig unwichtig.

    Wenn du eine Memberfunktion mit const qualifizierst, dann heißt das, dass auch konstante Objekte diese aufrufen können.

    struct A
    {
        void foo() { std::cout << "foo()\n"; }
        void bar() { std::cout << "foo()\n"; }
        void foo() const { std::cout << "foo() const\n"; }
    };
    
    int main()
    {
        A a;
        A const b;
    
        a.foo();
        b.foo();
    //    b.bar();  Compilerfehler - bar() kann von einem konstanten Objekt nicht aufgerufen werden
    }
    

    Ich dachte, das muss so. Weil es ja eigentlich mit einer Inline Funktion auch ausgelagert werden könnte und dann würden die Semikola auch da stehen.

    Nein, würden sie nicht. Nach einer Funktionsdefinition muss nie ein Semikolon stehen. Nur bei einer Deklaration:

    int ra();
    

    Das ist doch in C genauso.
    Edit: Da kam mir ingo zuvor.

    Bzw könnten beide Klassen gaaaanz unterschiedlich sein, sagen wir ein Auto und eine Birne. Wird die abstrakte Klasse, von der beide erben, dann "Objekte des realen Lebens"?

    Es kommt völlig auf das Design an. Ich sehe übrigens nicht, inwiefern man hier eine Basisklasse benötigt, denn beide Klassen haben möglicherweise keine Funktionalität gemein. Wenn sie tatsächlich ein Konzept teilen, welches man aus ihnen herausabstrahieren könnte, dann wäre das sinnvoll.



  • mein name ist igno, ingo ist ein anderer nutzer.



  • igno schrieb:

    meine basis-klasse ist btw nicht abstrakt, denn abstrakte klassen definieren sich dadurch, mindestens eine rein virtuelle funktion zu haben, ist aber nicht gegeben. ausserdem, solange die beiden erbenden klassen etwas gemeinsam haben (in diesem fall ist es die tatsache, dass man sie miteinander addieren kann), ist es nicht falsch, sie von der selben basis ableiten zu lassen.

    Nachdem ich jetzt eindrücklich gelernt habe, nur von Klassen abzuleiten, mit denen es eine IST-EIN Beziehung gibt, bin ich jetzt leicht verwirrt .... Die beiden Klassen HABEN doch nur etwas gemeinsam, dass sie nämlich beide eine integer Zahl besitzen...

    Arcoth schrieb:

    Ich sehe übrigens nicht, inwiefern man hier eine Basisklasse benötigt, denn beide Klassen haben möglicherweise keine Funktionalität gemein. Wenn sie tatsächlich ein Konzept teilen, welches man aus ihnen herausabstrahieren könnte, dann wäre das sinnvoll.

    ja, ich sehs auch nicht ... aber ich bin ja auch verwirrd und unwissend 😕



  • beide klassen haben ein gemeinsames member und eine gemeinsame methode. ausserdem wird ein operator in form einer klasse angeboten, der als argument je eine der beiden klassen akzeptiert. klar, es besteht auch die möglichkeit diesen getter 2x zu schreiben, sowie den operator 4x...

    über sinnvolle vererbung lässt sich nicht streiten solange die klassen nichts repräsentieren sondern einfach nur zum test da sind.


  • Mod

    Die beiden Klassen HABEN doch nur etwas gemeinsam, dass sie nämlich beide eine integer Zahl besitzen..

    Wir wissen nichts über die Bedeutung dieser Zahl, da du sie unwillkürlich hinzugefügt hast. Vielleicht brauchen ja nur zufällig beide einen int als Member.

    Wen sie hingegen beide bspw. eine Art ID brauchen, also beide einen int aus demselben Grund, dann sollten sie von einer Basisklasse ableiten, die ein Objekt mit einer ID repräsentiert, und so diese Funktionalität auslagern.

    Daher:

    über sinnvolle vererbung lässt sich nicht streiten solange die klassen nichts repräsentieren sondern einfach nur zum test da sind.

    👍



  • Daaanke!!!

    Fraaaage: 🙂 (eher Feststelltung, ob das so richtig ist:)

    Nun wird in ignos Beispiel ein Vector über eine vererbte Klasse benutzt.
    In dem C++ Programmierer (S. 267) steht allerdings:
    "C-Arrays sind keine Klasse. Der Compiler reserviert sich für den Speicher nur sizeof(Oberklasse), aber nicht sizeof(Unterklasse)."

    Vektoren sind ja keine C-Array. Vektoren reservieren also problemlos auch genügend für die geerbten Unterklassen?? 🙂
    uuuuiiiiiii 😮 🕶 sind die mächtig 🙂


  • Mod

    Nun wird in ignos Beispiel ein Vector über eine vererbte Klasse benutzt.

    Wie meinst du das? In ignos Beispiel ist vierte selbst ist nicht polymorph, sondern nimmt nur in Memberfunktionen eine Referenz auf eine Basisklasse.

    Vektoren reservieren also problemlos auch genügend für die geerbten Unterklassen??

    Natürlich. Basisklassen sind nur ein Subobjekt der ableitenden Klasse.

    "C-Arrays sind keine Klasse. Der Compiler reserviert sich für den Speicher nur sizeof(Oberklasse), aber nicht sizeof(Unterklasse)."

    Völliger Unsinn, oder du hast ohne Kontext zitiert (wahrscheinlicher).

    Solltest du ein Array von (Unter)klassen anlegen, wird auf jeden Fall das komplette Objekt angelegt - versprochen. Alles andere wäre Unfug.

    Zeig doch mal, wo genau du das her hast, das scheint irgendwie falsch zitiert worden zu sein.

    Edit: Da verwechsle ich glatt Unter- und Oberklasse...



  • ups, verguckt. Natürlich nicht die Klasse vierte, die erbt ja nix. Sondern die erste oder zweite. Und darüber ein Vektor:

    std::vector<erste> test2;
        test2.push_back(erste(2,3,4));
        test2.push_back(erste(4,5,1));
        vierte test4(test2[0],test2[1]);
        std::cout << test4.b <<"\n";
    

    Das geht! 😮

    Ja, das ist natürlich aus dem Zusammenhang.
    Es geht um solche Arrays:

    Oberklasse* array=new Unterklasse[4]; // sinnlos
    

    "Die nichtgeerbten Attribute eines Unterklassenobjekts sind nicht zugreifbar, weil nur die Oberklassenanteile abgespeichert werden. Die Adressen &array[i] (0<=i<=4) liegen nur sizeof(Oberklasse) Bytes auseinander, nicht sizeof(Unterklasse)."

    Wahrscheinlich weil es statisch ist.
    Vektoren sind aber ganz schön mächtig. 🕶


  • Mod

    Autor schrieb:

    Die nichtgeerbten Attribute eines Unterklassenobjekts sind nicht zugreifbar, weil nur die Oberklassenanteile abgespeichert werden.

    Das ist falsch. Gespeichert werden vier hintereinander liegende Unterklassen-Objekte.

    Die Adressen &array[i] (0<=i<=4) liegen nur sizeof(Oberklasse) Bytes auseinander, nicht sizeof(Unterklasse).

    Ja, das ist ja auch klar. Aber array[1] ist ein nicht erlaubter Ausdruck der undefiniertes Verhalten erzeugt, denn man dereferenziert da implizit einen ungültigen Zeiger. Das heißt, solche array-to-pointer-decays sollte man hübsch sein lassen.

    Wahrscheinlich weil es statisch ist.

    Was ist da statisch?



  • Lymogry schrieb:

    Es geht um solche Arrays:

    Oberklasse* array=new Unterklasse[4]; // sinnlos
    

    "Die nichtgeerbten Attribute eines Unterklassenobjekts sind nicht zugreifbar, weil nur die Oberklassenanteile abgespeichert werden. Die Adressen &array[i] (0<=i<=4) liegen nur sizeof(Oberklasse) Bytes auseinander, nicht sizeof(Unterklasse)."

    Wahrscheinlich weil es statisch ist.

    was du hier schreibst dürfte gar nichterst kompilieren.

    es nennt sich downcasting und ist - im gegensatz zu upcasting - nicht implizit vollstreckbar. wenn du dir sicher bist, dass deine (Unterklasse*)-ptr in wirklichkeit auf objekte vom typ Oberklasse zeigen, dann kannst du dynamic_cast<Oberklasse*>(ptr) schreiben. wenn du jedoch weisst, dass deine (Unterklasse*)-ptr das nicht tun, dann macht es wenig sinn downzucasten und ist auch - ausser mit einem hack den ich dir nicht verrate - nicht möglich.


  • Mod

    Oberklasse bezeichnet die Basisklasse. Das ist kein down- sondern upcasting. Das habe ich auch verwechselt.



  • achso, ups mein fehler

    edit: doch doch das macht schon sinn. kleines codebeispiel:

    #include <iostream>
    struct base
    {
    	virtual ~base()
    	{
    	}
    	virtual void print() const
    	{
    		std::cout << "i'm a base";
    	}
    };
    struct derived : base
    {
    	virtual void print() const
    	{
    		std::cout << "i'm derived";
    	}
    };
    int main()
    {
    	base* array = new derived[4];
    	array[2].print();
    	delete[] array;
    }
    

    und die ausgabe:

    i'm derived
    

    das zeigt dass über den zeiger auf eine basisklasse die methode der abgeleiteten klasse aufgerufen wurde. jedoch kannst du über einen zeiger auf die basisklasse (direkt zumindest) nur die methoden und member der basisklasse benutzen (wenn diese mit virtual in der abgeleiteten klasse überschrieben werden ist es etwas anderes).


  • Mod

    Das funktioniert zufaellig, weil derived und base beide gleich gross sind.

    Hier auf Ideone eine andere Variante, die natuerlich abstuerzt.


Anmelden zum Antworten