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
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
Du musst die Referenz auf die betreffende Objektinstanz im Konstruktor
von Wrapper auch speichern, dann kommst du da auch wieder ran.
1
template<classT>
2
classWrapper{
3
T&m_device;
4
public:
5
Wrapper(T&device):m_device(device){}
6
virtualvoidwrite(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.
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
classOutputDevice
2
{
3
public:
4
virtual~OutputDevice(){};
5
6
virtualvoidWrite(uint8_tvalue)=0;
7
};
8
9
classUART0:publicOutputDevice
10
{
11
public:
12
virtualvoidwrite(uint8_tc)
13
{
14
writetouart
15
}
16
};
17
18
classLCD:publicOutputDevice
19
{
20
public:
21
virtualvoidwrite(uint8_tc)
22
{
23
writetoLCD
24
}
25
};
26
27
28
voidfoo(OutputDevce*pWhere)
29
{
30
pWhere->write('a');
31
}
32
33
intmain()
34
{
35
UART0theUart;
36
LCDtheLcd;
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.
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
classoutput
2
{
3
public:
4
virtualvoidwrite(charc);
5
}
6
classUart:publicoutput
7
{
8
public:
9
virtualvoidwrite(charc);
10
}
11
classLCD:publicoutput
12
{
13
public:
14
virtualvoidwrite(charc);
15
}
16
17
18
voidmain()
19
{
20
Uartu;
21
LCDl;
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
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.
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.
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?
Marco M. schrieb:> Oh, das ist im Grunde genommen keine unübliche, wenn auch eher> fortgeschrittene Technik.
Karl-Heinz weiss, was Templates sind. Die Frage war, wozu sie in diesem
konkreten Fall gut sein sollen.
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.
Marwin schrieb:> Marco M. schrieb:>> Oh, das ist im Grunde genommen keine unübliche, wenn auch eher>> fortgeschrittene Technik.>> Karl-Heinz weiss, was Templates sind. Die Frage war, wozu sie in diesem> konkreten Fall gut sein sollen.
Das ist die Frage die ich beantwortet habe.
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".
Klaus Wachtler schrieb:> Nix für ungut, aber lies mal den Umschlag: der Mann heisst Stroustrup> :-)>> (nicht böse nehmen, aber die Steilvorlage war zu gut)
LOL
Danke.
(wenn ich böse wäre, könnte ich jetzt sagen: Ich hab mich mehr um den
Inhalt gekümmert als um den Umschlag :-)
Karl Heinz Buchegger schrieb:> (wenn ich böse wäre, könnte ich jetzt sagen: Ich hab mich mehr um den> Inhalt gekümmert als um den Umschlag :-)
Um ehrlich zu sein, den Eindruck machst du auch. ;)
Karl Heinz Buchegger schrieb:> (wenn ich böse wäre, könnte ich jetzt sagen: Ich hab mich mehr um den> Inhalt gekümmert als um den Umschlag :-)
Wenn du böse wärst, hättest du gesagt, ICH hätte nur den Umschlag
gelesen...
Klaus Wachtler schrieb:> Hast du allerdings vor, in je einem Programm immer nur die eine oder die> andere Version zu verwenden, kann man sich ein template vorstellen.markus schrieb:> C++ auf dem AVR
Das ist auf einem AVR mit knappen RAM in diesem Fall durchaus sinnvoll.
Oliver