Klassen Templates


  • Mod

    Eigentlich will ich ja dass das Template mir die Aufgabe abnimmt zu gucken, ob ich Elemente von der ersten oder zweiten Klassen zum Berechnen nehme.

    Das geht so nicht. Der Container kann immer nur Elemente eines bestimmten Typs halten, und vierte<erste, erste> und vierte<zweite, erste> sind zwei verschiedene Klassen und demnach zwei verschiedene Typen.

    Was wäre jetzt genau die Frage? Ob man Objekte verschiedenen Typs in einen Container einsetzen kann? Nein. Aber bestimmte Klassen können von einer Basisklasse ableiten, und Verweise auf diese kannst du dann im Container speichern. Polymorphie eben.

    zuerstmal solltest du dir vielleicht andere dinge anschauen, z.b. das korrekte setzen von semikola oder const-correctness.

    Unsinn, das ist beides in Ordnung.



  • Arcoth schrieb:

    zuerstmal solltest du dir vielleicht andere dinge anschauen, z.b. das korrekte setzen von semikola oder const-correctness.

    Unsinn, das ist beides in Ordnung.

    Lymogry schrieb:

    int ra() {return a;};
        double rb() {return b;};
        double rc() {return c;};
    

  • Mod

    igno schrieb:

    Lymogry schrieb:

    int ra() {return a;};
        double rb() {return b;};
        double rc() {return c;};
    

    Stört dich irgendetwas davon in diesem Beispiel? Das sind Dinge die der TE noch lernt, und die hier - in einem Thread über Klassentemplates - einfach irrelevant sind.

    Hast du irgendein gutes Tutorial zum Semikola-Setzen im Internet gefunden? Lass es mich wissen.



  • Arcoth schrieb:

    Stört dich irgendetwas davon in diesem Beispiel?

    dass es störend sei, davon war nie die rede...

    Arcoth schrieb:

    Das sind Dinge die der TE noch lernt,

    ich bin der meinung, dass man klassen lernt bevor man klassen-templates lernt...

    Arcoth schrieb:

    die hier - in einem Thread über Klassentemplates - einfach irrelevant sind.

    wenn der te es hier nicht richtig macht (in so einem kurzen listing wo alles übersichtlich ist), muss man davon ausgehen, dass er es auch in einem grösseren vorhaben nicht richtig machen würde, daher hab ich die stichworte in den raum geworfen. wenn er es schon kann, dann kann er meinen tipp getrost ignorieren. wenn er es nicht kann, hat er nun anhaltspunkte, was er noch lernen muss / sollte. was ist daran falsch?

    Arcoth schrieb:

    Hast du irgendein gutes Tutorial zum Semikola-Setzen im Internet gefunden? Lass es mich wissen.

    du hast c++ mit internet-tutorials gelernt?


  • Mod

    Arcoth schrieb:

    Das sind Dinge die der TE noch lernt,

    ich bin der meinung, dass man klassen lernt bevor man klassen-templates lernt...

    Der Meinung bin ich auch. 🙂 Dass der TE jedoch ein Grundlagenbuch durcharbeitet, weiß ich. Wenn er sich vorher in andere Gebiete reinwagt, ist das eigentlich löblich. Memberfunktionen, die auch konstante Objekte dieser Klasse aufrufen können, lernt er noch kennen.

    wenn er es nicht kann, hat er nun anhaltspunkte, was er noch lernen muss / sollte.
    was ist daran falsch?

    Du erklärst gar nichts. Du wirfst nur irgendwelche Begriffe in den Raum, von denen der TE nicht einmal die Verbindung zu seinem Beispiel kennt. Wenn du genau erklärt hättest, was wohin gehört bzw. nicht gehört, und wieso, wäre es hilfreich. So nützt es niemandem.

    du hast c++ mit internet-tutorials gelernt?

    Nein, aber in meinem Stroustrup gibt es ebenfalls kein Kapitel zur Semikola-Setzung.



  • Arcoth schrieb:

    Eigentlich will ich ja dass das Template mir die Aufgabe abnimmt zu gucken, ob ich Elemente von der ersten oder zweiten Klassen zum Berechnen nehme.

    Das geht so nicht. Der Container kann immer nur Elemente eines bestimmten Typs halten, und vierte<erste, erste> und vierte<zweite, erste> sind zwei verschiedene Klassen und demnach zwei verschiedene Typen.

    Was wäre jetzt genau die Frage? Ob man Objekte verschiedenen Typs in einen Container einsetzen kann? Nein. Aber bestimmte Klassen können von einer Basisklasse ableiten, und Verweise auf diese kannst du dann im Container speichern. Polymorphie eben.

    Danke!! Genau das war die Frage. 🙂
    Es geht also gar nicht. Gut zu wissen.

    ingo schrieb:

    zur letzten frage: klar geht das aber wieso machst du es nicht mit polymorphie?

    Ich lerne. 🙂
    Danke für das Beispiel!!!

    ingo schrieb:

    Arcoth schrieb:

    zuerstmal solltest du dir vielleicht andere dinge anschauen, z.b. das korrekte setzen von semikola

    Unsinn, das ist beides in Ordnung.

    Lymogry schrieb:

    int ra() {return a;};
        double rb() {return b;};
        double rc() {return c;};
    

    ähm ............
    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. Bei normalen Prozeduren mach ich sowas auch nie (ich kann eigentlich gut C), aber bei den Klassen dachte ich, dass das so da stehen muss, und weil auch der Compiler da kein bisschen meckert...
    ok. ich mach sie weg 🙂

    igno schrieb:

    zuerstmal solltest du dir vielleicht andere dinge anschauen,... const-correctness.

    Siehe Einganspost:
    (Stroustrup, Primer, Der C++ Programmierer und Meyers - neueste Auflagen - liegen hier ... unibib sei dank 😃 )
    Anm.: ich mach das erst seit 2 Wochen, und das mit Unterbrechung. Also bitte kein Flamewar, danke. 🕶

    ich lerne, .....
    Aber was meinst du mit const-correctness? Unter dem Stichpunkt find ich jetzt nichts in den Büchern ...

    UND JETZT NOCH INHALTLICHE FRAGEN 🙂

    Arcoth schrieb:

    Memberfunktionen, die auch konstante Objekte dieser Klasse aufrufen können, lernt er noch kennen.

    Meine Variable a ist aber nicht konstant. Es ist nur irgendeine Integerzahl, die es in beiden Klassen gibt, sie könnte ja auch anders heissen. 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"? 😉

    Warum ist das a im Beispiel von ingo const ??

    Arcoth schrieb:

    Dass der TE jedoch ein Grundlagenbuch durcharbeitet, weiß ich. Wenn er sich vorher in andere Gebiete reinwagt, ist das eigentlich löblich.

    Ja, sie springt gerne von Thema zu Thema, 🙂 um auszuprobieren und rumzuspielen. Viele Fragen ergeben sich erst wenn man sich intensiver als nur mit den Beispielen aus dem Buch auseinandersetzt. Und einiges wird dann Murks oder auch nicht, aus Fehlern lernt man. (Anm.: ich bin grad bei Templates gelandet, weil ich gerade mit dem Überladen von Funktionen rumgespielt habe und dann direkt zu den Templates gekommen bin. 🙂 Eigentlich bin ich grad im Kapitel mit Vererbung. Aber rumprobieren schadet ja nicht. 🙂 )

    Das Forum ist top!



  • Lymogry schrieb:

    ingo schrieb:

    Arcoth schrieb:

    zuerstmal solltest du dir vielleicht andere dinge anschauen, z.b. das korrekte setzen von semikola

    Unsinn, das ist beides in Ordnung.

    Lymogry schrieb:

    int ra() {return a;};
        double rb() {return b;};
        double rc() {return c;};
    

    ähm ............
    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. Bei normalen Prozeduren mach ich sowas auch nie (ich kann eigentlich gut C), aber bei den Klassen dachte ich, dass das so da stehen muss, und weil auch der Compiler da kein bisschen meckert...
    ok. ich mach sie weg 🙂

    es gilt einfach allgemein, dass ein semikolon nach der funktions-deklaration nötig ist, nicht aber nach der funktions-definition. ist sowohl in c, als auch in c++ so (damit ist sowohl inner- als auch ausserhalb der klassen gemeint).

    Lymogry schrieb:

    igno schrieb:

    zuerstmal solltest du dir vielleicht andere dinge anschauen,... const-correctness.

    Siehe Einganspost:
    (Stroustrup, Primer, Der C++ Programmierer und Meyers - neueste Auflagen - liegen hier ... unibib sei dank 😃 )
    Anm.: ich mach das erst seit 2 Wochen, und das mit Unterbrechung. Also bitte kein Flamewar, danke. 🕶

    ich lerne, .....
    Aber was meinst du mit const-correctness? Unter dem Stichpunkt find ich jetzt nichts in den Büchern ...

    klick.

    Lymogry schrieb:

    UND JETZT NOCH INHALTLICHE FRAGEN 🙂

    Arcoth schrieb:

    Memberfunktionen, die auch konstante Objekte dieser Klasse aufrufen können, lernt er noch kennen.

    Meine Variable a ist aber nicht konstant. Es ist nur irgendeine Integerzahl, die es in beiden Klassen gibt, sie könnte ja auch anders heissen. 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"? 😉

    Warum ist das a im Beispiel von ingo const ??

    die variable a ist - je nach dem ob die instanz der klasse konstant ist - konstant oder nicht (da du bei der definition von a weder explizit const noch mutable nutzt).

    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. nur wirst du im echten leben kaum eine birne mit einem auto addieren können...

    ausserdem ist mein "int a;" keinesfalls konstant, die getter-funktion dazu benötigt nur einen konstanten this-zeiger (wozu auch mehr, es wird eh nur eine kopie der instanz erzeugt). das ist das, was ich vorhin mit const-correctness angesprochen habe.


  • 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