Vererbung von Membern



  • Hallo zusammen,

    im Prinzip habe ich gleich zwei Fragen, wobei diese Irgendwie zusammen gehoeren. Ich habe zunaechst eine Sammlung von Objekten eines bestimmten Typs A, wobei jedes Objekt einen Zeiger auf andere Objekte (im folgenden Beispiel zwei Stueck) gleichen Typs besitzt.

    1. Problem: Wenn ich eine abgeleitete Klasse A2 von der Klasse A der Objekte bilden moechte, Zeigen die Zeiger immer noch auf die alte Klasse A und nicht auf A2.
    2. Problem: Wie sage ich der Klasse B, in der die Objekte erzeugt werden, am besten, dass jetzt A2 statt A verwendet werden soll. (Ich weiss, im Prinzip geht sowas mit Templates, aber gehts auch anders?)

    //In folgendem Beispiel entspricht: A=Strassenabschnitt,  2=KaputterStrassenabschnitt, B=Strasse
    
    #include <iostream>
    #include <cmath>
    #include <vector>
    
    //////////// So etwas habe ich bisher //////////////
    
    class Strassenabschnitt {
    public:
    	int Breite;
    	Strassenabschnitt* links;
    	Strassenabschnitt* rechts;
    
    	double Kapazitaet() {return pow(double(Breite * rechts->Breite * links->Breite), 1.0/3);}
    };
    
    class Strasse {
    public:
    	std::vector<Strassenabschnitt> strasse;
    	void Init(unsigned int n) {
    		strasse.resize(n);
    		for (unsigned int i = 0; i < n; i++) {
    			strasse[i].Breite = i*i % 100; //Irgendwelche Werte
    
    			//Zeiger anlegen
    			if (i > 0) strasse[i].links = &strasse[i-1];
    			else strasse[i].links = &strasse[n-1];
    			if (i < n-1) strasse[i].rechts = &strasse[i+1];
    			else strasse[i].rechts = &strasse[0];
    		}
    	}
    
    	double AvgKapazitaet() {
    		double sum = 0;
    		for (unsigned int i = 0; i < strasse.size(); i++) {
    			sum += strasse[i].Kapazitaet();
    		}
    		return sum/strasse.size();
    	}
    };
    
    ////////// So etwas soll dazu kommen //////////////////
    
    class KaputterStrassenabschnitt : public Strassenabschnitt {
    public:
    	double Zustand;
    	double Kapazitaet() {return Zustand*Strassenabschnitt::Kapazitaet();}
    	/* Was bei der Vererbung mit den Zeigern passiert, gefaellt mir nicht so ganz...
    	 * Eine Funktion wie z.B.
    	 * double Kaputti() {return pow(double(Zustand * rechts->Zustand * links->Zustand), 1.0/3);}
    	 * waere so nicht moeglich
    	 */
    };
    
    class KaputteStrasse : public Strasse {
    /* Was muss hier rein?
     * Die KaputteStrasse soll KaputterStrassenabschnitt statt Strassenabschnitt
     * verwenden und ausserdem z.B. eine Funktion analog zu AvgKapazitaet() anbieten,
     * also sowas wie AvgKaputti()
     */
    };
    
    int main ()
    {
    	Strasse myStrasse;
    	myStrasse.Init(1000);
    	std::cout << myStrasse.AvgKapazitaet() << std::endl;
    
    	KaputteStrasse myKaputteStrasse;
    	myKaputteStrasse.Init(1000);
    	std::cout << myKaputteStrasse.AvgKapazitaet() << std::endl;
    
    	return 0;
    }
    

    Ich wuerde hier gern die Kommentare in "KaputterStrassenabschnitt" und "KaputteStrasse" gern mit Code fuellen. Wenn dafuer Aenderungen an den jeweiligen Elternklassen noetig sind, sollten diese so gering wie moeglich sein.

    Danke schonmal

    PS: So etwas in der Art habe ich hier schon mal gefragt, das Problem aber vermutlich etwas bloed formuliert (ist auch nicht ganz das identische Problem). Also nicht wundern falls das jemandem schon bekannt vorkommt.



  • "Zustand" ist ein Attribut, das auf JEDEN Straßenabschnitt zutrifft. Wenn du einen Starßenabschnitt benutzen lässt, wird der Stück für Stück "verbraucht", sein Zustand wird schlechter. Diesen Fakt kannst du mit deinem Modell nicht beschreiben.
    Kleines Beispiel zum Vergleich:

    class Mensch {
        virtual double haarpracht() const { return 1.0; }
    };
    
    class MenschMitWenigerHaar : public Mensch {
        double haarverlust_;
    public:
        virtual double haarpracht() const {
            return haarverlust_ * Mensch::haarpracht();
        }
    };
    

    Wenn dem Menschen nun altersbedingt die Haare ausfallen, müsstest du in deinem Programm eine Instanz der Klasse "Mensch" durch eine der Klasse "MenschMitWenigerHaar" ersetzen - irgendwo Käse, oder?
    Genau so ginge es dir in deinem Fall, du müsstest ganze Straßenabschnitte ersetzen um sie kaputt zu machen 😃

    Wird zum PÜroblem, wenn du z.B. einen Straßenabschnitt von einer Firma reparieren lässt (Straßenabschnitt und Straße sind dann ja wohl kaputt). Die Arbeit ist vollbracht, die STraße und der Abschnitt sind wieder in Ordnung. Jetzt will die Firma in der Steuererklärung angeben, welchen Abschnitt sie repariert haben. Geht nicht, die Referenz ist nicht mehr gültig. OK, man kann hier mit IDs arbeiten, und die Abschnitte über diese ID und nicht über eine Referenz/Zeiger auf einen Abschnitt identifizieren, trotzdem kann das problematisch werden, wenn z.B. der Abschnitt nur in eine Richtung repariert wird, in die andere Richtung gerade ein Auto fährt (hat sich eine Referenz auf den Abschnitt über die ID geholt) die Arbeiter gerade fertig werden - und dein Programm dem Fahrer die Straße unter dem Hintern wegreißt...

    Alles recht utpoisch, aber du siehst, dass es Probleme bereiten kann, wenn man ein allgemeines Attribut durch eine eigene Unterklasse substituiert.



  • Ok, das stimmt in dem Beispiel natuerlich...ich hatte gehofft damit halbwegs ein Abstraktes Problem etwas anschaulicher zu machen.

    Aber ich wollte eigentlich ueber das Programmieren reden, und nicht ueber Strassen, aber nagut...

    Also mal angenommen, ich verwende so eine Strasse Klasse z.B. fuer eine Computersimulation, in der der Strassenzustand nicht beruecksichtigt wird, dann waere die Variable "Zustand" nur unnoetiger Ballast im Speicher. Bei einer Variable mag das nicht so Schlimm sein, aber wenn man sehr viele Eigenschaften hat, die den Zustand der Strasse charakterisieren, macht das doch was aus. Also will ich nur die Eigenschaften verwenden, die ich auch fuer die jeweilige Anwendungen brauche. Der "Strassenabschnitt" soll sowas wie die minimal moegliche Menge an Information darstellen, weitere Infos sollen nur Hinzukommen wenn sie gebraucht werden.



  • Für solche Sachen gibt es dann eine verwaltende Instanz (Straßenmeisterei, Straßenverkehrsbehörde, ...) die selber für jeden Straßenabschnitt den Zustand speichert:

    class StrassenAbschnitt {
    public:
        typedef size_t Id;
        struct Zustand {
            //
        };
    };
    
    class StrassenMeisterei {
        std::map<StrassenAbschnitt::Id, StrassenAbschnitt::Zustand> strassenZustaende_;
    };
    

    Die Klasse muss natürlich nicht StrassenMeisterei heißen, aber die Erweiterungsmöglichkeit sollte klar ersichtlich sein.


Anmelden zum Antworten