Warum werden Zeiger beim Codieren mit C ++ nicht empfohlen?


45

Ich habe irgendwo gelesen, dass bei der Verwendung von C ++ empfohlen wird, keine Zeiger zu verwenden. Warum sind Zeiger eine so schlechte Idee, wenn Sie C ++ verwenden. Was ist die bessere Alternative und Vorgehensweise in C ++ für C-Programmierer, die an die Verwendung von Zeigern gewöhnt sind?


40
bitte auf "irgendwo" verlinken. Der Kontext könnte sehr relevant sein.

1
Diese Frage ist hoffentlich hilfreich für Sie.
Garet Claborn

Die meisten dieser Antworten beziehen sich auf die Vermeidung von Speicherverlusten als Hauptgrund. Ich kann mich nicht erinnern, wann eine unserer Apps zum letzten Mal ein Speicherverlustproblem hatte, obwohl Zeiger verwendet wurden. Wenn Sie Probleme mit Speicherverlusten haben, verwenden Sie nicht die richtigen Tools oder wissen nicht, was Sie tun. Die meisten Entwicklungsumgebungen haben eine Möglichkeit, automatisch nach eingebauten Lecks zu suchen. Ich denke, Speicherleckprobleme sind in Sprachen mit Speicherbereinigung weitaus schwieriger zu finden, da deren Auftreten weitaus subtiler ist und Sie häufig ein Drittanbieter-Tool benötigen, um den Täter zu finden .
Dunk

1
Nach dem Kommentar von @Dunk funktionieren integrierte Garbage Collectors in höheren Sprachen manchmal einfach nicht richtig. Dies ist beispielsweise beim Garbage Collector von ActionScript 3 nicht der Fall. Momentan gibt es einen Fehler, der damit zusammenhängt, dass NetConnectionInstanzen vom Server getrennt werden ( stackoverflow.com/questions/14780456/… ), und es gibt ein Problem mit mehreren Objekten in einem Programm, die es ausdrücklich ablehnt, jemals zu sammeln ...
Panzerkrise

... ( adobe.com/devnet/actionscript/learning/as3-fundamentals/… - Suche nach GCRoots are never garbage collected.und der Absatz beginnt mit The MMgc is considered a conservative collector for mark/sweep.). Technisch ist dies ein Problem in Adobe Virtual Machine 2, nicht in AS3 selbst. Wenn Sie jedoch Probleme in höheren Sprachen haben, in denen die Garbage Collection im Wesentlichen integriert ist, haben Sie in der Sprache häufig keine echte Möglichkeit zum Debuggen diese Fragen komplett aus dem Programm. ...
Panzerkrise

Antworten:


58

Ich denke, sie bedeuten, dass Sie intelligente Zeiger anstelle von regulären Zeigern verwenden sollten.

In der Informatik ist ein intelligenter Zeiger ein abstrakter Datentyp, der einen Zeiger simuliert und gleichzeitig zusätzliche Funktionen wie die automatische Speicherbereinigung oder die Grenzwertprüfung bereitstellt. Diese zusätzlichen Funktionen sollen Fehler reduzieren, die durch den Missbrauch von Zeigern verursacht werden, während die Effizienz erhalten bleibt. Intelligente Zeiger verfolgen normalerweise die Objekte, auf die sie zum Zwecke der Speicherverwaltung zeigen.

Der Missbrauch von Zeigern ist eine Hauptursache für Fehler: Die ständige Zuordnung, Freigabe und Referenzierung, die von einem mit Zeigern geschriebenen Programm durchgeführt werden muss, birgt das Risiko, dass Speicherlecks auftreten. Intelligente Zeiger versuchen, Speicherverluste zu verhindern, indem sie die automatische Freigabe der Ressource veranlassen: Wenn der Zeiger (oder der letzte in einer Reihe von Zeigern) auf ein Objekt zerstört wird, z.

In C ++ liegt der Schwerpunkt auf der Garbage Collection und der Vermeidung von Speicherverlusten (um nur zwei zu nennen). Zeiger sind ein grundlegender Bestandteil der Sprache, daher ist es so gut wie unmöglich, sie nicht zu verwenden, es sei denn, es handelt sich um die trivialsten Programme.


