Ja, ich habe diese Frage und diese FAQ gesehen , aber ich verstehe immer noch nicht, was ->*
und was .*
in C ++ bedeutet.
Diese Seiten enthalten Informationen zu den Operatoren (z. B. Überladung), scheinen jedoch nicht gut zu erklären, was sie sind .
Was sind ->*
und .*
in C ++ und wann müssen Sie sie im Vergleich zu ->
und verwenden .
?
c++
operators
pointer-to-member
operator-arrow-star
user541686
quelle
quelle
pointer
unterscheidet sich ein normaler Funktionszeiger von einer anderen Syntax? (zB Ist es größer?)&X::f
funktioniert? Siehe diese Frage.BEARBEITEN: Übrigens wird es für Zeiger auf Funktionen virtueller Elemente seltsam .
Für Mitgliedsvariablen:
struct Foo { int a; int b; }; int main () { Foo foo; int (Foo :: * ptr); ptr = & Foo :: a; foo .*ptr = 123; // foo.a = 123; ptr = & Foo :: b; foo .*ptr = 234; // foo.b = 234; }
Mitgliedsfunktionen sind fast gleich.
struct Foo { int a (); int b (); }; int main () { Foo foo; int (Foo :: * ptr) (); ptr = & Foo :: a; (foo .*ptr) (); // foo.a (); ptr = & Foo :: b; (foo .*ptr) (); // foo.b (); }
quelle
Kurz gesagt: Sie verwenden
->
und.
wenn Sie wissen, auf welches Mitglied Sie zugreifen möchten. Und du benutzt->*
und.*
wenn nicht wissen, auf welches Mitglied Sie zugreifen möchten.Beispiel mit einer einfachen aufdringlichen Liste
template<typename ItemType> struct List { List(ItemType *head, ItemType * ItemType::*nextMemPointer) :m_head(head), m_nextMemPointer(nextMemPointer) { } void addHead(ItemType *item) { (item ->* m_nextMemPointer) = m_head; m_head = item; } private: ItemType *m_head; // this stores the member pointer denoting the // "next" pointer of an item ItemType * ItemType::*m_nextMemPointer; };
quelle
Sogenannte "Zeiger" auf Mitglieder in C ++ sind intern eher Offsets. Sie benötigen sowohl einen solchen Element- "Zeiger" als auch ein Objekt, um auf das Element im Objekt zu verweisen. Mitgliedszeiger werden jedoch mit Zeigersyntax verwendet, daher der Name.
Es gibt zwei Möglichkeiten, wie Sie ein Objekt zur Hand haben können: Sie haben einen Verweis auf das Objekt oder Sie haben einen Zeiger auf das Objekt.
Verwenden
.*
Sie für die Referenz, um sie mit einem Elementzeiger zu kombinieren, und für den Zeiger,->*
um sie mit einem Elementzeiger zu kombinieren.Verwenden Sie jedoch in der Regel keine Elementzeiger, wenn Sie dies vermeiden können.
Sie befolgen ziemlich kontraintuitive Regeln und ermöglichen es, den
protected
Zugriff ohne explizites Casting zu umgehen , das heißt, versehentlich ...Prost & hth.,
quelle
Wenn Sie einen normalen Zeiger (auf ein Objekt oder einen Basistyp) haben, können Sie ihn
*
dereferenzieren:int a; int* b = a; *b = 5; // we use *b to dereference b, to access the thing it points to
Konzeptionell machen wir dasselbe mit einem Elementfunktionszeiger:
class SomeClass { public: void func() {} }; // typedefs make function pointers much easier. // this is a pointer to a member function of SomeClass, which takes no parameters and returns void typedef void (SomeClass::*memfunc)(); memfunc myPointer = &SomeClass::func; SomeClass foo; // to call func(), we could do: foo.func(); // to call func() using our pointer, we need to dereference the pointer: foo.*myPointer(); // this is conceptually just: foo . *myPointer (); // likewise with a pointer to the object itself: SomeClass* p = new SomeClass; // normal call func() p->func(); // calling func() by dereferencing our pointer: p->*myPointer(); // this is conceptually just: p -> *myPointer ();
Ich hoffe, das hilft, das Konzept zu erklären. Wir dereferenzieren effektiv unseren Zeiger auf die Elementfunktion. Es ist etwas komplizierter - es ist kein absoluter Zeiger auf eine Funktion im Speicher, sondern nur ein Offset, der auf
foo
oderp
darüber angewendet wird . Aber konzeptionell dereferenzieren wir es, ähnlich wie wir einen normalen Objektzeiger dereferenzieren würden.quelle
Sie können den Zeiger auf Mitglieder nicht als normale Zeiger dereferenzieren, da für Elementfunktionen ein Zeiger erforderlich
this
ist und Sie ihn irgendwie übergeben müssen. Sie müssen also diese beiden Operatoren verwenden, mit Objekt auf einer Seite und Zeiger auf einer anderen, z(object.*ptr)()
.Erwägen Sie jedoch die Verwendung von
function
undbind
(std::
oderboost::
, je nachdem, ob Sie C ++ 03 oder 0x schreiben) anstelle dieser.quelle
Zugriffsoperatoren zwischen Zeigern
.*
und Mitgliedern: und->*
Die Zugriffsoperatoren Zeiger auf Mitglied
.*
und->*
dienen zum Dereferenzieren eines Zeigers auf ein Mitglied in Kombination mit einem Objekt bzw. einem Zeiger auf ein Objekt . Diese Beschreibung gilt sowohl für Zeiger auf Datenelemente als auch für Zeiger auf Elementfunktionen .Betrachten Sie zum Beispiel die Klasse
Foo
:struct Foo { int i; void f(); };
Wenn Sie einen Elementzeiger deklarieren
iPtr
, auf einint
Datenelement vonFoo
:int Foo::* iPtr;
Sie können diesen Elementzeiger
iPtr
so initialisieren , dass er auf dasFoo::i
Element zeigt:Um diesen Zeiger zu dereferenzieren, müssen Sie ihn in Verbindung mit einem
Foo
Objekt verwenden.Betrachten Sie nun das Objekt
foo
und den Zeiger auf das ObjektfooPtr
:Dann können Sie
iPtr
in Kombination mitfoo
oder dereferenzierenfooPtr
:foo.*iPtr = 0; fooPtr->*iPtr = 0;
Analog können Sie
.*
und->*
mit Zeigern auf Funktionselemente verwenden . Beachten Sie jedoch, dass Sie sie in Klammern setzen müssen, da der Funktionsaufrufoperator , dh()
hat eine höhere Priorität als die beiden.*
und->*
:void (Foo::*memFuncPtr)() = &Foo::f; (foo.*memFuncPtr)(); (fooPtr->*memFuncPtr)();
Fazit: Sie benötigen ein Objekt, um einen Zeiger auf ein Element zu dereferenzieren, und welches Sie entweder
.*
oder->*
zum Dereferenzieren des Zeigers auf das Element verwenden, hängt davon ab, ob dieses benötigte Objekt direkt oder über einen Objektzeiger bereitgestellt wird.C ++ 17 - Verwenden Sie
std::invoke()
stattdessenDie Verwendung beider Operatoren kann seit C ++ 17 durch die
std::invoke
Funktionsvorlage ersetzt werden.std::invoke
Bietet eine einheitliche Möglichkeit zum Dereferenzieren von Elementzeigern, unabhängig davon, ob Sie sie in Kombination mit einem Objekt oder einem Objektzeiger verwenden , und unabhängig davon, ob der Zeiger auf Element einem Zeiger auf Datenelement oder Zeiger auf Elementfunktion entspricht :// dereference a pointer to a data member std::invoke(iPtr, foo) = 0; // with an object std::invoke(iPtr, fooPtr) = 0; // with an object pointer // dereference a pointer to a member function std::invoke(memFuncPtr, foo); // with an object std::invoke(memFuncPtr, fooPtr); // with an object pointer
Diese einheitliche Syntax entspricht der normalen Funktionsaufrufsyntax und erleichtert möglicherweise das Schreiben von generischem Code.
quelle