AVR C++ Template Klasse

Gast #2869451
Lesenswert?

Hallo,

ich brauche eure Hilfe um den Knoten im meinem Kopf zu entwirren.

Ich wage gerade die ersten Schritte mit C++ auf dem AVR. Es stehen zwei 
Klassen für die Ausgabe von Werten zur Verfügung UART und LCD.  Über 
eine Template Klasse soll nun die Ausgabe gesteuert werden. Jede Klasse 
hat den Operator write implementiert. Mit Hilfe der Wrapper Klasse soll 
dann zur Laufzeit die Ausgabe auf das entsprechende Device umgeschaltet 
werden.
Der Compiler beschwert sich beim Bauen mit dieser Fehlermeldung
1
Error: cannot call member function `void UART::write(uint8_t) without object

Ich denke das Problem liegt daran, dass ich in der Wrapper methode die 
Klasse UART angebe anstelle der Instanz von UART. Wie komme ich jetzt an 
die Instanz von UART heran?

Ich hoffe, dass ich es möglichst verständlich erklärt habe. Vielleicht 
gelingt es ja jemanden meinen Knoten im Kopf zu entwirren. Oder gibt es 
noch einen einfacheren Ansatz zur Lösung dieses Problems?

merci für eure Inputs schon einmal!

markus
1
class UART0 {
2
  void write(uint8_t c) {
3
    write to uart
4
}
5
};
6
class LCD {
7
  void write{uint8_t c) {
8
    write to LCD
9
}
10
} ;
11

12
template <class T>
13
class Wrapper {
14
public:
15
  Wrapper(const T& device){}
16
  virtual void write(uint8_t){
17
    T::write();
18
  }
19
};
20

21
void main() {
22
UART uart0(9600);
23
Wrapper<UART> device(uart0);
24
device.write A ;
#2869463
Lesenswert?

Du musst die Referenz auf die betreffende Objektinstanz im Konstruktor 
von Wrapper auch speichern, dann kommst du da auch wieder ran.
1
template <class T>
2
class Wrapper {
3
 T &m_device; 
4
public:
5
  Wrapper(T& device) : m_device(device) {}
6
  virtual void write(uint8_t){
7
    m_device::write();
8
  }
9
};

Aber Achtung: Wie du siehst habe ich hier kein 'const T&' mehr stehen. 
Warum? Die Methode write() die du in UART0 und LCD aufrufen willst sind 
nicht als const deklariert, aber nur solche Methoden kannst du mit einem 
konstanten Objekt aufrufen.

Ich verstehe allerdings nicht, warum deine ersten Schritte in C++ gleich 
mit Templates zu tun haben. Das ist so als würde man auf dem Hochseil 
laufen lernen.
#2869486
Lesenswert?

Marco M. schrieb:

> Ich verstehe allerdings nicht, warum deine ersten Schritte in C++ gleich
> mit Templates zu tun haben. Das ist so als würde man auf dem Hochseil
> laufen lernen.

Ich versteh in erster Linie nicht, wozu dieses Template überhaupt gut 
sein soll. Ob man die virtuelle FUnktion im Template hat, oder ob man 
UART0 und LCD von einer gemeinsamen OutputDevice Klasse herleitet, kommt 
sich aufs gleiche raus.
1
class OutputDevice
2
{
3
  public:
4
    virtual ~OutputDevice() {};
5

6
    virtual void Write( uint8_t value ) = 0;
7
};
8

9
class UART0 : public OutputDevice
10
{
11
  public:
12
    virtual void write( uint8_t c )
13
    {
14
      write to uart
15
    }
16
};
17

18
class LCD : public OutputDevice
19
{
20
  public:
21
    virtual void write( uint8_t c )
22
    {
23
      write to LCD
24
    }
25
};
26

27

28
void foo( OutputDevce* pWhere )
29
{
30
  pWhere->write( 'a' );
31
}
32

33
int main()
34
{
35
  UART0 theUart;
36
  LCD   theLcd;
37

38
  foo( &theUart );    // foo gibt jetzt auf der UART aus
39
  foo( &theLcd );     // und jetzt landet die Ausgabe von Foo auf dem LCD
40
}

stink normale Polymorphie.
Genau das richtige um ...
> ... dann zur Laufzeit die Ausgabe auf das entsprechende
> Device umgeschaltet werden.
Genau dafür ist sie erfunden worden.
#2869495
Lesenswert?

markus schrieb:
> Mit Hilfe der Wrapper Klasse soll
> dann zur Laufzeit die Ausgabe auf das entsprechende Device umgeschaltet
> werden.

Ich glaube du Vererbung und virtuelle Methoden sind eher das wonach du 
suchen solltest.
1
class output
2
{
3
   public:
4
   virtual void write(char c);
5
}
6
class Uart : public output
7
{
8
   public:
9
   virtual void write( char c);
10
}
11
class LCD: public output
12
{
13
   public:
14
   virtual void write( char c);
15
}
16

17

18
void main()
19
{
20
 Uart u;
21
 LCD l;
22
 output * o;
23

24
 o = &u;
25
 o->write('a');
26
 o = &l;
27
 o->write('c');
28
}
(Entschuldigt bitte mein C++, ich programmiere zurzeit fast nur noch C).

Damit kannst du wirklich zur Laufzeit was umschalten. Templates sind 
Spielen nur während der Compilierung eine rolle.

Edit: Zu spät
#2869512
Lesenswert?

Nur, um mal (in diesem Fall) templates schlecht zu machen:
Mit einem Template schreibt man zwar einmal die Schablone hin, das spart 
Quelltext gegenüber zwei sehr ähnliche Klassen komplett zu formulieren.
Es spart aber keinen Programmcode.

Denn: Wrapper<UART> und Wrapper<LCD> sind zwei voneinander unabhängige 
Klassen, die der Compiler bei Bedarf aus der Schablone generiert - und 
zwar vollständig.

D.h. daß auch gemeinsamer Code der beiden zweimal vollständig im 
Programm vorhanden ist, wenn beide Klassen in einem Programm verwendet 
werden.

Zudem sind die beiden nicht wirklich zur Laufzeit umschaltbar, weil sie 
keine gemeinsame Basisklasse haben. Mal das eine und mal das andere z.B. 
als Parameter zu verwenden für dieselbe Funktion, geht nicht.

Das als zusätzliche Erklärung, warum es besser ist, die Gemeinsamkeit in 
eine Basisklasse zu packen und die Unterschiede in eine Ableitung.

Hast du allerdings vor, in je einem Programm immer nur die eine oder die 
andere Version zu verwenden, kann man sich ein template vorstellen.
Dann macht aber ein virtual keinerlei Sinn.
#2869544
Lesenswert?

Karl Heinz Buchegger schrieb:

> Ich versteh in erster Linie nicht, wozu dieses Template überhaupt gut
> sein soll. Ob man die virtuelle FUnktion im Template hat, oder ob man
> UART0 und LCD von einer gemeinsamen OutputDevice Klasse herleitet, kommt
> sich aufs gleiche raus.

Oh, das ist im Grunde genommen keine unübliche, wenn auch eher 
fortgeschrittene Technik. Man macht so etwas um Typen die in der 
Klassenhierachie nicht verwandt sind mit einem gemeinsamen Interface 
auszustatten, in etwa analog zu Haskell's Typklassen. Aber das ist nicht 
direkt Anfängerstoff.
#2869566
Lesenswert?

Marco M. schrieb:

> Oh, das ist im Grunde genommen keine unübliche, wenn auch eher
> fortgeschrittene Technik. Man macht so etwas um Typen die in der
> Klassenhierachie nicht verwandt sind mit einem gemeinsamen Interface
> auszustatten, in etwa analog zu Haskell's Typklassen.

Das sagt mir jetzt nicht viel.
(Und Templates sind einer meiner schwachen Punkte)

Hast du da mal ein Schlagwort dafür?
#2869574
Lesenswert?

Karl Heinz Buchegger schrieb:
> Marco M. schrieb:
>
>> Oh, das ist im Grunde genommen keine unübliche, wenn auch eher
>> fortgeschrittene Technik. Man macht so etwas um Typen die in der
>> Klassenhierachie nicht verwandt sind mit einem gemeinsamen Interface
>> auszustatten, in etwa analog zu Haskell's Typklassen.
>
> Das sagt mir jetzt nicht viel.
> (Und Templates sind einer meiner schwachen Punkte)
>
> Hast du da mal ein Schlagwort dafür?


Ist schon ok.
Nach ein paar Minuten nachdenken, denke ich weiß, wo da die Reise 
hingeht. Man will den Klassen keine gemeinsame Basisklasse unterjubeln, 
noch nicht mal in Form eines gemeinsamen Interfaces und macht sich ein 
spezialisierte Interfaceklasse(n) (mit gemeinsamer Basisklasse), welches 
die Umsetzung erledigt. Im Grunde 'so ähnlich wie ein PIMPL Idiom mit 
gemeinsamer Basisklasse'. Und die kann man natürlich dann auch in 
Templates verpacken, so dass man das nicht jedesmal selber neu schreiben 
muss.

Ja ok.
Bringt ihm aber in diesem Falle nichts.
Ich hätte gesagt: Machs erst mal so, wie man das in C++ macht. 
Gemeinsame Basisklasse und Polymorphie.
#2869645
Lesenswert?

Streitet euch doch nicht. :-)


Ich denke, wenn man diese Frage hier liest

> Der Compiler beschwert sich beim Bauen mit dieser Fehlermeldung
> Error: cannot call member function `void UART::write(uint8_t)’
> without object
>
> Ich denke das Problem liegt daran, dass ich in der Wrapper methode die
> Klasse UART angebe anstelle der Instanz von UART. Wie komme ich jetzt an
> die Instanz von UART heran?

dann brauchen wir uns nicht lange darüber unterhalten, was eventuell bei 
einem fortgeschrittenem Programmierer ein Template-Problem sein könnte. 
Da haperts schon an ganz anderer Stelle.

Er hat sich einfach nur verrannt und darauf gesetzt, dass Templates 
irgendwie magisch das tun, was er auf seinem Wunschzettel hat.
Das übliche leidige Problem: Im Stroustroup die ersten 400 Seiten 
übersprungen, weil "das brauch ich eh alles nicht".

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren