Konstruktor mehrfach sich selbst aufrufen?



  • Hi,

    Ich habe vor einiger Zeit eine Konsoleanwendung geschrieben, die zur Demonstration alle wichtige Standardthemen von C++ abdeckt. Gemeint sind Einfache Vererbung, Mehrfachvererbung, Polymorphie, Konstruktor, Destruktor, Zeiger usw.
    Bei dieser Anwendung werden verschiedene Fahrzeuge konstruiert. Bevor das "spezielle" Fahrzeug geschaffen wird, werden durch Konstuktoren Wheel, Seat und Engine erstellt, was dann das Grundgerüst für Vehicle ergibt. Dem Vehicle werden dann spezifische vordefinierte Daten von den "speziellen" Fahrzeugen z.B.Car, Plane usw. zugewiesen. Da ganze wird dann in der Konsole ausgegeben.

    In diesem Beispiel wird allerdings der Destruktor von Wheel, Seat und Engine nicht wirklich beansprucht. Um diesem "Arbeit" zu verschaffen möchte ich nun die Anzahle der Sizte von Hand eingeben und eine Farbe zuweisen.

    Frage: Wie kann ich das am besten realisieren damit der Konstruktor und Destruktor Arbeit haben.

    Ich dachte mir das so das ich z.B. 4 für 4 Sitze eingebe und der Konstruktor dann 4 Sitze baut.
    Kann sich der Konstruktor dabei selbst 4 mal aufrufen oder muss ich dazu eine "Hilfsklasse" z.B. Sitzmacher erstellen?
    Das Problem was ich bei meinen bisherigen Versuchen hatte, war das Vehicle ja von Seat, Wheel und Engine erbt und dazu muss der Konstruktor von Wheel ja mindestens einmal aufgerufen werden. Wenn ich also 4 Sitze eingebe wird der Konstruktor wegen Veerbung einmal automatisch gestartet und darf dann nur noch 3 mal "konstruieren".

    Versteht überhaupt jemand was ich machen will?

    Schonmal einen Dank für eure Antworten.

    Mfg Lars



  • du lässt Vehicle von Seat erben (public)? ein Vehicle ist ein Seat?
    Da sieht was im Design nicht ganz in Ordnung aus.



  • Normalerweise loest man es mit 'Layering'

    class Vehicle
    {
    private:
      std::vector<Seat> seats;
    //...
    };
    

    Bei Vererbung musst du immer daran denken was sie bedeutet.

    public Vererbung heisst: IST EIN
    private bedeutet IST IMPLEMENTIERT MIT (BEINHALTET)

    Allerdings verwendet man private Vererbung nur selten, da 'Layering' meistens besser ist. so auch hier.



  • Erstma danke für die schnelle Antwort.
    Ich poste mal meinen Code das macht es für euch vielleicht einfacher.

    #include <list>
    #include <string>
    #include "Vehicle.h"
    #include "Bike.h"
    #include "Car.h"
    #include "Plane.h"
    
    int main(int argc, char **argv)
    {
    	Vehicle *vehicles[] =
    	{
    		new Bike,
    		new Car,
    		new Plane,
    	};
    
    	for (int i=0; i<sizeof(vehicles)/sizeof(Vehicle*); i++)
    	{
    		printf("---------------------------------\n"
    			   "vehicle number %i:\n"
    			   "---------------------------------\n"
    			   "name:               \"%s\"\n"
    			   "number of wheels:   %i\n"
    			   "number of seats:    %i\n"
    			   "engine brand:       \"%s\"\n"
    			   "engine ps:          %.1f\n",
    			   i+1,
    			   vehicles[i]->getName(),
    			   vehicles[i]->getNumWheels(),
    			   vehicles[i]->getNumSeats(),
    			   vehicles[i]->getEngineBrand(),
    			   vehicles[i]->getEnginePS());
    
    		printf("trying to drive vehicle: ");
    		vehicles[i]->drive();
    
    		// free memory
    		delete vehicles[i];
    	}
              return 0;
    }
    
    #ifndef __VEHICLE_H__
    #define __VEHICLE_H__
    
    class Wheels
    {
    	int	mNumWheels;
    public:
    
    	Wheels(int numWheels) { mNumWheels = numWheels; }
    	virtual ~Wheels() {}
    	int		getNumWheels() const { return mNumWheels; }
    };
    class Seats
    {
    	int		mNumSeats;
    public:
    	Seats(int numSeats) { mNumSeats=numSeats; }
    	virtual ~Seats() {}
    	int getNumSeats() const { return mNumSeats; }
    };
    class Engine
    {
    	std::string		mBrand;
    	float			mPS;
    public:
    	Engine(const char *brand, float ps) { mBrand=brand; mPS=ps; }
    	virtual ~Engine() {}
    
    	const char *getEngineBrand() const { return mBrand.c_str(); }
    	float		getEnginePS() const { return mPS; }
    };
    class Vehicle : public Wheels, public Seats, public Engine
    {
    	std::string	mName;
    public:
    	Vehicle(const char *name, int numWheels, int numSeats, const char *brand, float numPS)
    		: Wheels(numWheels),
    		  Seats(numSeats),
    		  Engine(brand, numPS)
    	{
    		setName(name);
    	}
    
    	virtual ~Vehicle() {}
    	virtual void	drive()=0;
    	const char		*getName() const { return mName.c_str(); }
    };
    
    #endif // __VEHICLE_H__
    
    #ifndef __CAR_H__
    #define __CAR_H__
    
    class Car : public Vehicle
    {
    
    public:
    
    	Car()
    		: Vehicle("VW Polo", 4, 4, "VW", 60.0f)
    	{
    	}
    
    	virtual void drive() { printf("Polo is driving.\n"); }
    
    };
    #endif // __CAR_H__
    


  • pietsche schrieb:

    class Vehicle : public Wheels, public Seats, public Engine
    

    Sehr fragwürdiges Design. Ich würde hier mit Komposition arbeiten (Vehicle HAS-A Wheel etc.), ausser, du brauchst irgendwann eine abstrakte Sicht auf das Fahrzeug als "Ding was Sitze hat".
    BTW seh ich noch nicht die Notwendigkeit, Konstruktoren mehrfach aufzurufen ... warum soll das denn passieren?



  • also das Design spielt bei der ganzen Sache erstmal nicht die Rolle.
    das ganze soll nur zur Demonstration dienen und musste auch nicht weiter sinnvoll sein. es ging nur darum die Möglichkeiten von c++ möglichst kompakt darzustellen und da hatte ich keine andere Idee.
    jetzt muss ich halt nur noch konstruktor und destruktor "beschäftigen".
    die sache mit der veränderbaren sitzanzahl und der sitzfarbe.
    ich weiss aber eben nicht wie ich den konstruktor mehrfach aufrufen kann.



  • Du hast keine Klasse, die einen Sitz repräsentiert, also kann es auch nirgends einen Konstruktor geben, der 4 Sitze baut. Deine Klasse «Seats» repräsentiert ein abstraktes Ding, was eine variable Anzahl von Sitzen hat, wobei die Anzahl im Mittelpunkt steht.
    Es bleibt dabei, was Shade schon gesagt hat: Du willst eigentlich eine Teil-Ganzes-Beziehung zwischen Sitz und Fahrzeug (Komposition), oder, wenn es unbedingt sein muss, zwischen Sitz und «Ding was Sitze hat».



  • und wie könnte ich am besten 4 Sitze mit unterschiedlichen Eigenschaften, also unterschiedlichen Farben zur Laufzeit erzeugen?



  • also das Design spielt bei der ganzen Sache erstmal nicht die Rolle.
    das ganze soll nur zur Demonstration dienen und musste auch nicht weiter sinnvoll sein. es ging nur darum die Möglichkeiten von c++ möglichst kompakt darzustellen und da hatte ich keine andere Idee.

    Nun, das sehe ich anders.
    Wenn du schon mit Klassen und Vererbung arbeitest, also auch OOP vermitteln willst, dann solltest du auch ein ordentliches Design hinlegen.

    class Vehicle : public Wheels, public Seats, public Engine
    

    Ein Fahrzeug ist Reifen, Sitze und ein Motor. 🙂

    Da sind jetzt sogar noch Grammatikfehler drin. 🤡

    MfG MAV 🙂



  • Das mit dem Design ist schon richtig aber ... wenn ich jetzt ein Vehicle erstelle (dessen Konstruktor aufrufe) dass wird doch die Klasse Seats aufgerufen und es soll aber nicht nur die Anzahl der Sitze als Variable übergeben werden, sondern es soll einen Kostruktor geben der eben die gewählte Anzahl der Sitze auch wirklich erstellt und diesen eine Farbe (aus einer Liste zuweist)

    wenn ich nun eine Klasse Seats mache ...
    und diese dann mit

    new Seat(Anzahl)
    

    ebenso oft aufrufe - meinetwegen durch eine Schleife im Konstruktor von Seats ... erzeug ich eben Sitz 1 bis Anzahl

    oder soll Vehicle einfach nicht von Sitzen erben weil das ja auch naja ... ist
    😞

    Cisco aka Kollege von Pietsche



  • eine Klasse ruft man nicht auf, man instanziiert sie:

    class Seat {  //repräsentiert einen (!) Sitz
    public:
       void set_color (...);
       void set_beschichtung (...); //wie auch immer
    };
    
    int main () {
      Seat einer, zweiter, dritter;
      einer.set_color(gruen);
      zweiter.set_color(rot);
      dritter.set_color(schwarz_braun);
    
      Seat *p = new Seat;
      Seat *p2 = new Seat;
    
      delete p; delete p2;
    }
    

    jetzt hab ich fünf verschiedene Sitze erstellt. Jeder hat dann seine eigene Farbe etc.
    Jetzt kann ich die Sitze zb in einer Liste speichern:

    list<Seat> sitzplaetze;
    sitzplaetze.push_back(Seat(gruen, Leder)); //einen für den "piloten"
    sitzplaetze.insert(Seat(rot, 20, sitzplaetze.end()); //20 sitzplätze für die passagiere
    
    sitzplaetze.size(); //anzahl der sitzplätze
    


  • also so ungefähr hab ich mir das auch vorgestellt aber danke für deine Ausführungen ... bin leider nicht so drin in C++

    Aber der Prof will das jede Klasse einen Konstruktor und Destruktor hat und dieser soll des Beispiels wegen auch benutzt werden

    class Seat {  //repräsentiert einen (!) Sitz 
    public: 
       Seat() {
           // das macht der Konstruktor
           Seat *p = new Seat; 
       }
       ~Seat() {
           // und nun der Dekonstruktor
           delete p;
       }
    
       void set_color (...); 
       void set_beschichtung (...); //wie auch immer 
    }; 
    
    int main () { 
      Seat einer, zweiter, dritter; 
      einer.set_color(gruen); 
      zweiter.set_color(rot); 
      dritter.set_color(schwarz_braun); 
    }
    

    ich dachte an sowas in der Art ... aber das geht ja nicht
    🤡 kann auch sein das ist jetzt völlig dämlich 🙄 sorry



  • vielleicht hilft dir das:

    enum Beschichtung { samt, leder, plastik };
    enum Farbe { rot, braun, gruen, blau, schwarz, silber, grau };
    
    class Seat {
      Beschichtung b; //Seat hat-eine beschichtung
      Farbe f;        //Seat hat-eine farbe
    public:
    
      Seat (Beschichtung b_, Farbe f_) : b(b_), f(f_) {}
      //Der Ctor initialisiert die elemente
    
      //ein selbstdefinierter Dtor ist hier nicht notwendig
    
      Beschichtung get_beschichtung () const { return b; }
      Farbe get_farbe () const { return f; }
    
      void streichen_mit (Farbe f_) { f = f_; }
      void neuer_ueberzug (Beschichtung b_) { b = b_; }
    };
    
    int main () {
    
       Seat vorne (leder,silber);
       Seat beifahrer (leder, grau);
    
       vorne.neuer_ueberzug(plastik);
       beifahrer.streichen_mit(blau);
    
       Seat *p = new Seat(samt, braun);
       p->neuer_ueberzug(leder);
    
       delete p; //Standard Dtor wird verwendet
    };
    

    ich hoffe das beispiel bringt klarheit.



  • erstmal vielen Dank für eure Hilfe.
    ..und schönen Abend

    MfG pietsche


Log in to reply