22
Typischerweise ist es keine reine Müllabfuhr im klassischen Sinne, eher eine Referenzzählung. Zumindest im Smart PTR bin ich es gewohnt ([boost | std] :: shared_ptr)
Doug T.

3
Diese Antwort ist sehr beschränkt auf Smart Pointer, was nur ein kleiner Aspekt des Problems ist. Darüber hinaus sind Smart Pointer keine Garbage Collection.
Deadalnix

3
Auch RAII im Allgemeinen.
Klaim am

3
Nein, das ist nicht gemeint. Es ist nur ein Aspekt und nicht der wichtigste.
Konrad Rudolph

Ich denke, kluge Zeiger sind der wichtigste Aspekt, aber ich stimme zu, dass es viele andere gibt.
DeadMG

97

Da ich derjenige bin, der die Polemik "benutze keine f * kking-Zeiger" veröffentlicht hat, denke ich, dass ich hier einen Kommentar abgeben sollte.

Als Polemik ist es offensichtlich ein extremer Gesichtspunkt. Es gibt definitiv legitime Verwendungen von (rohen) Zeigern. Aber ich (und viele professionelle C ++ - Programmierer) behaupten, dass diese Fälle äußerst selten sind. Aber was wir wirklich meinen, ist das Folgende:

Zuerst:

Raw Pointer dürfen auf keinen Fall eigenen Speicher besitzen.

Hier bedeutet "eigenes Gedächtnis" im Wesentlichen, dass irgendwann deleteauf diesen Zeiger zugegriffen wird (aber es ist allgemeiner als das). Diese Aussage kann mit Sicherheit als absolut angesehen werden. Die einzige Ausnahme ist die Implementierung eines eigenen Smart Pointers (oder einer anderen Speicherverwaltungsstrategie). Und selbst dort sollten Sie normalerweise noch einen Smart Pointer auf niedriger Stufe verwenden.

Die Begründung hierfür ist ganz einfach: Rohe Zeiger, die über Speicher verfügen, führen zu einer Fehlerquelle. Und diese Fehler sind in bestehender Software sehr häufig: Speicherverluste und doppeltes Löschen - beides eine direkte Folge von unklarem Ressourcenbesitz (aber in entgegengesetzter Richtung).

Dieses Problem kann praktisch kostenlos vollständig beseitigt werden, indem einfach intelligente Zeiger anstelle von unformatierten Zeigern verwendet werden (Vorsicht: Dies erfordert natürlich noch Nachdenken; gemeinsame Zeiger können zu Zyklen und damit wiederum zu Speicherverlusten führen - dies ist jedoch einfach vermeidbar).

Zweite:

Die meisten Verwendungen von Zeigern in C ++ sind nicht erforderlich.

Im Gegensatz zu anderen Sprachen unterstützt C ++ die Wertesemantik sehr stark und benötigt einfach keine Indirektion von Zeigern. Dies wurde nicht sofort erkannt - in der Vergangenheit wurde C ++ erfunden, um eine einfache Objektorientierung in C zu ermöglichen, und es wurde stark darauf geachtet, Objektgraphen zu konstruieren, die durch Zeiger verbunden waren. In modernem C ++ ist dieses Paradigma jedoch selten die beste Wahl, und moderne C ++ - Redewendungen benötigen häufig überhaupt keine Zeiger . Sie arbeiten eher mit Werten als mit Zeigern.

Leider hat sich diese Nachricht in weiten Teilen der C ++ - Benutzergemeinschaft noch nicht durchgesetzt. Infolgedessen ist der größte Teil des geschriebenen C ++ - Codes immer noch mit überflüssigen Zeigern übersät, die den Code komplex, langsam und fehlerhaft / unzuverlässig machen.

Für jemanden, der modernen C ++ kennt, dann ist es klar , dass man sehr selten brauchen keine Zeiger (entweder intelligent oder roh, außer wenn sie als Iteratoren verwenden). Der resultierende Code ist kürzer, weniger komplex, besser lesbar, oft effizienter und zuverlässiger.


