Forum: Compiler & IDEs In Konstruktor dynamisch instanz einer Klasse generieren, vererbung, C++


von Matze (Gast)


Lesenswert?

Hallo zusammen,

Ich möchte einen LED-String aus WS2812B ansteuern können.

Dazu habe ich einen Treiber der die Bits auf der HW Rausschreibt.
-->Funktioniert.

Eine Klasse RGB_LED, welche die eigenschaften(Farbe) der LED enthält.
-->Funktioniert.

Eine Klasse RGB_STRING welche eine Anzahl an RGB_LEDs enthalten soll.
Sie soll über einen Aufruf von write_to_string() die eigenschaften aller 
LEDs an den String übertragen.

Weiterhin soll sie Farben, der LED nach Index einstellbar machen.
set_RGB_LED(uint8_t index, uint8_t red, uint8_t green, uint8_t blue)

Durch den Construktor soll ein Array mit zeigern auf die Elemente vom 
Typ LED_String angelegt werden, durch welches die oben genannten 
Funktionen von RGB_STRING durchitterieren können.

Hier leigt das Problem mit der Meldung:
Error : expected type-specifier before ';' token

In dieser Zeile:
RGB_STRING::string[i]=*new(RGB_LED());

Ich bin überfragt welchen Typ ich hier angeben soll.

Wäre schön wenn jemand eine idee hätte.
Weitere Fehler/Warungen gibt es nicht.

Hier der gesamte Code:
1
class RGB_LED
2
{
3
  public:
4
  RGB_LED();
5
  void set_LED(void);
6
  void set_colors(uint8_t r, uint8_t g, uint8_t b);
7
  private:
8
  uint8_t red;
9
  uint8_t green;
10
  uint8_t blue;
11
};
12
13
RGB_LED::RGB_LED()
14
{
15
  RGB_LED::red=0x00;
16
  RGB_LED::green=0xff;
17
  RGB_LED::blue=0x00;
18
}
19
20
void RGB_LED::set_colors(uint8_t r, uint8_t g, uint8_t b)
21
{
22
  red = r;
23
  blue = b;
24
  green = g;
25
};
26
27
void RGB_LED::set_LED()
28
{
29
  RGB_LED_write(RGB_LED::green,RGB_LED::red,RGB_LED::blue);
30
};
31
32
class RGB_STRING : public RGB_LED
33
{
34
  public:
35
    RGB_STRING(uint8_t led_cnt);
36
    void set_RGB_LED(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
37
    void write_RGB_STRING();
38
  private:
39
    uint8_t number_of_LEDs;
40
    RGB_LED string[];
41
};
42
43
RGB_STRING::RGB_STRING(uint8_t led_cnt)
44
{
45
    RGB_STRING::number_of_LEDs = led_cnt;
46
    for (int i=0; i < number_of_LEDs;i++)
47
    {
48
      RGB_STRING::string[i]=*new(RGB_LED()); //Problemzeile!!
49
    }
50
}
51
52
void RGB_STRING::set_RGB_LED(uint8_t index, uint8_t red, uint8_t green, uint8_t blue)
53
{
54
  for (int i=0; i < RGB_STRING::number_of_LEDs;i++)
55
  {
56
    RGB_STRING::string[i].set_colors(red,green,blue);
57
  }
58
}
59
60
void RGB_STRING::write_RGB_STRING()
61
{
62
  for (int i=0; i < RGB_STRING::number_of_LEDs;i++)
63
  {
64
    RGB_STRING::string[i].set_LED();
65
  }
66
}
67
68
69
70
int main(void)
71
{
72
  RGB_STRING LED_Chain(3);
73
    while(1)
74
    {
75
    for (int i=0;i<3;i++)
76
    {
77
      LED_Chain.set_RGB_LED(i,0xff,0xff,0xff);
78
    }
79
    LED_Chain.write_RGB_STRING();
80
    _delay_ms(10);
81
    }
82
}

Schöne Grüße,
Matze

: Verschoben durch Moderator
Beitrag #6501458 wurde von einem Moderator gelöscht.
von Carl D. (jcw2)


Lesenswert?

Du erzeugst eine RGB_LED Instanz auf dem Heap und übergibst deren 
Adresse an ein "placement new", d.h. new soll an der übergebenen Adresse 
eine Instanz des nach new(addr) folgende Typs erzeugen, also dessen 
Konstruktor ausführen. Genau dieser Typ wird vermisst.
Daß du dieses Objekt nur kurz leben läßt, nämlich bis es vom Assignment 
Operator in einen Slot deines Arrays kopiert wurde, ist zwar syntaktisch 
korrekt, aber ungeschickt.
Generell: in der Implementierung einer Methode einer Klasse hat man 
Zugriff auf die andern Member der Klasse, ohne den "Klassen-Namespace" 
davorzuschreiben.

von Matze (Gast)


Lesenswert?

Hallo und vielen Dank,

so war es nicht gedacht, new soll nicht an der übergebenen Addresse ein 
element des fehlenden Typs erzeugen.

Ich stelle es mit so vor, dass LED_STRING die zeiger auf die einzelnen 
LEDs in string[] enthält.

Da ich die größe von String nicht fix festlegen möchte, soll sie 
variabel sein. Nach Programmstart in String ein zeiger auf die 
Basisaddresse eines  Arrays von RGB_LED stehen.

Oh, ich habe nun eine Lösung gefunden :)

