2013-03-21 7 views
5

Ich weiß, dass ich einen Zeiger auf Datenelement für eine Klasse bekommen oder Struktur, aber die letzte Zeile des folgenden Code kompilieren fehlschlägt:Convert Zeigerelement Daten ungültig zu erklären *

struct abc 
{ 
    int a; 
    int b; 
    char c; 
}; 

int main() 
{ 
    typedef struct abc abc; 
    char abc::*ptt1 = &abc::c; 
    void *another_ptr = (void*)ptt1; 
} 

warum nicht Ich konvertiere ptt1 in another_ptr? Wir reden über Zeiger so ein Zeiger eine ähnliche Dimension zu einem anderen (obwohl konzeptionell verschieden)

+0

Was ist die Fehlermeldung? –

+1

"typedef struct abc abc;" "Ja wirklich?" –

+0

Ich benutze MSVC2012: Fehler C2440: 'type cast': kann nicht konvertieren von 'char abc :: *' zu 'void *' – Paul

Antwort

9

A Zeiger auf nicht-statische Klasse Elementtyp haben sollte ist nicht das gleiche wie ein Objekt Zeigertyp; sie verhalten sich sehr unterschiedlich. In der Tat können Sie einen Zeiger auf Element mit * nicht sogar dereferenzieren. Um auf einen Member über einen Zeiger auf Member zuzugreifen, verwenden Sie stattdessen die Operatoren .* und ->*. Wenn Sie könnte es in einen Objekt Zeiger Typ wie folgt umwandeln, was würde dann passieren, wenn Sie es mit * dereferenziert?

Nur Objektzeiger Typen haben eine Standardkonvertierung zu void* (§4.10):

A prvalue des Typ "Zeiger auf cvT", wo T ist ein Objekttyp, zu einem umgerechnet werden prvalue des Typs "Zeiger auf Lebenslaufvoid".

Sie sind so verschieden, dass der Standard selbst aus dem Weg geht, um sicherzustellen, dass der Begriff „Zeiger“ enthält keine Hinweise auf nicht-statische Elemente (§3.9.2):

Mit Ausnahme von Zeigern auf statische Elemente gilt Text für "Zeiger" nicht für Zeiger auf Mitglieder.

+0

Über das einzige, was man mit einem 'void *' machen kann, ist, es auf das Original zurückzuwerfen Typ sowieso, so ist die Frage der möglichen Verwendung nicht unbedingt gültig. Sie können ein 'void *' auch nicht mit '*' dereferenzieren. –

+0

@JamesKanze Umformuliert, um den Punkt klarer zu machen. –

+0

Außer dass es noch nicht klar ist, was du mit "normalen Zeigern" meinst. Nur Zeiger auf Objekte (in der C++ - Richtung) können in "void *" umgewandelt werden. Zeiger auf Mitglieder und Zeiger auf Funktionen können nicht. –

0

Versuchen Sie, so etwas zu tun?

struct ABC 
{ 
    int a; 
    int b; 
    char c; 
}; 

int main() 
{ 
    ABC abc; 
    char *ptt1 = &abc.c; 
    void *another_ptr = (void*)ptt1; 
} 
+0

Ja, aber ohne ein Objekt – Paul

+0

Ohne ein Objekt ist es jedoch bedeutungslos. – Damon

+1

Hier ist eine schrecklich ausgedehnte Analogie: Was Sie versucht haben, ist wie der Versuch, einen Nagel in den Bauplan eines Hauses anstelle des Hauses selbst zu schlagen. –

2

Der Hauptgrund dafür ist, weil es nicht erforderlich ist, dass ein Zeiger auf Elemente die gleiche Größe und Darstellung wie einen Zeiger auf Daten. In der Praxis ist es schwer sich einen Zeiger zu einem Datenelement vorzustellen, das nicht in eine void* passen kann, da ein Zeiger auf ein Datenelement wirklich nur einen Offset enthalten muss. Grob gesagt muss ein Zeiger auf ein Datenelement niemals größer sein als ein size_t, und ein void* muss mindestens so groß wie ein size_t sein. Auf der anderen Seite könnte es leicht Bitmuster enthalten, die in einem Zeiger nicht zulässig waren. In der Tat, wie Steve Jessop darauf hinweist, erfordern Zeiger auf Mitglied zusätzliche Informationen, da, wenn das Mitglied in einer virtuellen Basis ist, sein Offset von der abgeleiteten Klasse abhängt und dynamisch berechnet werden muss, basierend auf zusätzlichen Informationen in der Zeiger.

Allgemeiner kann ein void* nur einen Zeiger auf Daten enthalten. Es muss so groß wie der größte Datenzeiger sein (normalerweise a char*), aber Zeiger auf Funktionen und Member Zeiger, können größer sein, und nicht passen (und Zeiger auf Member-Funktionen fast nie passen).

+0

"ein Zeiger auf ein Datenelement muss wirklich nur einen Offset enthalten" - es sei denn, das Mitglied ist in einer virtuellen Basisklasse, in diesem Fall wird mehr benötigt (denke ich. Bin ich falsch, ist es nur mit Zeiger zu Mitglied -Funktion, dass es schwierig ist?). –

+0

@SteveJessop Sie haben Recht. Ich weiß nicht, wo ich es als einfachen Offset gesehen habe. Mit VC 2012, 32-Bit-Modus, hat 'int * 'eine Größe von 4,' int Class :: *' 12. (Denken Sie darüber nach, ich denke, das letzte Mal, als ich es im Detail betrachtet habe, war vorher Mehrfachvererbung wurde der Sprache hinzugefügt. Und die einzige Schwierigkeit sind virtuelle Funktionen. –