5
Seufz ... das sollte wirklich die Antwort mit mehr als 30 positiven Stimmen sein ... vor allem für den zweiten Punkt. Zeiger sind in modernem C ++ nur selten erforderlich .
Charles Salvia

1
was ist mit zB. Gui-Objekt besitzt eine Reihe von Doc-Objekten. Es hat diese als Zeiger, damit die Klasse vorwärts deklariert werden kann (vermeidet erneutes Kompilieren) und damit das Objekt beim Erstellen (mit neuem) initialisiert werden kann, anstatt in einem leeren Zustand auf dem Stapel erstellt und später abgelegt zu werden. Dies scheint eine absolut gültige Verwendung von Zeigern zu sein - sollten sich nicht alle eingekapselten Objekte auf dem Haufen befinden?
Martin Beckett

4
@Martin GUI-Objekte sind ein Fall, in dem Zeigerobjektdiagramme in der Tat die beste Lösung sind. Das Edikt gegen speichereigene rohe Zeiger bleibt jedoch bestehen. Verwenden Sie entweder durchgehend gemeinsame Zeiger oder entwickeln Sie ein geeignetes Eigentumsmodell und haben Sie nur schwache (= nicht im Besitz befindliche) Beziehungen zwischen den Steuerelementen über unformatierte Zeiger.
Konrad Rudolph

1
@ VF1 std::unique_ptr. Warum auch nicht ptr_vec? In der Regel wird ein Wertevektor mit dennoch schneller ausgetauscht (insbesondere mit Bewegungssemantik).
Konrad Rudolph

1
@gaazkam Niemand hat Sie gezwungen, nur Standardcontainer zu verwenden. Boost bietet beispielsweise eine Kartenimplementierung mit Unterstützung für unvollständige Typen. Eine andere Lösung besteht darin, die Art der Löschung zu verwenden. boost::variantmit a recursive_wrapperist wohl meine lieblingslösung um eine DAG darzustellen.
Konrad Rudolph

15

Ganz einfach, weil Ihnen Abstraktionen zur Verfügung stehen, die die eher temperamentvollen Aspekte der Verwendung von Zeigern verbergen, z. B. den Zugriff auf den unformatierten Speicher und das Aufräumen nach Ihren Zuweisungen. Mit intelligenten Zeigern, Containerklassen und Entwurfsmustern wie RAII wird der Bedarf für die Verwendung von rohen Zeigern verringert. Das heißt, wie bei jeder Abstraktion sollten Sie verstehen, wie sie tatsächlich funktionieren, bevor Sie darüber hinausgehen.


11

Relativ einfach ausgedrückt lautet die C-Mentalität "Haben Sie ein Problem? Verwenden Sie einen Zeiger". Sie können dies in C-Strings, Funktionszeigern, Zeigern als Iteratoren, Zeigern auf Zeiger und ungültigen Zeigern sehen - selbst in den frühen Tagen von C ++ mit Elementzeigern.

In C ++ können Sie jedoch Werte für viele oder alle dieser Aufgaben verwenden. Benötigen Sie eine Funktionsabstraktion? std::function. Es ist ein Wert, der eine Funktion ist. std::string? Es ist ein Wert, das ist eine Zeichenfolge. Sie können ähnliche Ansätze in C ++ beobachten. Dies erleichtert die Analyse des Codes sowohl für den Menschen als auch für den Compiler erheblich.


In C ++: Haben Sie ein Problem? Verwenden Sie einen Zeiger. Jetzt haben Sie 2 Probleme ...
Daniel Zazula

10

Einer der Gründe ist die zu weite Anwendung von Zeigern. Sie können zum Durchlaufen von Containern verwendet werden, um zu vermeiden, dass große Objekte beim Übergeben an eine Funktion kopiert werden, nicht triviale Lebensdauerverwaltung, Zugriff auf zufällige Speicherbereiche usw. Sobald Sie sie für einen Zweck verwendet haben, stehen andere Funktionen zur Verfügung sofort selbständig auf Vorsatz.

