Hallo,
ich möchte von einer Klasse ein Objekt erzeugen und dieses mit
geschweiften Klammern initialisieren.
Die Klasse beinhaltet einen Funktionszeiger, den ich auch mittels
Lambdaausdrucks initialisieren möchte und welcher Zugriff auf die
Atribute ha`ben soll.
Folgendes Beispiel geht leider nicht. Gibt es da eine Möglichkeit?
Außerhalb der Klasse kannst du kein this nehmen...
PS: die ganze Lambdafuntion ist außerhalb der Klasse, die wird keine
Methode werden können.
Muß mal grübeln, ob das gehen könnte, was du vielleicht vorhast...
Was du als z deklarierst, ist auch keine Methode, sondern nur ein Zeiger
auf eine Funktion.
Den kannst du als Lambdafunktion setzen. Aber die kann dann nicht auf x
zugreifen, weil sie keine Methode ist.
Und wie gesagt kann sie auch kein this nehmen - weil keine Methode.
Ich wollte eine Menustruktur definieren, als Konstanten im Flash. Und
ein Parameter sollte eben sein, was bei Buttons passieren soll und das
wollte ich als Lamda definieren.
Nun müsste ich ständig einen zeiger mitgeben und der Schreibaufwand wird
massiv. Gibt es da eine elegantere Lösung?
So irgendwie wollte ich das halt lösen:
Versuch doch erstmal, deine Lambdas als normale Funktion zu formulieren
- wenn das funktioniert, kannste immer noch ne Lambda machen.
1
class Bildschirm{
2
public:
3
void (*button)();
4
void (*print)();
5
};
6
7
void onButtonPress()
8
{}
9
10
11
Bildschirm Bild1 = {
12
.button = &onButtonPress;
13
[...]
14
};
Was du hier versuchst zu tun, nennt sich Dependency Injection bzw.
Inversion of Control. Und wenn der aufrufende Code dynamisch (zur
Laufzeit) bestimmen können soll, was der aufgerufene Code zu tun hat -
dann gehts halt nicht ohne Funktionspointer.
Wenn du das Objekt noch mitgeben willst, musste halt deine Callback
anpassen:
1
class Bildschirm{
2
public:
3
void (*button)(Bildschirm* const);
4
void (*print)(Bildschirm* const);
5
};
6
7
void onButtonPress( Bildschirm* const screen)
8
{}
Beim Zugriff auf Bild1.button musste halt Bild1 als Parameter mit
reinschleifen.
tut nix zur Sache schrieb:> (zur Laufzeit)
Ich würde das hingegen gerne als Konstante zur Compilezeit definieren
können, so dass ich mir den Bildschirm* const sparen kann. Aber das geht
scheinbar nicht.
Da würde ich eher Funktionsobjekte nehmen.
Das sind Objekte, in deren Klasse der operator() überladen ist (ggf. mit
Parametern bei Bedarf) und die deshalb wie eine Funktion resp.
Funktionszeiger resp. Lambdafunktion verwendet werden können.
Der zugehörige Parameter in deiner Bildschirmklasse könnte dann ein
std::function sein.
Der Vorteil von Funktionsobjekten ist, daß sie noch Daten enthalten
können (wie man halt Member in ihrer Klasse definiert).
So könnte man das Funktionsobjekt, das in dem Bildschirm abgelegt wird,
mit dem Bildschirm wiederum initialisieren. Dann weiß das Objekt, wessen
Methoden es aufrufen muß.
Im wesentlichen der Trenner ";" statt "," zwischen den "designated
initializers";
Trotzdem ist das wahrscheinlich mit der Konvertierung zu einem
Funktionszeiger nicht das, was Du möchtest. Denn das geht nur für
capture-less lambda-expr (aus naheliegenden Gründen).
Ja, sieht schon besser aus.
Aber trotzdem sind button() und print() "nur" Funktionen und keine
Methoden. Deshalb werden sie nicht auf Interna des Bildschirms zugreifen
können, was Rene ursprünglich mal wollte mit seinem this.
Wilhelm M. schrieb:> Ok, das hatte ich überlesen:> #include <functional>> #include <iostream>> class Bildschirm{> [...]> Bild1.onEvent([](const Bildschirm* const b){> });
Ich würde vermuten, dass das der massive Schreibaufwand ist, den er
vermeiden möchte ;-)
Rene schrieb:> Nun müsste ich ständig einen zeiger mitgeben und der Schreibaufwand wird> massiv.
Mombert H. schrieb:> Ich würde vermuten, dass das der massive Schreibaufwand ist, den er> vermeiden möchte ;-)
Oh ha ;-)
Den hätte er doch sowieso (Beim Erzeugen des Closures in der LE, wenn
dort ein Capture des (noch nicht gebauten) Objektes möglich wäre).
Mombert H. schrieb:> Rene schrieb:>> Nun müsste ich ständig einen zeiger mitgeben und der Schreibaufwand wird>> massiv.
Zeiger (nullable reference) ist an der Stelle eh sehr fragwürdig. Denn
ein nullptr an der Stelle wäre immer falsch, und man müsste expl.
zusichern oder ein run-time check auf nullptr machen.
Daher habe ich das oben geändert.
Ich glaube der einzige Weg, einen echten this pointer zu bekommen, ist
mit Klassen und virtuellen Methoden:
1
#include<iostream>
2
#include<array>
3
4
classMenuItem{
5
public:
6
MenuItem(std::stringname):name(name){}
7
std::stringname;
8
virtualvoidrun()const=0;
9
virtualvoidshow()const=0;
10
};
11
12
namespacemenu{
13
constclassBla:publicMenuItem{
14
public:
15
Bla(std::stringname):MenuItem(name){}
16
voidrun()const{
17
std::cout<<"run bla bla"<<std::endl;
18
}
19
voidshow()const{
20
std::cout<<"show "<<this->name<<std::endl;
21
}
22
}bla{"bla"};
23
constclassM123:publicMenuItem{
24
public:
25
M123(std::stringname):MenuItem(name){}
26
voidrun()const{
27
std::cout<<"run 123 "<<this->name<<std::endl;
28
}
29
voidshow()const{
30
std::cout<<"show "<<this->name<<std::endl;
31
}
32
}m123{"123"};
33
conststd::array<constMenuItem*,2>menu={
34
&bla,
35
&m123
36
};
37
}
38
39
intmain(){
40
for(autoitem:menu::menu)
41
item->show();
42
}
Ich habe schon lange (ein paar Jahre) klein C++ mehr geschrieben. OMG
ist das scheisse. Was ich da alles gelernt habe, was man in C++ nicht
machen kann.
Sowas wie offset_of oder container_of bei c ist mit member pointern
nicht one hacks machbar.
Kein new von anonymen Klassen mit virtuellen Methoden, und Konstruktoren
kann man bei anonymen Klassen auch vergessen.
Im globalen Scope eine Referenz von einem Compound literal nehmen, um da
in einem Member eines Objekts zu initialisieren, geht auch nicht, anders
als in C ist das dort dann ne temporäre Referenz!?!
Und ein normales C array von anonymen C Klassen Instanzen als Compound
literal zu erstellen, scheint schon rein syntaktisch nicht möglich zu
sein!?!
Einfach mal was wie .name initialisieren alla designated initialisers,
gibts auch nicht.
Und die std::array brauchen immer noch die Angabe, wie viele Elemente da
sind, auch wenn man es direkt initialisiert?
Und den Bla construktor konnte es mir auch nicht automatisch generieren,
wie das andere Sprachen wie z.B. JavaScript könnten?
WTF, wie kann mit dem Mist irgend wer arbeiten? Dieses C++ ist ja fast
noch schlimmer als Rust!
🐧 DPA 🐧 schrieb:> Ich glaube der einzige Weg, einen echten this pointer zu bekommen, ist> mit Klassen und virtuellen Methoden:
Leider hast Du mit Deinem Post am Thema vorbei geschrieben: es geht
nicht(!) um Laufzeitpolymorphie.
Rene schrieb:> Ich habe evtl. eine Lösung gefunden.class A {> public:> int x; void createConstMembers(); std::function<void()> f;> };> A B_Test;> void A::createConstMembers(){ B_Test = A{> .f = [this](){ x = 0;> }> };> }
Wofür brauchst du jetzt noch f. wenn du eh ne neue Methode schreibst?
Rene schrieb:> Ich würde das hingegen gerne als Konstante zur Compilezeit definieren> können, so dass ich mir den Bildschirm* const sparen kann. Aber das geht> scheinbar nicht.
Ich glaube zwar nicht, dass der OP noch dabei ist, doch trotzdem:
wieviele "Bildschirm"-Objekte hast Du denn?
Einen?
Dann macht es keinen Sinn, im Code die Möglichkeit zu haben, mehrere
Objekte davon zu erzeugen. Es sei denn, Du baust Deine Klasse als
Monostate.
Oder Du verwendest ein Singleton (ggf. mit anderen Problemen).
Meistens hat man es bei µC-Anwendungen nur mit einer begrenzten Anzahl
von Objekten als Abstraktion einer (internen) Peripherie zu tun. Dann
kannst Du auch gleich auf Heap/Stack-Objekte bzw. globale Objekte
verzichten, und statt dessen static-only Klassen bzw. templates
verwenden.
Wilhelm M. schrieb:> Ich glaube zwar nicht, dass der OP noch dabei ist, doch trotzdem:> wieviele "Bildschirm"-Objekte hast Du denn?
An die zehn und jedes Objekt soll eine eigene Funktion für jeden
Tastendruck und die "print" Funktion erhalten.
Das wäre zumindest meine Idee. In der Klasse ist fast alles static (die
Ressourcen), lediglich die Funktionspointer sind Objektattribute.
Derzeit habe ich halt für jede Taste und die Bildschirmausgabe ein
riesiges Switch-Case.
Mit der Lösung, die ich hier nochmal poste, kann ich scheinbar zumindest
Objekte erstellen, die alle auf die gemeinsamen static Attribute
zugreifen können. Ich bin da aber nicht zufrieden mit, die teilen sich
natürlich auch potentiell alle das gleiche Objekt.
Mombert H. schrieb:> Wo ist der Vorteil gegenüberclass A {
Ich kann nicht für jedes Object eine individuelle Methode erstellen. Die
machen alle das Selbe.
Bei meiner Lösung kann ich auch schreiben: