virtuelle Funktion



  • hallo hallo!
    ich beschäftige mich derzeit mit virtuellen funktionen.
    habe aber eine explizite frage bzgl. meines Programms.

    kurze erläuterung:
    ich habe eine basisklasse fahrzeug und leite von ihr die klasse auto ab.
    nun will ich ein objekt der klasse auto (also der abgeleiteten klasse) erstellen und mit printAusgabe eine kleine ausgabe schreiben.
    mein ziel: ich will über die abgeleitete klasse die ausgabe speziell für diese ausgeben, als auch eine ausgabe in der basisklasse aufrufen.

    so das z.b.

    class basisklasse
    {
        printAusgabe() { cout << "text der basisklasse"; }
    };
    
    class subklasse :: basisklasse
    {
        printAusgabe() { cout << "text der subklasse"; }
    };
    

    es soll also ein objekt der subklasse erstellt werden. dieses übergeb ich an eine print-funktion, welche wiederum auf die jeweiligen printAusgaben() zugreifen. damit das geschieht und der compiler weiß welche klasse, nehme ich ja virtual. so hab ich das zumindest verstanden.

    hier nun mein programm:

    class CFahrzeug
    {
    protected:
        int id;
        string name;
        float preis;
    public:
        CFahrzeug(); //beide Konstruktorinitialisierungen hab ich jetzt einfach wegen platz weggelassen.
        CFahrzeug(int id, string name, float preis);
    
        virtual void ausgabe()
        {
            cout << "ID: " << id << " name: " << name << " preis: " << preis << endl;
        }          
    };
    
    class CAuto : public CFahrzeug
    {
    private:
        string kennzeichen;
    public:
        CAuto();
        CAuto(int id, string name, float preis, int raeder, string pkennzeichen) 
                    : CFahrzeug(id,name, preis)            
        {
    
            kennzeichen = pkennzeichen;
        } 
         virtual void ausgabe()
        {
            CFahrzeug::ausgabe();
            cout << " Kennzeichen: " << kennzeichen << endl;
        }
    };
    CAuto::CAuto()
    {
        kennzeichen = "n/a";
    };
    
    void printAusgabe(CFahrzeug test)
    {
        test.ausgabe();
    }
    
    int main(int argc, char *argv[]) 
    {
        CAuto testAuto;
        printAusgabe(testAuto);
    
        return 0;
    }
    

    ich könnte auch die printAusgabe weglassen und im abgeleiteten objekt einfach in der funktion "ausgabe()" einfach nochmal die ausgabe der basisklasse aufrufen. das erscheint mir einfach logischer.
    damit ruft er (bei erstellung eins objekts abgeleiteter klasse) die ausgabe in der subklasse auf und in der steht wieder der aufruf der basisklasse. ergo: ausgabe basis- und subklasse gibt er mir aus.

    wenn ich aber wie im beispiel was ich lerne, eine funktion extra anlege die alles ausgeben soll, dann klappts nicht.

    mein ergebnis müsste jetzt in der abgespeckten version:
    ID: 0 name: n/a preis: 0 sein. //konstruktoren sind natürlich hier weggelassen wegen der "0" jetzt.

    void printAusgabe(CFahrzeug test)
    {
        test.ausgabe();
    }
    

    hier sage ich ja: nehme das jeweilige obejekt und führe die ausgabe in der jeweiligen klasse aus. CFahrzeug steht ja als basisklasse und durch virtual sollte er die ausgabe ja "durchreichen".
    im skript steht übrigens auch die basisklasse und objekt als parameter. wenn ich als parameter die abgeleitete klasse und objekt nehme, gehts. so will ich es aber halt nicht.
    also:
    void printAusgabe(CFahrzeug test) // geht nicht
    void printAusgabe(CAuto test) // geht

    mein gewünschtes ergebnis sollte:
    ID: 0 name: n/a preis: 0
    Kennzeichen: n/a

    sein und nicht nur:
    ID: 0 name: n/a preis: 0

    was ist an meinem "virtual" falsch, dass er nur cout der basisklasse ausgibt und nicht das cout der basisklasse und der subklasse?
    ich hoffe ihr konntet meiner konfusen beschreibung folgen und wisst was ich meine?! 😉

    gruß norben





  • void printAusgabe(CFahrzeug& test)
    


  • ach neee oder? 😃
    extra einen hunderzeiler geschrieben und dann fehlt nur ein "&"?! 😃

    vielleicht kann mir der ein oder andere nochmal die zeilen explizit erklären:

    void printAusgabe(CFahrzeug& test)
    

    was genau ist anders als die zeile ohne "&"?
    mir schwirrt beim dem kaufmanns-und immer die speicheradresse oder referenz durch den kopf. warum geht es nicht ohne?



  • Im bereits geposteten Artikel über ObjectSlicing wird es erklärt. Aber ich kanns mal versuchen:

    Bei

    void printAusgabe(CFahrzeug test) { .. }
    

    wird beim Aufruf

    printAusgabe(testAuto);
    

    ein neues Objekt der Klasse CFahrzeug erstellt und das Objekt testAuto wird in diese Instanz kopiert. Jetzt hast du aber kein Objekt vom Typ CAuto mehr, sondern ein Objekt vom Typ CFahrzeug (testAuto kann nicht vollständig kopiert werden, da ein Objekt der Klasse CFahrzeug eventuell gar nicht alle Felder der Klasse CAuto besitzt). Folglich wird dann die print-Methode der Klasse CFahrzeug aufgerufen.

    Bei

    void printAusgabe(CFahrzeug &test) { .. }
    

    wird beim Aufruf

    printAusgabe(testAuto);
    

    das Objekt nicht kopiert sondern per Referenz uebergeben (stelle dir einfach vor, dass test ein anderer Name fuer testAuto, d.h. es handelt sich um das selbe Objekt). Das heisst test ist (bzw. referenziert) dann noch immer ein Objekt der Klasse CAuto, folglich wird die print-Methode der Klasse CAuto aufgerufen.



  • ich hab mich wohl doch zu früh gefreut.

    da ich hier:

    virtual void ausgabe() 
        { 
            CFahrzeug::ausgabe();  //vergessen auszukommentieren
            cout << " Kennzeichen: " << kennzeichen << endl; 
        } 
    };
    

    in der abgeleiteten klasse nochmal die ausgabe aus der basisklasse aufrufe gehts.
    dies ist unabhängig vom "&" in der zeile:

    void printAusgabe(CFahrzeug& test)
    

    es geht also mit und ohne.

    lustig aber:
    kommentier ich CFahrzeug::ausgabe(); aus, setze kein & in der zeile void printAusgabe(CFahrzeug& test), dann kommt: ID: 0 name: n/a preis: 0 raus
    setze ich das "&" kommt: Kennzeichen: n/a raus.

    beide ausgaben aus basis- und subklasse gibt er aber nicht zusammen aus -.-
    also immer noch gewünscht:
    ID: 0 name: n/a preis: 0 raus
    Kennzeichen: n/a

    kommt nicht heraus 😞



  • ok. der letzte post war meinerseits bisschen fail, denk ich.
    wie soll er auch aus der basisklasse eine funktion aufrufen, wenn man explizit in die subklasse geht und dort kein aufruf von der basis aufruft. 😃
    ich glaube dahingehend hatte ich einen denkfehler.

    besten dank soweit.
    ich melde mich bestimmt nochmal 😃


Anmelden zum Antworten