Die Auswahl eines Tools für den genauen Zweck macht Code einfacher und bewusster sichtbar - Iteratoren für Iterationen, intelligente Zeiger für die Lebensdauerverwaltung usw.


3

Neben den bereits aufgeführten Gründen gibt es eine offensichtliche: bessere Optimierungen. Die Aliasing-Analyse ist in Gegenwart einer Zeigerarithmetik viel zu kompliziert, wohingegen Referenzen auf einen Optimierer hinweisen, sodass eine viel tiefere Aliasing-Analyse möglich ist, wenn nur Referenzen verwendet werden.


2

Neben dem von @jmquigley angegebenen Risiko von Speicherlecks kann die Zeiger- und Zeigerarithmetik als problematisch angesehen werden, da Zeiger überall im Speicher hinweisen können und "schwer zu findende Fehler" und "Sicherheitslücken" verursachen.

Aus diesem Grund wurden sie in C # und Java fast aufgegeben.


Erwarten Sie, dass sie in C # nicht "abgebrochen" wurden. Diese Antwort ist schlecht, hat eine schreckliche Rechtschreibung und eine schreckliche ungenaue Aussage.
Ramhound

1
Sie wurden fast verlassen. Ich entschuldige mich dafür, dass ich kein Muttersprachler bin.
k3b

1
Hey, wir können mit der Rechtschreibung helfen. Meinten Sie erwarten oder ausnehmen sagen?
DeveloperDon

1
Fast in C # verlassen, können Sie immer noch Zeiger ermöglichen durch Angabe unsafeSchlüsselwort
linquize

-1

C ++ unterstützt die meisten Funktionen von C sowie Objekte und Klassen. C hatte schon Zeiger und andere Sachen.

Zeiger sind eine sehr nützliche Technik, die mit der Objektorientierung kombiniert werden kann, und C ++ unterstützt sie. Diese Technik ist jedoch schwer zu lehren und zu verstehen, und es ist sehr leicht, unerwünschte Fehler zu verursachen.

Viele neue Programmiersprachen geben vor, keine Zeiger für Objekte zu verwenden, wie Java, .NET, Delphi, Vala, PHP, Scala. Es werden jedoch weiterhin Zeiger "hinter den Kulissen" verwendet. Diese "versteckten Zeigertechniken" werden "Referenzen" genannt.

Wie auch immer, ich betrachte Zeiger als Programmiermuster, als einen gültigen Weg, um bestimmte Probleme zu lösen, so wie es die objektorientierte Programmierung tut.

Andere Entwickler sind möglicherweise anderer Meinung. Ich schlage jedoch vor, dass Studenten und Programmierer lernen, wie man:

(1) Verwenden Sie Zeiger ohne Objekte

(2) Objekte ohne Zeiger

(3) explizite Zeiger auf Objekte

(4) "versteckte" Zeiger auf Objekte (AKA- Referenz ) ;-)

In dieser Reihenfolge.

