2017-03-12 3 views
5

Vor kurzem habe ich das Buch Wirksame C++ gelesen und es gibt eine Erklärung über Typdef in Punkt 35, die mich verwirrt.Wie man die Typedef in dieser Erklärung zu verstehen

Also meine erste Frage ist: Warum verwendet der Autor eine Vorwärtsdeklaration hier? Gibt es einen bestimmten Grund?

Und meine zweite Frage ist: Wie verstehe ich die Typedef-Erklärung, und wie verwende ich sie? Ich weiß nur so etwas wie typedef int MyInt;

Antwort

8

Also meine erste Frage ist, warum die Erklärung Verwendung Vorwärts-Autors hier?

Damit der Compiler weiß, dass GameCharacter ein gültiger Name ist, wenn die int defaultHealthCalc(const GameCharacter& gc); Linie angetroffen wird.

Und meine zweite Frage ist, wie man die Typedef Erklärung und wie man es benutzt?

Idealerweise tun Sie nicht verwenden Sie es nicht mehr.

Beginnend mit C++ 11, using ist eine bessere Alternative, weil es besser lesbar ist; Im Gegensatz zu typedef 'Ed Funktionszeigern, trennt es deutlich den Namen von dem, was der Name beschreibt. Vergleichen Sie dies:

typedef int (*HealthCalcFunc)(const GameCharacter&); 

mit diesem:

using HealthCalcFunc = int (*)(const GameCharacter&); 

In der typedef Version wird der Name HealthCalcFunc auf beiden Seiten umgeben von dem, was der Name beschreibt. Das schmerzt Lesbarkeit.


aber der Code noch verbessert werden kann, weil C++ 11 auch als Alternative eingeführt std::function und/oder eine Abstraktionsschicht oberhalb Funktionszeigern.

using HealthCalcFunc = std::function<int(const GameCharacter&)>; 

Dies ist so lesbar es so gut wie gar erklärt werden muss. HealthCalcFunc ist eine Funktion, die eine int zurückgibt und eine const GameCharacter& übernimmt.

Die Funktion defaultHealthCalc passt in diese Definition. Hier ist ein vollständiges Beispiel:

#include <functional> 

class GameCharacter; 

int defaultHealthCalc(const GameCharacter& gc); 

class GameCharacter { 
public: 
     using HealthCalcFunc = std::function<int(const GameCharacter&)>; 

     explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) 
     : healthFunc(hcf) 
     {} 
     int healthValue() const 
     {return healthFunc(*this); } 
private: 
     HealthCalcFunc healthFunc; 
}; 

Die große Sache über std::function ist, dass Sie nicht zu freistehend sind eingeschränkte Funktionen. Sie können jede funktionsähnliche Sache passieren. Hier sind einige Beispiele:

struct Functor 
{ 
    int f(const GameCharacter& gc); 
}; 

int main() 
{ 
    // normal function: 
    GameCharacter character1(defaultHealthCalc); 

    // lambda: 
    GameCharacter character2([](auto const& gc) { return 123; }); 

    // using std::bind: 
    Functor functor; 
    using namespace std::placeholders; 
    GameCharacter character3(std::bind(&Functor::f, functor, _1)); 
} 

Siehe auch Should I use std::function or a function pointer in C++?.

+0

_ "Da der Code immer noch ** verbessert werden kann **" _: Erwähnen von 'std :: function' ist hier angebracht, aber es ist eine völlig andere Alternative, und für ein einfaches Beispiel wie dieses könnte es Es könnte irreführend sein, Verbesserungen zu erwähnen, wenn von einem leichten Funktionszeigertyp auf die völlig andere und im Vergleich dazu "schwere" Kreatur von "std :: function" umgeschaltet wird. Beide haben ihren Platz (meistens sollten imo, 'std :: function 'bevorzugt werden, aber wenn man mit älteren APIs arbeitet ...), aber sie sind sehr unterschiedliche Konzepte, und ob man einen über den anderen verwendet, sollte gegen den Kontext gewichtet werden . – dfri

+0

@ dfri: Ich denke, 'std :: function' ist viel einfacher zu schreiben, lesen und anwenden als ein Funktionszeiger, also halte ich es für die Standardlösung, während Funktionszeiger Spezialbestien sind. –

+0

Ja, ich stimme zu, notiere mein Ninja-Edit.Wenn man jedoch 'std :: function' als eine ständige Verbesserung nennt, kann es nützlich sein, darauf hinzuweisen, dass es Situationen gibt, in denen ein einfacher Funktionszeiger vorzuziehen ist (oder sogar die einzige Alternative). Wie auch immer, gute Antwort, nur eine kleine Nebenzeile von mir oben! – dfri

9
typedef int (*HealthCalcFunc)(const GameCharacter&); 

Erklärt ein typedefHealthCalcFunc für einen Funktionszeigertyp benannt, wobei die Funktionssignatur eine int zurückgibt und einen Parameter const GameCharacter&.

Die Forward-Deklaration wird benötigt, da diese Klasse als Parametertyp in typedef verwendet wird.

11

Die Forward-Deklaration wird wegen der Forward-Deklaration von defaultHealthCalc benötigt, die verwendet. Ohne Vorwärtsdeklaration würde der Compiler später nicht wissen, dass es einen Typ mit dem Namen GameCharacter geben wird, und Sie müssen daher die Deklaration weiterleiten oder die Definition vor der Funktionsdeklaration verschieben.

Das typedef bedeutet, den Typ int(*)(const GameCharacter&)HealthCalcFunc zu benennen. Das ist ein Funktionszeiger auf int(const GameCharacter&). Aus diesem Grund typedefs ziemlich unlesbar sind, ist es ratsam, stattdessen eine using Deklaration zu verwenden:

using HealthCalcFunc = int(*)(const GameCharacter&); 
13

Also meine erste Frage ist, warum der Autor Verwendung Vorwärtsdeklaration hier?

Da die Deklaration der Funktion defaultHealthCalcconst GameCharacter& als Typ des Parameters verwendet wird, dann muss GameCharacter im Voraus angemeldet werden.

Und meine zweite Frage ist, wie die typedef Erklärung

Es deklariert einen Typnamen HealthCalcFunc, zu verstehen, die eine Art von Zeiger auf Funktion, die const GameCharacter& als Parameter nimmt und int.

und wie man es benutzt?

So wie das Codebeispiel

zeigte
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) // declare a parameter with type HealthCalcFunc; 
                   // the default argument is function pointer to defaultHealthCalc 
: healthFunc(hcf)            // initialize healthFunc with hcf 
{} 

int healthValue() const 
{return healthFunc(*this); }         // invoke the function pointed by healthFunc 

HealthCalcFunc healthFunc;          // declare a member with type HealthCalcFunc 
2

Die Vorwärtsdeklaration von GameCharacter ist nicht unbedingt erforderlich; die Funktionsdeklaration gelesen haben könnte:

int defaultHealthCalc(const class GameCharacter& gc); 

die die gleiche Wirkung wie das Original-Code hat. Aber es wird als lesbarer angesehen, die Vorwärtsdeklaration in einer eigenen Zeile zu haben.

Verwandte Themen