Forum: Mikrocontroller und Digitale Elektronik Arduino / C++ - Objekt an Klasse übergeben (Referenz, Zeiger??)


von Yannik (Gast)


Lesenswert?

Hi,

ich habe folgendes Problem :

Ich habe in meinem Code ein Objekt "strip" vom Typ Adafruit_NeoPixel
1
Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, STRIP_PIN, NEO_GRB + NEO_KHZ800);

Nun möchte ich dieses Objekt an eine andere Klasse übergeben, so dass 
diese das Objekt selbst manipulieren kann.

Ich habe leider noch nicht viel Ahnung von Referenzen und Zeigern usw.

Ich habe erstmal das ganze probiert indem ich das Objekt an eine Methode 
innerhalb meines Codes übergebe :
1
void setup()
2
{
3
  delay(2000);
4
  Serial.begin(115200); //For Debugging
5
  delay(50);
6
  
7
  strip.begin(); //Strip(s) initialisieren
8
  strip.show();  //Initialize all pixels to 'off'
9
  
10
  Serial.print("Color will be : "); Serial.println(farben[0]);
11
  Serial.print("Color is : "); Serial.println(strip.getPixelColor(0));
12
  changeColor(strip);
13
  Serial.print("After Function Color is : "); Serial.println(strip.getPixelColor(0));
14
  
15
}
16
17
void loop() {}
18
19
20
void changeColor(Adafruit_NeoPixel &stripToChange)
21
{
22
  stripToChange.setPixelColor(0, farben[0]);  
23
  Serial.print("In Function Color is : "); Serial.println(stripToChange.getPixelColor(0));
24
}

Als Augabe bekomme ich dann :
1
Color will be : 16711680
2
Color is : 0
3
In Function Color is : 16711680
4
After Function Color is : 16711680

So soll es auch sein ;)

Jetzt könnte ich das ganze analog ja auch an eine Klasse übergebn, kein 
Problem..

Ich möchte aber ein Objekt meiner Klasse erstellen und beim Erstellen 
des Objektes an den Konstruktor nur ein mal das Objekt "strip" 
übergeben, und die Klasse soll sich das merken und bei späteren aufrufen 
immernoch wissen, wo das Objekt "strip" ist.

Das Problem ist ja dass ich "stripToChange" nur innerhalb des 
Konstruktors verwenden kann, ist der Kontruktor fertig, wird auch dieser 
Zeiger(ist es einer?) gelöscht. Ich möchte also diesen Zeiger als 
globale Variable in meiner Klasse speichern, damit meine Klasse immer 
wieder darauf zugreifen kann.

Wie das bei Integern z.B. geht ist ein Problem, da kann ich ja vorher 
einen globalen Integer definieren und dann einfach den Wert zuweisen.

Aber ich kann ja keine leere Referenz erzeugen?! Und wenn ich das erst 
im Konstruktr definiere ist es ja auch wieder weg und für andere 
Methoden nicht mehr benutzbar.


Ich hoffe ich konnte mein Problem halbwegs verständlich darstellen. Wäre 
super, wenn ihr da eine Lösung für mich hättet!

von Tom (Gast)


Lesenswert?

Meinst Du das so?
1
#include <iostream>
2
3
class LED
4
{
5
public:
6
    void blink()
7
    {
8
        std::cout << "blink\n";
9
    }
10
};
11
12
class Blinks0r
13
{
14
public:
15
    Blinks0r(LED& l): my_led(l)
16
    {
17
    }
18
    void doit()
19
    {
20
        my_led.blink();
21
    }
22
private:
23
    LED& my_led;
24
};
25
26
int main()
27
{
28
    LED gelbe_led;
29
    Blinks0r zappel_licht(gelbe_led);
30
    zappel_licht.doit();
31
}

von Stefan F. (Gast)


Lesenswert?

> Aber ich kann ja keine leere Referenz erzeugen

Genau, dann nimmt man Zeiger.

von Stefan F. (Gast)


Lesenswert?

Im Konstruktor kannst du auch Referenzen speichern (wie im obigen 
Beispiel gezeigt), aber nur dort - soweit ich weiß.

von Yannik (Gast)


Lesenswert?

Tom schrieb:
> Meinst Du das so?
> #include <iostream>
>
> class LED
> {
> public:
>     void blink()
>     {
>         std::cout << "blink\n";
>     }
> };
>
> class Blinks0r
> {
> public:
>     Blinks0r(LED& l): my_led(l)
>     {
>     }
>     void doit()
>     {
>         my_led.blink();
>     }
> private:
>     LED& my_led;
> };
>
> int main()
> {
>     LED gelbe_led;
>     Blinks0r zappel_licht(gelbe_led);
>     zappel_licht.doit();
> }


Hmm ne, ich glaube nicht.

Ich möchte später halt mehrere Objekte meienr Klasse erzeugen, die alle 
das selbe Objekt "strip" manipulieren können..

Ich bin mir nicht sicher ob ich deinen Code ganz verstehe (Kann halt nur 
das Arduino C++, da gibt es ja einige Operatoren nicht, bzw. verwendet 
man nicht).