Hier meine Änderungen in RGB_STRING:
1
class RGB_STRING : public RGB_LED
2
{
3
  public:
4
    RGB_STRING(uint8_t led_cnt);
5
    void set_RGB_LED(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
6
    void write_RGB_STRING();
7
  private:
8
    uint8_t number_of_LEDs;
9
    RGB_LED* string[];
10
};
11
12
RGB_STRING::RGB_STRING(uint8_t led_cnt)
13
{
14
    RGB_STRING::number_of_LEDs = led_cnt;
15
    for (int i=0; i < number_of_LEDs;i++)
16
    {
17
      RGB_STRING::string[i*sizeof(RGB_LED)]=(RGB_LED*)malloc(sizeof(RGB_LED));
18
    }
19
}
20
21
void RGB_STRING::set_RGB_LED(uint8_t index, uint8_t red, uint8_t green, uint8_t blue)
22
{
23
  for (int i=0; i < RGB_STRING::number_of_LEDs;i++)
24
  {
25
    RGB_STRING::string[i*sizeof(RGB_LED)]->set_colors(red,green,blue);
26
  }
27
}
28
29
void RGB_STRING::write_RGB_STRING()
30
{
31
  for (int i=0; i < RGB_STRING::number_of_LEDs;i++)
32
  {
33
    RGB_STRING::string[i*sizeof(RGB_LED)]->set_LED();
34
  }
35
}

Es funktioniert bis auf einen kleinen BUG, wenn in main() keine farbe 
gesetzt wird, bleiben die LEDs aus.
--> Folglich wird der Konstruktor nicht aufgerufen.
Wenn ich in den Konstruktor von RGB_String nach dem Anlegen der neuen 
LED:
1
RGB_STRING::string[i*sizeof(RGB_LED)]->RGB_LED();
kommt die Meldung:
Error invalid use of 'RGB_LED::RGB_LED'  Ver3_1_Atmega8

Bei
1
RGB_STRING::string[i*sizeof(RGB_LED)]->RGB_LED::RGB_LED();
bekomme ich ein:
Error cannot call constructor 'RGB_LED::RGB_LED' directly

Wäre super wenn noch jemand wüsste warim die Klasse ohne 
Konstruktoraufrif angelegt werden kann?

Denke ich korrekt, wenn ich davon ausgehe, dass die RGB_LED-Objekte nun 
ab der basisaddresse des strings im Speicher liegen?

Grüße,
Matze

von Rolf M. (rmagnus)


Lesenswert?

Matze schrieb:
> so war es nicht gedacht, new soll nicht an der übergebenen Addresse ein
> element des fehlenden Typs erzeugen.

Du nutzt hier aber placement new:

> RGB_STRING::string[i]=*new(RGB_LED());

Placement new sieht etwa so aus:
1
new(wert) Typ(Parameter);
Bei dir fehlt der Typ. Wenn du ein normales new willst, musst du die 
Klammern weglassen.
Aber auch dann ergibt das alles so keinen Sinn. Du hast ein Element vom 
Typ RGB_STRING, und nun erzeugst du ein neues dynamisches Objekt vom 
gleichen Typ und weist das diesem Element zu. Den Zeiger auf das 
dynamische Objekt verwirfst du dann und hast damit ein Memory-Leak.
Was mir noch auffällt:
RGB_STRING ist von RGB_LED abgeleitet. Warum?
Dem Array RGB_LED string[]; fehlt eine Größe.
Auch das ergibt in mehrererlei Hinsicht keinen Sinn:
1
> RGB_STRING::string[i*sizeof(RGB_LED)]=(RGB_LED*)malloc(sizeof(RGB_LED));

> Bei
> RGB_STRING::string[i*sizeof(RGB_LED)]->RGB_LED::RGB_LED();
> bekomme ich ein:
> Error cannot call constructor 'RGB_LED::RGB_LED' directly

Da hat der Compiler recht. Konstruktoren kann man nicht direkt aufrufen.

> Wäre super wenn noch jemand wüsste warim die Klasse ohne
> Konstruktoraufrif angelegt werden kann?

Das weiß ich auch nicht. Da dem Array die Größe fehlt, hätte ich 
erwartet, dass schon dort mit Fehler abgebrochen wird. Aber gcc lässt 
das wohl als Erweiterung selbst im Standard-Modus durchgehen. Wie das 
funktionieren soll, ist mir aber nicht klar.
Wenn das sauber funktionieren soll, wirst du nicht drum herum kommen, 
ein paar Grundlagen von C++ zu lernen.

Beitrag #6502564 wurde von einem Moderator gelöscht.
von Erik S. (erik_s)


Lesenswert?

Da sind einige Ungereimtheiten, Undurchgängigkeiten und Lücken im 
Grundlagenwissen zu finden. Anbei mein Vorschlag basierend auf dem, was 
ich als gewünschte Funktionalität vermute. Nicht übermäßig schön, aber 
funktionsfähig und der Heap wird dank Destruktor auf wieder freigegeben.
1
#include <memory>
2
3
class RGB_LED
4
{
5
  public:
6
    RGB_LED();
7
    void set_LED(void);
8
    void set_colors(uint8_t r, uint8_t g, uint8_t b);
9
  private:
10
    uint8_t red;
11
    uint8_t green;
12
    uint8_t blue;
13
};
14
15
16
17
RGB_LED::RGB_LED()
18
{
19
  set_colors(0x00, 0xff, 0x00);
20
// sofern die LED jetzt bereits grün leuchten sollte: 
21
  set_LED();
22
}
23
24
25
26
void RGB_LED::set_colors(uint8_t r, uint8_t g, uint8_t b)
27
{
28
  red = r;
29
  blue = b;
30
  green = g;
31
};
32
33
34
void RGB_LED::set_LED()
35
{
36
  RGB_LED_write(RGB_LED::green,RGB_LED::red,RGB_LED::blue);
37
};
38
39
40
class RGB_STRING
41
{
42
  public:
43
    RGB_STRING(uint8_t led_cnt);
44
    void set_RGB_LED(uint8_t index, uint8_t red, uint8_t green, uint8_t blue);
45
    void set_RGB_STRING();
46
    uint8_t get_led_cnt(void) const { return m_led_cnt; }
47
    ~RGB_STRING();
48
    
49
  private:
50
    uint8_t m_led_cnt;
51
    RGB_LED* (*m_p_leds)[]; // Pointer auf ein Array von Pointern auf RGB_LED
52
};
53
54
55
56
RGB_STRING::RGB_STRING(uint8_t led_cnt)
57
{
58
  m_p_leds =(RGB_LED*(*)[])malloc(led_cnt * sizeof(RGB_LED*)); // Speicher für Pointer-Array(RGB_LEDs) allokieren
59
  m_led_cnt = led_cnt;
60
  
61
  for(uint8_t i=0; i<m_led_cnt; i++){
62
    (*m_p_leds)[i] = new RGB_LED; // RGB-LED auf Heap instanziieren und Adresse in Pointer-Array ablegen. new sorgt dafür, dass der Konstruktor aufgerufen wird.
63
  }
64
}
65
66
67
68
void RGB_STRING::set_RGB_LED(uint8_t index, uint8_t red, uint8_t green, uint8_t blue)
69
{
70
  (*m_p_leds)[index]->set_colors(red,green,blue);
71
}
72
73
74
75
void RGB_STRING::set_RGB_STRING()
76
{
77
  for (int i=0; i < m_led_cnt; i++)
78
  {
79
    (*m_p_leds)[i]->set_LED();
80
  }
81
}
82
83
84
RGB_STRING::~RGB_STRING(){
85
  for(uint8_t i=0; i<m_led_cnt; i++){
86
    delete (*m_p_leds)[i]; // allokierten Speicher der RGB_LEDs freigeben
87
  }
88
  free(m_p_leds);  // allokierten Speicher des Pointer-Array(RGB_LEDs) freigeben
89
}
90
91
92
void main()
93
{
94
  {    
95
    RGB_STRING LED_Chain(3);
96
   
97
    for (int i=0;i<LED_Chain.get_led_cnt();i++)
98
    {
99
      LED_Chain.set_RGB_LED(i,0xff,0xff,0xff);
100
    }
101
    LED_Chain.set_RGB_STRING();
102
  }
103
}

: Bearbeitet durch User
von Dirk K. (merciless)


Lesenswert?

Warum verwendest du nicht std::vector<RGB_LED>
(oder std::vector<RGB_LED *>) anstelle des C-Arrays?

merciless

Beitrag #6507274 wurde von einem Moderator gelöscht.
Beitrag #6507349 wurde von einem Moderator gelöscht.
Beitrag #6508622 wurde von einem Moderator gelöscht.
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.