Vererbung funktioniert nicht



  • Hallo, ich bin derzeit C++ zu lernen und gerade am verzweifeln, ich versuche jetzt schon seit ca 2 std die vererbung zum laufen zu kriegen es will aber einfach nicht funktionieren, derzeit meckert er rum das die methoden schon definiert sein in der Auto.obj ? aber diese will ich doch überschreiben hier die Datein:

    Auto.h

    #pragma once
    #ifndef AUTO_H
    #define AUTO_H
    #include<iostream>
    class Auto {
    public:
    	std::string hersteller;
    	std::string farbe;
    
    	void start();
    	void fahren();
    	void stop();
    };
    
    #endif
    

    Auto.cpp

    #include "Auto.h"
    #include<iostream>
    
    void Auto::start() {}
    void Auto::fahren() {}
    void Auto::stop() {}
    

    Audi.h

    #pragma once
    #ifndef AUDI_H
    #define AUDI_H
    #include "Auto.h"
    class Audi : public Auto {
    
    };
    #endif // !AUDI_H_
    

    Audi.cpp

    #include "Audi.h"
    
    void Auto::start() {
    	std::cout << "Der Audi macht brumm" << std::endl;
    }
    
    void Auto::fahren() {
    	std::cout << "Langweiliger Audi fährt" << std::endl;
    }
    
    void Auto::stop() {
    	std::cout << "Der Audi bleibt stehen" << std::endl;
    }
    

    Tesla.h

    #pragma once
    #pragma once
    #ifndef TESLA_H
    #define TESLA_H
    #include "Auto.h"
    class Tesla: public Auto {
    
    };
    #endif // !AUDI_H_
    

    Tesla.cpp

    #include "Tesla.h"
    
    	void Auto::start() {
    		std::cout << "Der Tesla macht brumm" << std::endl;
    	}
    
    	void Auto::fahren() {
    		std::cout << "Tesla fährt" << std::endl;
    	}
    
    	void Auto::stop() {
    		std::cout << "Der Tesla bleibt stehen" << std::endl;
    	}
    

    main.cpp

    #include <iostream>
    #include "Auto.h"
    #include "Audi.h"
    #include "Tesla.h"
    
    using namespace std;
    
    int main() {
    	cout << "HELLO WORLD" << endl;
    	Audi audi;
    	audi.fahren();
    	while (true) {
    
    	}
    }
    

    Fehler:
    http://imgur.com/a/dQe5k

    Und ja die Strings.. ich wusste nicht wie ich sonst die vererbung testen sollte also den text gekonnt ignorieren bitte 😃

    Ich bedanke mich jetzt schonmal für jegliche hilfe


  • Mod

    Du definierst mehrmals die Auto-Methoden, du möchtest wohl lieber Methoden für Audi, Tesla, etc. definieren.



  • Mein plan war methoden in der Auto klasse zu haben mit einer normalen funktion, aber diese funktion über die Audi und Tesla klasse zu überschreiben, bin ich das komplett falsch angegangen? oder wie überschreibe ich die methoden?



  • Danke dir! habe es jetzt hingekriegt, habe anstatt Auto:: halt Tesla:: und Audi:: vor die methoden geschrieben, und im header definiert ! so einfach und ich habe so lange gebraucht dafür DANKE!

    // Edit:
    Zu früh gefreut, es gibt jetzt keine compile fehler mehr.. aber wenn ich
    Auto* audi = new Audi; mache
    und daraufhin audi->fahren(), führt er die methode aus der Auto klasse aus und nicht aus der Audi klasse, aber genau die wollte ich ja überschreiben mithilfe der vererbung.

    //Edit 2:
    Okay scheint nun zu gehen. habe die voids in der Auto.h virtual gemacht



  • Ein Tipp: wenn du in Audi und Tesla sicherstellen willst, dass eine Funktion in Auto virtuell ist, dann deklarieren sie mit override . Dann bekommst du einen Compilefehler, wenn das virtual in Auto fehlt.

    Siehe http://en.cppreference.com/w/cpp/language/override



  • gerade ausprobiert danke für den hilfreichen tipp ! mal ne andere sache, gibt es in C++ wie in java eigl auch sowas wie packages ? (ordner für klassen)



  • In C++gibt es namespaces



  • Ich hätte es so gemacht:

    #include <iostream>
    #include <string>
    
    class IAuto
    {
    public:
        IAuto() {}
        virtual ~IAuto() {}
    
        virtual void start() = 0;
        virtual void fahren() = 0;
        virtual void stop() = 0;
    };
    
    class Tesla : public IAuto
    {
    public:
        Tesla()
        : IAuto()
        {}
    
        virtual ~Tesla()
        {}
    
        virtual void start()
        {
            std::cout << "Der Tesla macht brumm" << std::endl;
        }
    
        virtual void fahren()
        {
            std::cout << "Tesla fährt" << std::endl;
        }
    
        virtual void stop()
        {
            std::cout << "Der Tesla bleibt stehen" << std::endl;
        }
    
    };
    
    int main()
    {
        Tesla tesla;
        tesla.fahren();
    }
    

    Siehe https://en.wikibooks.org/wiki/C%2B%2B_Programming/Classes/Abstract_Classes
    Hat den Vorteil, dass man die Funktionen in IAuto implementieren MUSS, wenn man davon ableitet. Ähnlich dem Java "interface".

    Leftwitch2 schrieb:

    #pragma once
    #ifndef AUTO_H
    #define AUTO_H
    

    Hierzu noch: #pragma once reicht vollkomnmen. Das wird von allen gängigen Compilern unterstützt. Den altmodischen include guard kannst dir sparen, vor allem weil die gerne zu Fehlern führen, wegen Namenskollisonen mit anderen alten include guards.



  • gcc schrieb:

    CPP supports two more ways of indicating that a header file should be read only once. Neither one is as portable as a wrapper ‘#ifndef’ and we recommend you do not use them in new program

    https://gcc.gnu.org/onlinedocs/gcc-7.1.0/cpp/Alternatives-to-Wrapper-_0023ifndef.html#Alternatives-to-Wrapper-_0023ifndef



  • manni66 schrieb:

    gcc schrieb:

    CPP supports two more ways of indicating that a header file should be read only once. Neither one is as portable as a wrapper ‘#ifndef’ and we recommend you do not use them in new program

    https://gcc.gnu.org/onlinedocs/gcc-7.1.0/cpp/Alternatives-to-Wrapper-_0023ifndef.html#Alternatives-to-Wrapper-_0023ifndef

    Die Info auf der Seite ist veraltet. #pragma once wird von allen Compiler Suites bis auf die Portland Group C++ Suite. Den faktisch keiner hier benutzt. #import dagegen nur von gcc. Und wie ich schon sagte, sind include guards anfällig für namenskollisonen in der Form. Nur weil irgendwo was steht, heisst das nicht, dass es auch korrekt ist.

    Import ist in VC++ als Beispiel für .COM reserviert.

    https://msdn.microsoft.com/en-us/library/8etzzkb6(VS.71).aspx
    https://en.wikipedia.org/wiki/Pragma_once



  • gcc.gnu.org ist nicht irgendwo.



  • Ich frage mich bei Scorcher24s Code viel mehr, warum leere Konstuktoren und Destruktoren implementiert werden. Wenn man die nicht braucht, einfach weglassen.

    Natürlich muss der Destuktor ~IAuto virtual sein, aber ich würde dann vorschlagen, einfach folgendes zu schreiben:

    virtual ~IAuto() = default;
    

    Das macht deutlich klar, dass hier nichts benutzerdefiniertes stattfindet, sondern nur der Destruktor virtual gemacht wird.

    Und in den abgeleiteten Klassen wie Tesla eben nicht

    virtual void start()
    

    sondern

    void start() override
    

    Bzgl. Include-Guards:
    Was macht #pragma once eigentlich bei Symlinks, bei Hardlinks, bei Headern, die in unterschiedliche Verzeichnisse kopiert wurden? Mit normalen Include-Guards ist alles klar. Außerdem kann man dann auch mal einfach eine DummyClassAuto.h includen, die nur ein simples konstantes Auto modelliert - diese könnte dann das define für die "normale" Auto-Klasse enthalten und somit verhindern, dass diese geladen wird. Das ist dann zwar vielleicht "poor men's testing", aber mit pragma once hätte das nicht so einfach funktioniert.



  • wob schrieb:

    Bzgl. Include-Guards:
    Was macht #pragma once eigentlich bei Symlinks, bei Hardlinks, bei Headern, die in unterschiedliche Verzeichnisse kopiert wurden? Mit normalen Include-Guards ist alles klar. Außerdem kann man dann auch mal einfach eine DummyClassAuto.h includen, die nur ein simples konstantes Auto modelliert - diese könnte dann das define für die "normale" Auto-Klasse enthalten und somit verhindern, dass diese geladen wird. Das ist dann zwar vielleicht "poor men's testing", aber mit pragma once hätte das nicht so einfach funktioniert.

    Symlinks und ähnliches aufzulösen ist Aufgabe des Betriebssystems bzw Dateisystems. Auch bei Headern in unterschiedlichen Verzeichnissen gibt es da kein Problem. Ich verstehe nicht, wie du darauf kommst. Zudem haben include guards das Problem der Namenskollission. Wenn man sie benutzt, dann bitte mit Zufallszahlen drin. Aka

    #ifndef EXAMPLE_782376237623723_HPP
    #define EXAMPLE_782376237623723_HPP
    #endif
    

    Aber #import ist definitiv der falsche Weg und nicht halb so portabel wie pragma once.



  • Scorcher24 schrieb:

    Symlinks und ähnliches aufzulösen ist Aufgabe des Betriebssystems bzw Dateisystems.

    Aha. Komisch, dass es dann solche Fragen gibt: https://social.msdn.microsoft.com/Forums/SqlServer/en-US/f7d4aab9-c3b0-43a3-a51b-1a3fae87fcc7/pragma-once-and-symbolic-links?forum=vcgeneral

    Zu den unterschiedlichen Verzeichnissen (siehe https://en.wikipedia.org/wiki/Pragma_once#Caveats): "This backfires when the same file is intentionally copied into several parts of a project."



  • Wer macht den auch so ein scheiß mit symlinks? wtf?

    #pragma once macht viel weniger probleme als #ifndef etc.
    Vor allem sind versehentliche doppeltbenutzungen der macros oft nicht sehr offensichtliche Fehler.

    ...genauso wie leute die Pfade haben die MAX_PATH überschreiten und mit Sonderzeichen vollgeballert sind, nur weil die noch nie was von Datenbanken gehört haben... manche Leute wollen es auch wirklich wissen, wie man sich alles zerschießt!


Log in to reply