Auch wenn es schwer zu lehren und schwer zu lernen ist. Object Pascal (Delphi, FreePascal, andere) und C++(nicht Java oder C #) können für diese Ziele verwendet werden.

Und später können unerfahrene Programmierer Programmiersprachen wie Java, C #, objektorientiertes PHP und andere "versteckte Zeiger auf Objekte" verwenden.


19
C ++ ist viel mehr als das "C mit Klassen", als das es begann.
David Thornley

Warum schließen Sie C ++ und C in Anführungszeichen ein? Und "versteckt", "Referenzen" und alles andere? Sind Sie ein "Verkäufer" und nehmen nicht an der "Programmierung" teil?
Phresnel

Ich sollte sie fett schreiben. Anführungszeichen können verwendet werden, um das Gegenteil
hervorzuheben

-6

Apropos VC6: Wenn Sie einen Zeiger einer Klasse (die Sie instanziieren) in eine Variable (z. B. DWORD) umwandeln, können Sie, auch wenn dieser Zeiger lokal ist, über alle Funktionen, die denselben Heap verwenden, auf die Klasse zugreifen. Die instanziierte Klasse ist als lokal definiert, ist es jedoch nicht. Soweit ich weiß, ist jede Adresse einer Heap-Variablen, -Struktur oder -Klasse während des gesamten Lebens der Hosting-Klasse eindeutig.

Beispiel:

class MyClass1 {
    public:
        void A (void);
        void B (void);
        void C (void);
    private:
        DWORD dwclass;
};

class MyClass2 {
    public:
        int C (int i);
};

void MyClass1::A (void) {
    MyClass2 *myclass= new MyClass2;
    dwclass=(DWORD)myclass;
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    int i = myclass->C(0); // or int i=((MyClass2 *)dwclass)->C(0);
}

void MyClass1::B (void) {
    MyClass2 *myclass= (MyClass2 *)dwclass;
    delete myclass;
}

EDIT Das ist ein sehr kleiner Teil des Originalcodes. Die CSRecodset-Klasse ist nur eine Casting-Klasse von CXdbRecordset, in der der gesamte echte Code enthalten ist. Auf diese Weise kann der Benutzer das, was ich geschrieben habe, nutzen, ohne meine Rechte zu verlieren. Ich behaupte nicht, dass meine Datenbank-Engine professionell ist, aber es funktioniert wirklich.

//-------------------------------------
class CSRecordSet : public CSObject
//-------------------------------------
{
public:
    CSRecordSet();
    virtual ~CSRecordSet();
    // Constructor
    bool Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef);
    //Open, find, close
    int OpenRst(bool bReadBlanks=0,bool bCheckLastSql=0,bool bForceLoad=0,bool bMessage=1);     // for a given SQL
    int FindRecord(bool bNext);         // for a given SQL
    // TABLE must be ordered by the same fields that will be seek
    bool SeekRecord(int nFieldIndex, char *key, int length=0);  // CRT bsearch
    bool SeekRecord(int nFieldIndex, long key);     
    bool SeekRecord(int nFieldIndex, double key, int decimals);     
    bool SeekRecord(XSEK *SEK);     
    bool DeleteRecord(void);
    bool Close(void);
    // Record Position:
    bool IsEOF(void);           // pointer out of bound
    bool IsLAST(void);          // TRUE if last record
    bool IsBOF(void);           // pointer out of bound
    bool IsOpen(void);
    bool Move(long lRows);      // returns FALSE if out of bound
    void MoveNextNotEof(void);  // eof is tested
    void MoveNext(void);        // eof is not tested
    void MovePrev(void);        // bof is tested
    void MoveLast(void);
    void MoveFirst(void);
    void SetAbsolutePosition(long lRows);
    long GetAbsolutePosition(void);
    void GoToLast(void); // Restore position after a Filter
    // Table info
    long GetRecordCount(void);
    int GetRstTableNumber(void);
    int GetRecordLength(void); //includes stamp (sizeof char)
    int GetTableType(void);
    // Field info
    int GetFieldCount(void);
    void GetFieldName(int nFieldIndex, char *pbuffer);
    int GetFieldIndex(const char *sFieldName);
    int GetFieldSize(int nFieldIndex);
    int GetFieldDGSize(int nFieldIndex); // String size (i.e. dg_Boolean)
    long GetRecordID(void);
    int GetStandardFieldCount(void);
    bool IsMemoFileTable(void);
    bool IsNumberField(int nFieldIndex);
    int GetFieldType(int nFieldIndex);
    // Read Field value
    bool GetFieldValue(int nFieldIndex, XdbVar& var);
    bool GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer);
    char *GetMemoField(int nMemoFieldIndex, char *pbuffer, int buf_size);
    bool GetBinaryField(unsigned char *buffer,long *buf_size);
    // Write Field value
    void Edit(void); // required
    bool SetFieldValue(int nFieldIndex, XdbVar& var);
    bool SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer);
    bool Update(void); // required
    // pointer to the same lpSql
    LPXSQL GetSQL(void);
};

