Forum: PC-Programmierung C++ Klasse in Array einbinden?


von Kai A. (kaiculon)


Lesenswert?

Hallo zusammen,

ich möchte in einer Klasse Instanzen einer zweiten Klasse in 
abhängigkeit einer dynamischen variablen anlegen und Daten in deren 
Variable ablegen. In C# kein Problem, nur in C++ klappt das wieder nicht 
weil ich es nicht schaffe ein dynamisches Array anzulegen.

header-Datei:
1
#pragma once
2
3
#define _USE_MATH_DEFINES
4
5
#include <iostream>
6
#include <cmath>
7
#include "Level.h"
8
9
10
11
class Pufferspeicher
12
{
13
  double Diameter;
14
  double Volume;
15
  double T1;
16
  double T2;
17
  int NumberOfLevel;
18
  static int NumberOfPuffer;
19
  Level* NLEVEL;
20
...
cpp-Datei Konstruktor:
1
Pufferspeicher::Pufferspeicher(double diameter, double volume, int numberoflevel)
2
{
3
  this-> Diameter = diameter;
4
  this-> Volume = volume;
5
  this-> NumberOfLevel = numberoflevel;
6
  NumberOfPuffer++;
7
  
8
  for (int i = 0; i <= NumberOfLevel; i++)
9
  {
10
    NLEVEL = new Level();
11
    NLEVEL->setTlevel(20.0);
12
    NLEVEL->setTconv(0.0);
13
    NLEVEL->setHeight(CalculateLevelHeight());
14
    NLEVEL->setVolume(CalculateLevelVolume());
15
  }
16
17
  
18
}
19
20
....
Ich möchte wieder auf die verschiedenen Instanzen und deren Variable 
zugreifen können. Jemand ne Idee wie ich das ohne Array machen kann.

Danke

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

wo ist genau dein Problem?

Ich könnte std::list die Lösung sein?

von Karl H. (kbuchegg)


Lesenswert?

Kai A. schrieb:

> zugreifen können. Jemand ne Idee wie ich das ohne Array machen kann.

... oder ein std::vector

Genau dazu ist der eigentlich gedacht.

Aber wenn du es unbedingt selbst dynamisch machen willst: Um das 
erzeugen eines Arrays wirst du nicht rumkommen. Also musst du eines in 
entsprechender Größe anlegen
1
Pufferspeicher::Pufferspeicher(double diameter, double volume, int numberoflevel)
2
{
3
  this-> Diameter = diameter;
4
  this-> Volume = volume;
5
  this-> NumberOfLevel = numberoflevel;
6
  NumberOfPuffer++;
7
8
  NLEVEL = new Level[ NumberOfLevel ];
9
  
10
  for (int i = 0; i < NumberOfLevel; i++)
11
  {
12
    NLEVEL[i].setTlevel(20.0);
13
    NLEVEL[i].setTconv(0.0);
14
    NLEVEL[i].setHeight(CalculateLevelHeight());
15
    NLEVEL[i].setVolume(CalculateLevelVolume());
16
  }
17
18
...

aber eigentlich willst du viel lieber einen der Standardcontainer 
benutzen. Denn das spart dir dann, dass du dich um den Destruktor, den 
Copy Construktor und den Assignment OPerator kümmern musst. Das alles 
erledigt std::vector für dich dann schon richtig.


> In C# kein Problem, nur in C++ klappt das wieder nicht weil ich
> es nicht schaffe ein dynamisches Array anzulegen.

Eigentlich klappt es nicht, weil du viel zu kompliziert denkst (denn in 
C# hast du ja auch nichts anderes gemacht als einen Standard-Container 
zu benutzen, der das Array für dich verwaltet) bzw. weil du wieder mal 
denkst, du könntest C++ programmieren, weil du ja schliesslich C# auch 
programmieren kannst und daher ein C++ Buch überflüssiger Luxus ist.

Der Unterschied zwischen den Sichtweisen in C# und C++ besteht darin, 
dass dir in C# die automatische Verwaltung ob du willst oder nicht aufs 
Auge gedrückt wird, während du in C++ die Wahl hast. Du kannst die 
Standard-Container benutzen, hast aber auch die Freiheit dich selbst um 
die dynamische Allokierung zu kümmern, wenn du das tun willst (und 
kannst).

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Kai A. schrieb:
> In C# kein Problem, nur in C++ klappt das wieder nicht
> weil ich es nicht schaffe ein dynamisches Array anzulegen.

Kai A. schrieb:
> for (int i = 0; i <= NumberOfLevel; i++)
>   {
>     NLEVEL = new Level();

Ich kenne zwar C# nicht besonders gut, aber der Code würde da bestimmt 
das gleiche machen wie in C++.

Kai A. schrieb:
> Ich möchte wieder auf die verschiedenen Instanzen und deren Variable
> zugreifen können. Jemand ne Idee wie ich das ohne Array machen kann.

Warum denn ohne Array?

von Borislav B. (boris_b)


Lesenswert?

Karl Heinz schrieb:
> Der Unterschied zwischen den Sichtweisen in C# und C++ besteht darin,
> dass dir in C# die automatische Verwaltung ob du willst oder nicht aufs
> Auge gedrückt wird, während du in C++ die Wahl hast.

Das stimmt so nicht. In C# hast du genauso die Wahl einen 
Standardcontainer zu verwenden, oder aber etwas Eigenes zu schreiben.
Letzteres ist jedoch meistens in keiner der beiden Sprachen sinnvoll.

von eric (Gast)


Lesenswert?

Kai A. schrieb:
> In C# kein Problem, nur in C++ klappt das wieder nicht
> weil ich es nicht schaffe ein dynamisches Array anzulegen.

Die Frage ist, wie dynamisch es überhaupt sein muss.
Solange die Größe zur Instanzierung bekannt ist und
sich nicht ändern muss, kann man das z.B. so machen:
1
class Bar {};
2
3
template<int N>
4
class Foo {
5
        public:
6
                Bar array[N];
7
};

Und dann anlegen mit:
1
Foo<100> f;

Nachteil ist, dass man für jedes N einen eigenen Datentyp
bekommt und die gewöhnungsbedürftige Syntax.

Mit Initialisierungslisten bekommt man im Konstruktor auch
Werte in const-Variablen. Hier funktioniert das nur leider nicht,
weil die Größe der Klasse nicht mehr konstant wäre.

Sonst ist ein std::vector vermutlich das Einfachste...

von Kai A. (kaiculon)


Lesenswert?

Hallo,

mit dem Vector funktioniert das ;) Happy Happy Joy Joy

Pufferspeicher::Pufferspeicher(double diameter, double volume, int 
numberoflevel)
{
  this-> Diameter = diameter;
  this-> Volume = volume;
  this-> NumberOfLevel = numberoflevel;
  CountPuffer++;

  std::vector<Level> NLevel = std::vector <Level>(NumberOfLevel);
  std::vector<Level>::iterator it_NLevel;

  for (it_NLevel = NLevel.begin(); it_NLevel != NLevel.end(); 
it_NLevel++)
  {
    it_NLevel->setTlevel(20.0);
    it_NLevel->setTconv(0.0);
    it_NLevel->setHeight(CalculateLevelHeight());
    it_NLevel->setVolume(CalculateLevelVolume());
  }

  for (it_NLevel = NLevel.begin(); it_NLevel != NLevel.end(); 
it_NLevel++)
  {
    std::cout << it_NLevel->getTlevel() << std::endl;
    std::cout << it_NLevel->getTconv() << std::endl;
    std::cout << it_NLevel->getHeight() << std::endl;
    std::cout << it_NLevel->getVolume() << std::endl;
  }

}

Danke für die Hilfe.

von Dr. Sommer (Gast)


Lesenswert?

Kai A. schrieb:
> std::vector<Level> NLevel = std::vector <Level>(NumberOfLevel);
Das ist so eine Java-Seuche, oder? Das geht so:
1
NLevel.resize (NumberOfLevel);
Oder noch besser per Initializer-List:
1
Pufferspeicher::Pufferspeicher(double diameter, double volume, int 
2
numberoflevel) : NLevel(numberoflevel) {
3
 ...

Kai A. schrieb:
> for (it_NLevel = NLevel.begin(); it_NLevel != NLevel.end();
> it_NLevel++)
>   {
>     it_NLevel->setTlevel(20.0);
>     it_NLevel->setTconv(0.0);
>     it_NLevel->setHeight(CalculateLevelHeight());
>     it_NLevel->setVolume(CalculateLevelVolume());
>   }
Das braucht man so nicht mehr, das geht jetzt auch so:
1
for (auto& it_NLevel : NLevel) {
2
  it_NLevel.setTlevel (20.); ...
Oder noch besser - warum diese Werte nicht direkt in der "Level"-Klasse 
im Konstruktor zuweisen? Dann entfällt die Schleife komplett und die 
Initialisierung geschieht automatisch durch Initialisierung oder 
Vergrößern des std::vector.

von Kai A. (kaiculon)


Lesenswert?

Dr. Sommer schrieb:
> Kai A. schrieb:
>> std::vector<Level> NLevel = std::vector <Level>(NumberOfLevel);
> Das ist so eine Java-Seuche, oder? Das geht so:NLevel.resize
> (NumberOfLevel);

Ich programmiere noch nicht nicht lange ;) C++ hat mir tatsächlich ein 
Java-Entwickler beigebracht. Schwöhr auf JAVA digga ;)

Dr. Sommer schrieb:
> Oder noch besser per
> Initializer-List:Pufferspeicher::Pufferspeicher(double diameter, double
> volume, int
> numberoflevel) : NLevel(numberoflevel) {

Das finde ich interessant. Hab ich bis jetzt noch keine Erfahrung mit 
gemacht, ich versuche das mal.

Gruß

von Kai A. (kaiculon)


Lesenswert?

Ich verstehe nicht warum Beispiel 1 nicht funktioniert. Wie funktioiert 
auto?

Beispiel 1:
1
  for (auto it_NLevel : NLevel)
2
  {
3
    it_NLevel->setTlevel(20.0);
4
    it_NLevel->setTconv(0.0);
5
    it_NLevel->setHeight(CalculateLevelHeight());
6
    it_NLevel->setVolume(CalculateLevelVolume());
7
  }


Beispiel 2:
1
  for (auto& it_NLevel : NLevel)
2
  {
3
    it_NLevel.setTlevel(20.0);
4
    it_NLevel.setTconv(0.0);
5
    it_NLevel.setHeight(CalculateLevelHeight());
6
    it_NLevel.setVolume(CalculateLevelVolume());
7
  }

von tictactoe (Gast)


Lesenswert?

Kai A. schrieb:
> Ich verstehe nicht warum Beispiel 1 nicht funktioniert. Wie funktioiert
> auto?
>
> Beispiel 1:  for (auto it_NLevel : NLevel)
>   {
>     it_NLevel->setTlevel(20.0);
>     it_NLevel->setTconv(0.0);
>     it_NLevel->setHeight(CalculateLevelHeight());
>     it_NLevel->setVolume(CalculateLevelVolume());
>   }
>
> Beispiel 2:
>   for (auto& it_NLevel : NLevel)
>   {
>     it_NLevel.setTlevel(20.0);
>     it_NLevel.setTconv(0.0);
>     it_NLevel.setHeight(CalculateLevelHeight());
>     it_NLevel.setVolume(CalculateLevelVolume());
>   }

Lassen wir erst mal 'auto' aus dem Spiel. Dann würdest du so schreiben 
müssen, damit es funktioniert (ich lass das 'it_' mal weg, weil das ist 
schon die nächste Verwirrung):
1
for (Level& l : NLevel)
2
{
3
  l.setTlevel(20.0);
4
  //...
5
}
Die Variable 'l' ist hier nicht ein Iterator, der auf ein Element zeigt, 
sondern wird für jeden Schleifendurchlauf mit dem Element des Containers 
Nlevel initialisiert. Im Hintergrund wird tatsächlich ein Iterator 
dereferenziert.

Jetzt willst du beim Initialisieren ja, dass du die Elemente im Vektor 
beschreibst. Daher darf die Initialisierung von 'l' für den aktuellen 
Schleifendurchlauf nicht eine Kopie erzeugen. Daher deklarieren wir 'l' 
als Referenz (das '&' davor). Dadurch wirkt der 'setTlevel'-Aufruf auf 
das Element im Container, und nicht auf eine Kopie davon.

Würdest du jetzt schreiben:
1
for (Level l : NLevel)
2
{
3
  l.setTlevel(20.0);
4
  //...
5
}
(ohne Referenz), dann wird 'l' immer mit einer Kopie des 
Container-Elements initialisiert, und 'setTlevel' wirkt auf die Kopie 
und nicht auf das Element im Container.

Schreibst du jetzt aber sogar
1
for (Level l : NLevel)
2
{
3
  l->setTlevel(20.0);
4
  //...
5
}
dann mault der Compiler, weil der Typ 'Level' kein Pointer ist und auch 
keinen operator-> definiert hat.

Das hat bisher alles nichts mit 'auto' zu tun, und 'auto' ändert auch 
nichts an den Fehlersituationen. In deinen beiden Beispielen bewirkt es 
nur, dass der Compiler sich den Typ der Container-Elemente ('Level') 
selbst ausrechnen soll.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.