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++?.
_ "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
@ 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. –
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