//---------------------------------------------------
CSRecordSet::CSRecordSet(){
//---------------------------------------------------
    pClass |= (CS_bAttach);
}
CSRecordSet::~CSRecordSet(){
    if(pObject) delete (CXdbRecordset*)pObject;
}
bool CSRecordSet::Create(CSDataBase* pDataBase,CSQueryDef* pQueryDef){
    CXdbQueryDef *qr=(CXdbQueryDef*)pQueryDef->GetObject();
    CXdbTables *db=(CXdbTables*)pDataBase->GetObject();
    CXdbRecordset *rst = new CXdbRecordset(db,qr);
    if(rst==NULL) return 0;
    pObject = (unsigned long) rst;
    return 1;
}
bool CSRecordSet::Close(void){
    return ((CXdbRecordset*)pObject)->Close();
}
int CSRecordSet::OpenRst(bool bReadBlanks,bool bCheckLastSql,bool bForceLoad, bool bMessage){
    unsigned long dw=0L;
    if(bReadBlanks) dw|=SQL_bReadBlanks;
    if(bCheckLastSql) dw|=SQL_bCheckLastSql;
    if(bMessage) dw|=SQL_bRstMessage;
    if(bForceLoad) dw|=SQL_bForceLoad;

    return ((CXdbRecordset*)pObject)->OpenEx(dw);
}
int CSRecordSet::FindRecord(bool bNext){
    return ((CXdbRecordset*)pObject)->FindRecordEx(bNext);
}
bool CSRecordSet::DeleteRecord(void){
    return ((CXdbRecordset*)pObject)->DeleteEx();
}
bool CSRecordSet::IsEOF(void){
    return ((CXdbRecordset*)pObject)->IsEOF();
}
bool CSRecordSet::IsLAST(void){
    return ((CXdbRecordset*)pObject)->IsLAST();
}
bool CSRecordSet::IsBOF(void){
    return ((CXdbRecordset*)pObject)->IsBOF();
}
bool CSRecordSet::IsOpen(void){
    return ((CXdbRecordset*)pObject)->IsOpen();
}
bool CSRecordSet::Move(long lRows){
    return ((CXdbRecordset*)pObject)->MoveEx(lRows);
}
void CSRecordSet::MoveNextNotEof(void){
    ((CXdbRecordset*)pObject)->MoveNextNotEof();
}
void CSRecordSet::MoveNext(void){
    ((CXdbRecordset*)pObject)->MoveNext();
}
void CSRecordSet::MovePrev(void){
    ((CXdbRecordset*)pObject)->MovePrev();
}
void CSRecordSet::MoveLast(void){
    ((CXdbRecordset*)pObject)->MoveLast();
}
void CSRecordSet::MoveFirst(void){
    ((CXdbRecordset*)pObject)->MoveFirst();
}
void CSRecordSet::SetAbsolutePosition(long lRows){
    ((CXdbRecordset*)pObject)->SetAbsolutePosition(lRows);
}
long CSRecordSet::GetAbsolutePosition(void){
    return ((CXdbRecordset*)pObject)->m_AbsolutePosition;
}
long CSRecordSet::GetRecordCount(void){
    return ((CXdbRecordset*)pObject)->GetRecordCount();
}
int CSRecordSet::GetFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetFieldCount();
}
int CSRecordSet::GetRstTableNumber(void){
    return ((CXdbRecordset*)pObject)->GetRstTableNumber();
}
void CSRecordSet::GetFieldName(int nFieldIndex, char *pbuffer){
    ((CXdbRecordset*)pObject)->GetFieldName(nFieldIndex,pbuffer);
}
int CSRecordSet::GetFieldIndex(const char *sFieldName){
    return ((CXdbRecordset*)pObject)->GetFieldIndex(sFieldName);
}
bool CSRecordSet::IsMemoFileTable(void){
    return ((CXdbRecordset*)pObject)->IsMemoFileTable();
}
bool CSRecordSet::IsNumberField(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->IsNumberField(nFieldIndex);
}
bool CSRecordSet::GetFieldValueIntoBuffer(int nFieldIndex,char *pbuffer){
    return ((CXdbRecordset*)pObject)->GetFieldValueIntoBuffer(nFieldIndex,pbuffer);
}
void CSRecordSet::Edit(void){
    ((CXdbRecordset*)pObject)->Edit();
}
bool CSRecordSet::Update(void){
    return ((CXdbRecordset*)pObject)->Update();
}
bool CSRecordSet::SetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->SetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SetFieldValueFromBuffer(int nFieldIndex,const char *pbuffer){
    return ((CXdbRecordset*)pObject)->SetFieldValueFromBuffer(nFieldIndex,pbuffer);
}
bool CSRecordSet::GetFieldValue(int nFieldIndex, XdbVar& var){
    return ((CXdbRecordset*)pObject)->GetFieldValue(nFieldIndex,var);
}
bool CSRecordSet::SeekRecord(XSEK *SEK){
    return ((CXdbRecordset*)pObject)->TableSeek(SEK);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,char *key, int length){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,key,length);
}
bool CSRecordSet::SeekRecord(int nFieldIndex,long i){
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,i);
}
bool CSRecordSet::SeekRecord(int nFieldIndex, double d, int decimals)
{
    return ((CXdbRecordset*)pObject)->TableSeek(nFieldIndex,d,decimals);
}
int CSRecordSet::GetRecordLength(void){
    return ((CXdbRecordset*)pObject)->GetRecordLength();
}
char *CSRecordSet::GetMemoField(int nMemoFieldIndex,char *pbuffer, int BUFFER_SIZE){
    return ((CXdbRecordset*)pObject)->GetMemoField(nMemoFieldIndex,pbuffer,BUFFER_SIZE);
}
bool CSRecordSet::GetBinaryField(unsigned char *buffer,long *buf_size){
    return ((CXdbRecordset*)pObject)->GetBinaryField(buffer,buf_size);
}
LPXSQL CSRecordSet::GetSQL(void){
    return ((CXdbRecordset*)pObject)->GetSQL();
}
void CSRecordSet::GoToLast(void){
    ((CXdbRecordset*)pObject)->GoToLast();
}
long CSRecordSet::GetRecordID(void){
    return ((CXdbRecordset*)pObject)->GetRecordID();
}
int CSRecordSet::GetStandardFieldCount(void){
    return ((CXdbRecordset*)pObject)->GetStandardFieldCount();
}
int CSRecordSet::GetTableType(void){
    return ((CXdbRecordset*)pObject)->GetTableType();
}
int CSRecordSet::GetFieldType(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldType(nFieldIndex);
}
int CSRecordSet::GetFieldDGSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldDGSize(nFieldIndex);
}
int CSRecordSet::GetFieldSize(int nFieldIndex){
    return ((CXdbRecordset*)pObject)->GetFieldSize(nFieldIndex);
}