Stefan us schrieb:
>> Aber ich kann ja keine leere Referenz erzeugen
>
> Genau, dann nimmt man Zeiger.

Das möchte ich ja, aber ich kriegs nicht hin ;D

Ich habe folgendes Versucht (erstmal nicht in einer extra Klasse, 
sondern einfach im Code selbst einen Zeiger zu definieren
1
Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, STRIP_PIN, NEO_GRB + NEO_KHZ800); //Objekt das manipuliert werden soll
2
3
Adafruit_NeoPixel *strip2; //Zeiger auf ein Objekt vom Typ Adafruit_NeoPixel
4
5
...
6
7
strip2 = &strip;   //Hier bekommt der Zeiger strip2 die Adresse vom Objekt strip
8
*strip2.setPixelColor(0, farben[0]); //Über den Zeiger strip2 wird strip manipuliert

Leider kompiliert Arduino das nicht mit folgendem Fehler in der Zeile :
1
*strip2.setPixelColor(0, farben[0]);

[code] request for member 'setPixelColor' in 'strip2', which is of 
non-class type 'Adafruit_NeoPixel*'[{code]

Habe es auch ohne das * probiert, selber Fehler.

Was ist daran falsch?? Einer ne Idee?

von Yannik (Gast)


Lesenswert?

Ah, ich glaube ich habe die Lösung gefunden.

Ich habe im Netzgefunden, dass wenn man Zeiger auf Objekte macht und 
dann Methoden des Objektes aufrufen will " -> " statt " . " verwenden 
muss.

Also, wenn man
1
strip2 = &strip;
2
  strip2.setPixelColor(0, farben[0]);

in
1
strip2 = &strip;
2
  strip2->setPixelColor(0, farben[0]);

ändert funktioniert es.. Keine Ahnung woher das kommt.. Diesen Pfeil 
habe ich noch nie gesehn ^^ Aber es geht..

von nfet (Gast)


Lesenswert?

der Pfeil steht für das selbe was du oben versucht hast, nur das du 
Klammern vergessen hast / nicht wissen konntest, dass da welche hin 
müssen

*strip2.setPixelColor(0, farben[0]); war fast richtig,

richtig ist es so

*(strip2).setPixelColor(0, farben[0]);

was äquivalent zu

strip2->setPixelColor(0, farben[0]);

ist.

von nfet (Gast)


Lesenswert?

(*strip2).setPixelColor(0, farben[0]);

der Stern muss natürlich rein!

von Yannik (Gast)


Lesenswert?

Argh, so eine Kleinigkeit und ich hab mir n Wolf gesucht :D

Aber vielen Dankt für die Erklärung!! Jetzt weiß ich wie ichs machen 
kann :)

von Karl H. (kbuchegg)


Lesenswert?

Yannik schrieb:

>> Meinst Du das so?
>> ...
>> class Blinks0r
>> {
>> public:
>>     Blinks0r(LED& l): my_led(l)
>>     {
>>     }
>> ...
>
>
> Hmm ne, ich glaube nicht.

Doch. Genau so.

> Ich möchte später halt mehrere Objekte meienr Klasse erzeugen, die alle
> das selbe Objekt "strip" manipulieren können..

Und?
Dann kriegen eben alle bei der Initialisierung eine Referenz auf dieses 
eine gemeinsam zu benutzende Objekt. Kein Problem.


Das 'Problem' ist, dass dein C++ zu schwach ist, um ein paar 
grundlegende Dinge über Referenzen zu wissen. Das, und den grundlegenden 
Unterschied zwischen Zuweisung und Initialisierung in C++. Referenzen 
können nur eingerichtet werden, während einer Initialisierung. Genau das 
macht
1
    Blinks0r(LED& l): my_led(l)

Es initialisiert die im Blinks0r Objekt enthaltene Referenz, so dass 
diese Referenz als ein anderer Name für das (per Referenz) übergebene 
Objekt l ist.

Nichts und niemand hindert einen daran, dass auch andere Klassen bzw. 
Objekte sich derartige Referenzen auf ein und dasselbe Objekt halten.

von Tom (Gast)


Lesenswert?

Yannik schrieb:
> Ich möchte aber ein Objekt meiner Klasse erstellen und beim Erstellen
> des Objektes an den Konstruktor nur ein mal das Objekt "strip"
> übergeben, und die Klasse soll sich das merken und bei späteren aufrufen
> immernoch wissen, wo das Objekt "strip" ist.

Allgemeine Anmerkung: Glückwunsch, dass Dir diese Herangehensweise 
(Objekte, die ein anderes Objekt benötigen, bekommen jenes (vorher 
angelegte) Objekt bei der Initialisierung verpasst) schon an diesem 
Punkt der Programmierkarriere einfällt.

Viele (auch fortgeschrittene) Programmierer würden sich einen 
undurchschaubaren, nicht erweiterbaren und untestbaren Kothaufen mit 
Singletons¹ oder anderen globalen Variablen zurechtfummeln.

¹auf dem Arduino eher nicht, aber das Prinzip ist auf dem PC das 
gleiche.

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.