Forum: PC-Programmierung C++ Objektarray im Konstruktor initialisieren?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Werner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Moin,

ich habe eine Reifen-Klasse und verschiedene Fahrzeugklassen. Jedes 
Fahrzeug kann unterschiedlich viel Reifen haben, die Anzahl der Reifen 
desselben Fahrzeugtyps ändert sich aber nie. Im folgenden ist der 
"Pseudecode", den ich so in C++ aber nicht umgesetzt bekomme; Das 
Befüllen des Reifenarrays in der abgeleiteten Klasse geht so nicht. 
Hätte jemand eine Idee wie man das umsetzen kann?

Wernder
1
class Reifen {
2
public:
3
    Reifen(int breite) {}
4
};
5
6
class Fahrzeug {
7
private:
8
    Reifen reifen[];
9
};
10
11
class Auto: public Fahrzeug {
12
public:
13
    Auto(): reifen({100, 100, 120, 120}) //hier sollen die 4 Reifenobjekte erzeugt werden
14
};

von rmu (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Erstens kann man in der abgeleiteten Klasse nicht direkt auf private 
member der Basisklasse zugreifen.

Zweitens muss die Größe des Arrays fixiert werden (zur 
Übersetzungszeit), der Compiler muss wissen, wie groß das Objekt ist.

Unter diesen Voraussetzungen gehts ab C++11, man muss aber 
{}-initializer verwenden.

von Werner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ja, muss natürlich protected sein. C++11 steht leider nicht zur 
Verfügung :-(

>Zweitens muss die Größe des Arrays fixiert werden (zur
>Übersetzungszeit), der Compiler muss wissen, wie groß das Objekt ist.

Es muss eben je nach Klasse unterschiedlich groß sein (z.B. Auto 4, 
Fahrrad 2). Da das in C++ so nicht geht suche ich nach einem anderen 
Konzept. Zusätzlich handelt es sich noch dazu um einen älteren Keil 
(µVision4) für eine Embedded Platform, so dass die STL auch nicht zur 
Verfügung steht.

Werner

von rmu (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenns in jeder abgeleiteten Klasse unterschiedlich gross ist, dann muss 
das Array in der abgeleiteten Klasse deklariert werden, oder man erbt 
von einer template-basis-klasse, die man mit der größe des arrays 
spezialisiert, aber vermutlich geht das mit dem compiler nicht.

Die Elemente des Arrays kann man einzeln explizit initialisieren, bläht 
den Text halt a bissl auf, codesize sollte gleich bleiben. IIRC gibts da 
ein boost-ding was einem die Arbeit abnimmt, von dessen impl könnte man 
sich inspirieren lassen.

von Peter II (Gast)


Bewertung
0 lesenswert
nicht lesenswert
warum muss es denn ein Array sein - C++ bietet auch Vektor, List und 
ähnliches an. Dann kann die Größe zur Laufzeit festgelegt werden.

ein Array könnte man auch dynamische allokieren.

von Schneck (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Peter II schrieb:
> warum muss es denn ein Array sein - C++ bietet auch Vektor, List
> und ähnliches an.

>> die STL auch nicht zur Verfügung steht

Allerdings ist "PC-Programmierung" das falsche Unterforum für die Frage 
(der TO hätte zumindest die C++-Version und die Restriktionen gleich 
erwähnen sollen).

von Werner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Wenns in jeder abgeleiteten Klasse unterschiedlich gross ist, dann muss
>das Array in der abgeleiteten Klasse deklariert werden,

Dann folgende Idee:
1
class Fahrrad: public Fahrzeug {
2
private:
3
  Reifen reifen[2];
4
public:
5
  Fahrrad(): reifen(Reifen(10), Reifen(20)) {}
6
};

Geht das so? Wenn ja wie lautet die Syntax im Konstruktor um das 
reifen-array zu initialisieren?

Werner

von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
statt
1
Fahrrad(): reifen(Reifen(10), Reifen(20)) {}
1
Fahrrad(): reifen{Reifen(10), Reifen(20)}{}

von Peter II (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Werner schrieb:
> Geht das so?

nein.

Denn ein Objekt von einen Type brauch auch eine definierte Größe.

was soll denn sizeof( Fahrrad ) liefern?


Man könnte es mit Templates lösen.

von Werner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>statt
>Fahrrad(): reifen(Reifen(10), Reifen(20)) {}
>Fahrrad(): reifen{Reifen(10), Reifen(20)}{}

Also kompilierbares Beispiel:
1
class Reifen {
2
public:
3
    Reifen(int breite) {}
4
};
5
6
class Fahrrad {
7
private:
8
    Reifen reifen[2];
9
public:
10
    Fahrrad(): reifen{(10), (10)} {}
11
};

Ärgerlich, das geht z. B. mit dem g++ 7.1.1 wunderbar, aber der olle 
Keil 4 sagt (selber Code!) zur Zeile mit dem Fahrrad-Ctor:

error: expected a declaration
error: expected a "("
error: no default constructor exists for class "Reifen"
warning: expression has no effect
warning: expression has no effect
error: expected a ";"

>Man könnte es mit Templates lösen.
Du meinste die Arraygröße über ein Template festlegen? Ja, beim obigen 
Fahrrad habe ich ja schon ein Array fester Größe, aber der Keil 
kompiliert das nicht :-(

Werner

von cbe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ohne C++-11 könntest du dir so behelfen
1
class Reifen {
2
public:
3
    Reifen(int breite) {
4
    }
5
    ~Reifen() {
6
    }
7
};
8
9
class Fahrzeug {
10
protected:
11
    Reifen *reifen;
12
};
13
14
class Auto : public Fahrzeug {
15
public:
16
   Auto() {
17
      reifen = (Reifen*)malloc(sizeof(Reifen[4]));
18
      for(int i = 0; i < 4; ++i)
19
         new (&reifen[i]) Reifen(245);
20
   }
21
   ~Auto() {
22
      for(int i = 0; i < 4; ++i) {
23
         reifen[i].~Reifen();
24
      }
25
      free(reifen);
26
   }
27
};

von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenn es nicht so richtig will, warum mit dem Kopf durch die Wand?

Du must es ja nicht über die Init Liste machen. Weise den Variablen 
einfach den wert im Ctor zu.
1
  class Fahrrad {
2
private:
3
    Reifen reifen[2];
4
public:
5
    Fahrrad() {
6
        reifen[0].breite = 10;
7
        reifen[1].breite = 20;
8
    }
9
};

von Werner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Wenn es nicht so richtig will, warum mit dem Kopf durch die Wand?

Ja warscheinlich muss ich es so machen :-( :-(  Schade, wäre anders 
deutlich kompakter geworden...

Werner

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
2 lesenswert
nicht lesenswert
cbe schrieb:
> reifen = (Reifen*)malloc(sizeof(Reifen[4]));
>       for(int i = 0; i < 4; ++i)
>          new (&reifen[i]) Reifen(245);

Sorry, aber malloc und new zu mischen ist Gewurschtel.

von Sebastian E. (sbe_15)


Bewertung
1 lesenswert
nicht lesenswert
1
new (&reifen[i]) Reifen(245);
ruft nur den Konstruktor auf &reifen[i] auf. Es wird kein Speicher 
allokiert.
Speicher mit new holen und mit free freigeben, bzw. mit malloc holen und 
mir delete freigeben ist in der Tat Unfug. Den Fall haben wir hier aber 
nicht.

: Bearbeitet durch User
von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Sebastian E. schrieb:
> ruft nur den Konstruktor auf &reifen[i] auf. Es wird kein Speicher
> allokiert.

Es bleibt aber trozdem dabei, dass

Rufus Τ. F. schrieb:
> Sorry, aber malloc und new zu mischen ist Gewurschtel.

Richtig ist. In C++ nimmt man new und kein malloc. Das ist schlich nicht 
nötig. Eigentlich benutzt man new auch nicht nicht mehr seit C++14. 
Dafür gibts Smartpointer.

Der C++ Weg wäre einen enprechenden Container zu nehmen.
1
   std::vector<Reifen> reifen;
2
3
   for (auto i: {20,30})
4
        reifen.push_back(i)

damig. Darf ja kein modernes C++ sein. Dann also mit einer normalen for 
Schleife (die Mühe sie zu schreiben mache ich mal nicht).

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
cbe schrieb:
> reifen = (Reifen*)malloc(sizeof(Reifen[4]));
>       for(int i = 0; i < 4; ++i)
>          new (&reifen[i]) Reifen(245);
>    }

Warum denn malloc und placement new statt einfach normales new?

nicht"Gast" schrieb:
> Der C++ Weg wäre einen enprechenden Container zu nehmen.
>    std::vector<Reifen> reifen;
>
>    for (auto i: {20,30})
>         reifen.push_back(i)

Warum dann nicht gleich:
1
std::vector<Reifen> reifen { 20, 30 };
?

> damig. Darf ja kein modernes C++ sein.

Und keine Standardlib.

> Dann also mit einer normalen for Schleife (die Mühe sie zu schreiben
> mache ich mal nicht).

Und ohne vector. Damit sind wir wieder beim new.

von cbe (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Warum denn malloc und placement new statt einfach normales new?

Dann eben nur new.
1
class Fahrzeug {
2
protected:
3
    Reifen **reifen;
4
};
5
6
class Auto : public Fahrzeug {
7
public:
8
   Auto() {
9
      reifen = new Reifen*[4];
10
      for(int i = 0; i < 4; ++i)
11
         new Reifen(245);
12
   }
13
   ~Auto() {
14
      for(int i = 0; i < 4; ++i) {
15
         delete reifen[i];
16
      }
17
      delete reifen;
18
   }
19
};

In der Variante ist IMHO auch am nähesten an der Probelmstellung des TO.

Also für Versionen < C++11 und ohne STL finde ich die Lösung gar nicht 
mal so schlecht.
Wobei mir persönlich die Version mit malloc und placement new besser 
gefallen hat, da alle 4 Instanzen direkt hintereinander liegen - also 
wie im Array des TO, nur eben erzeugt mit nicht Standartkonstruktoren.

Rufus Τ. F. schrieb:
> Sorry, aber malloc und new zu mischen ist Gewurschtel.

Statt malloc könnte man den Speicher natürlich auch mit new 
allokieren...

von Tom (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Es geht auch ohne new oder malloc, wenn man Platz für einen Pointer 
verschwenden kann.
1
class Fahrzeug 
2
{
3
protected:
4
    Reifen* reifen;
5
};
6
7
class Auto : public Fahrzeug 
8
{
9
public:
10
   Auto() 
11
   {
12
      reifen = meine_reifen;
13
      for(int i = 0; i < 4; ++i)
14
          meine_reifen[i] = Reifen(245); // oder placement new
15
   }
16
private:
17
    Reifen meine_reifen[4];
18
};

von nicht"Gast" (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> std::vector<Reifen> reifen { 20, 30 };

aber ich mag doch die neue for Schleife so :)

von Werner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Es geht auch ohne new oder malloc, wenn man Platz für einen Pointer
>verschwenden kann.

Da motzt der Compiler, weil es keinen Standardkonstruktor für Reifen 
gibt, man müsste die Reifen schon in der Initialisierungsliste (nach dem 
Doppelpunkt) des Konstruktors setzen...

Werner

Beitrag #5137510 wurde von einem Moderator gelöscht.
Beitrag #5137741 wurde von einem Moderator gelöscht.
Beitrag #5137787 wurde von einem Moderator gelöscht.
Beitrag #5137832 wurde von einem Moderator gelöscht.
Beitrag #5137918 wurde von einem Moderator gelöscht.
Beitrag #5137936 wurde von einem Moderator gelöscht.
Beitrag #5137980 wurde von einem Moderator gelöscht.
Beitrag #5137981 wurde von einem Moderator gelöscht.
Beitrag #5138003 wurde von einem Moderator gelöscht.
Beitrag #5138083 wurde von einem Moderator gelöscht.
Beitrag #5138351 wurde von einem Moderator gelöscht.
Beitrag #5138521 wurde von einem Moderator gelöscht.
Beitrag #5139158 wurde von einem Moderator gelöscht.
Beitrag #5139160 wurde von einem Moderator gelöscht.
Beitrag #5139981 wurde von einem Moderator gelöscht.
Beitrag #5139984 wurde von einem Moderator gelöscht.
Beitrag #5140100 wurde von einem Moderator gelöscht.
Beitrag #5140185 wurde von einem Moderator gelöscht.
Beitrag #5140241 wurde von einem Moderator gelöscht.
Beitrag #5140382 wurde von einem Moderator gelöscht.
Beitrag #5142598 wurde von einem Moderator gelöscht.
Beitrag #5143772 wurde von einem Moderator gelöscht.
Beitrag #5144965 wurde von einem Moderator gelöscht.
Beitrag #5144997 wurde von einem Moderator gelöscht.
Beitrag #5145003 wurde von einem Moderator gelöscht.
Beitrag #5145233 wurde von einem Moderator gelöscht.
Beitrag #5145939 wurde von einem Moderator gelöscht.
Beitrag #5145964 wurde von einem Moderator gelöscht.
Beitrag #5148073 wurde von einem Moderator gelöscht.
Beitrag #5149299 wurde von einem Moderator gelöscht.
Beitrag #5149362 wurde von einem Moderator gelöscht.
Beitrag #5149383 wurde von einem Moderator gelöscht.
Beitrag #5149418 wurde von einem Moderator gelöscht.
Beitrag #5153245 wurde von einem Moderator gelöscht.
Beitrag #5167778 wurde von einem Moderator gelöscht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.