EDIT: beantragt von DeadMG:

void nimportequoidumomentquecaroule(void) {

    short i = -4;
    unsigned short j=(unsigned short)i;

}

1
Diese Beschreibung könnte durch Code erheblich verbessert werden, um zu veranschaulichen, was Sie beschreiben. Ich habe das Gefühl, dass es sich um die ursprüngliche Frage handelt, aber wenn Sie uns in diesem Szenario vor einer Gefahr warnen, hilft dies, das Thema des Fragestellers zu erläutern.
DeveloperDon

1
Diese DWORDUmwandlung in ist missbräuchlich und möglicherweise falsch (DWORD ist nicht unbedingt breit genug, um einen Zeiger aufzunehmen). Wenn Sie einen untypisierten Zeiger benötigen, verwenden Sie void*-, aber wenn Sie feststellen, dass Sie diesen in C ++ benötigen, haben Sie häufig ein Designproblem in Ihrem Code, das Sie beheben sollten.
Mat

Salvador, ich denke, Sie versuchen etwas über VC6 zu sagen und wie es ungewöhnliche und unerwartete Zeigerhandhabung hat. Das Beispiel könnte von Kommentaren profitieren, und wenn Sie Warnungen vom Compiler sehen, sind diese möglicherweise informativ in Bezug auf Ihre Antwort auf die Frage.
DeveloperDon

@Mat Dieses Beispiel gilt für ein 32-Bit-Betriebssystem und den VC6 ++ - Compiler.
Salvador

6
Sprechen Sie über schlechten Code in einem absolut alten Compiler? Nein Danke.
DeadMG
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.