Forum: Mikrocontroller und Digitale Elektronik Abstrakte Klasse durch Initlasisierungsliste referenzieren


von Evil-E (Gast)


Lesenswert?

Ich muss für ein STM32 Microcontroller Projekt in C++ ein Objekt einer 
Klasse durch Referenz aufrufen, dass ein Interface initialisiert.
Das Problem ist dass das Objekt während der Runtime gebraucht wird aber 
es da noch nicht existiert.

Ich habe es mit constexpr versucht aber das scheint nicht zu 
funktionieren.

Die Klasse nennt sich Ltdc und das Objekt muss den Konstruktor aufrufen, 
zB LtdcObjekt(Ldtc()),


class Ltdc : public ILtdc
{
      public:
        constexpr Ltdc() noexcept {};
}


///////////////////////////////////////

class ILtdc
{
    protected:

    constexpr ILtdc() { }

    public:

    virtual ~ILtdc() {};
}
///////////////////////////////////////

class Ili9341 final
{
  public:

  Ili9341() noexcept;

  ILtdc & ltdc; //Interface Ltdc Referenz
}


///////////////////////////////////////

Ili9341:: Ili9341() noexcept :

    ltdc(Ltdc()), //Hier wird es in der cpp Datei aufgerugen
{ }


////////////////////////////////////////

Dieser Fehler wird mir geworden

error: #461 initial value of non-const must be an lvalue

von Wilhelm M. (wimalopaan)


Lesenswert?

Evil-E schrieb:
> Ich muss für ein STM32 Microcontroller Projekt in C++ ein Objekt einer
> Klasse durch Referenz aufrufen, dass ein Interface initialisiert.
> Das Problem ist dass das Objekt während der Runtime gebraucht wird aber
> es da noch nicht existiert.
>
> Ich habe es mit constexpr versucht aber das scheint nicht zu
> funktionieren.

Hat damit auch nichts zu tun.


> Ili9341:: Ili9341() noexcept :
>
>     ltdc(Ltdc()), //Hier wird es in der cpp Datei aufgerugen
> { }
>
>
> ////////////////////////////////////////
>
> Dieser Fehler wird mir geworden
>
> error: #461 initial value of non-const must be an lvalue

Du versuchst eine lvalue-reference durch ein rvalue zu initialisieren. 
Das geht nicht.

von wolpino (Gast)


Lesenswert?

Das Problem ist die Zeile:
1
    ltdc(Ltdc()), //Hier wird es in der cpp Datei aufgerugen

Da wird versucht, ein anonymes Object (rvalue) an eine Lvalue-Referenz 
zu binden. Das ist verboten, da das anonyme Objekt mit Verlassen des 
Konstruktors (genauer: der Initialisierungsliste) automatisch zerstört 
wird und man dann eine "hängene" (ungültige, tote) Referenz 
zurückbehält.

Achtung! Mit einem Zeiger anstelle einer Referenz würde das nicht besser 
werden!

Mögliche Lösung (ohne Änderung/Verbesserung des Klassendesigns):
Speichern einer dynamisch erzeugten Instanz, z.B. mittels 
std::unique_ptr.
Der std::unique_ptr sorgt dann automatisch auch für die Zerstörung des 
verwaltenen Objekts im Destruktor.
1
#include <memory>
2
3
class ILtdc
4
{
5
protected:
6
    constexpr ILtdc() { }
7
8
public:
9
    virtual ~ILtdc() {};
10
};
11
12
///////////////////////////////////////
13
14
class Ltdc : public ILtdc
15
{
16
public:
17
    constexpr Ltdc() noexcept {};
18
};
19
20
///////////////////////////////////////
21
22
class Ili9341 final
23
{
24
public:
25
  Ili9341() noexcept;
26
  std::unique_ptr<ILtdc> ltdc; //Interface Ltdc Referenz
27
};
28
29
///////////////////////////////////////
30
31
Ili9341::Ili9341() noexcept
32
: ltdc(std::make_unique<Ltdc>()) //Hier wird es in der cpp Datei aufgerugen
33
{
34
}

Das Member 'ltdc' kann dann wie ein Zeiger dereferenziert werden.

von Evil-E (Gast)


Lesenswert?

Wir sind im Embedded Bereich und haben leider keinen Zugriff auf externe 
Bibliotheken, darunter auch die std Bibliothek.

von Wilhelm M. (wimalopaan)


Lesenswert?

Dein Code von oben macht ja auch so, wie er da steht, keinen Sinn. Denn 
die offensichtliche Laufzeitpolymorphie benötigst Du ja gar nicht. Ein 
einfaches Datenelement wäre ja ausreichend.

von wolpino (Gast)


Lesenswert?

Evil-E schrieb:
> Wir sind im Embedded Bereich und haben leider keinen Zugriff auf externe
> Bibliotheken, darunter auch die std Bibliothek.

Hmm, dann gibt es (wahrscheinlich) für das Target auch kein new/delete, 
somit sehe ich als Option nur das direkte Speichern einer Instanz der 
Implementierungsklasse (class Ltdc) als Datenmember in der Klasse 
Ili9341 (oder irgendwo anders).
1
class ILtdc
2
{
3
protected:
4
    constexpr ILtdc() { }
5
6
public:
7
    virtual ~ILtdc() {};
8
};
9
10
///////////////////////////////////////
11
12
class Ltdc : public ILtdc
13
{
14
public:
15
    constexpr Ltdc() noexcept {};
16
};
17
18
///////////////////////////////////////
19
20
class Ili9341 final
21
{
22
public:
23
  Ili9341() noexcept;
24
  Ltdc ltdc; //Interface Ltdc Referenz
25
};
26
27
///////////////////////////////////////
28
29
Ili9341::Ili9341() noexcept
30
: ltdc() //Hier wird es in der cpp Datei aufgerugen
31
{
32
}

von Dr. Sommer (Gast)


Lesenswert?

Wahrscheinlich soll die Ili9341 Klasse doch gar nicht wissen, welche 
ILtdc Implementation da jetzt benutzt wird. Sonst wäre die abstrakte 
Klasse ziemlich nutzlos. Daher sollte man die Instanz außerhalb anlegen 
und übergeben:
1
class Ili9341 final
2
{
3
  public:
4
5
  Ili9341(ILtdc & l) noexcept;
6
7
  ILtdc & ltdc; //Interface Ltdc Referenz
8
}
9
10
11
///////////////////////////////////////
12
13
Ili9341:: Ili9341(ILtdc & l) noexcept :
14
15
    ltdc(l), // Referenz übernehmen
16
{ }

und dann, typischerweise als globale Variablen:
1
Ltdc ltdc;
2
Ili9341 ili9341 (ltdc);

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.