Ich möchte einen Funktionszeiger als Mitglied einer Klasse einrichten, die auf eine andere Funktion in derselben Klasse verweist. Die Gründe, warum ich das tue, sind kompliziert.
In diesem Beispiel möchte ich, dass die Ausgabe "1" ist.
class A {
public:
int f();
int (*x)();
}
int A::f() {
return 1;
}
int main() {
A a;
a.x = a.f;
printf("%d\n",a.x())
}
Dies schlägt jedoch beim Kompilieren fehl. Warum?
Die Syntax ist falsch. Ein Elementzeiger ist eine andere Typkategorie als ein gewöhnlicher Zeiger. Der Mitgliedszeiger muss zusammen mit einem Objekt seiner Klasse verwendet werden:
class A {
public:
int f();
int (A::*x)(); // <- declare by saying what class it is a pointer to
};
int A::f() {
return 1;
}
int main() {
A a;
a.x = &A::f; // use the :: syntax
printf("%d\n",(a.*(a.x))()); // use together with an object of its class
}
a.x
Sagt noch nicht an welchem Objekt die Funktion aufgerufen werden soll. Es heißt nur, dass Sie den im Objekt a
gespeicherten Zeiger verwenden möchten. Wenn Sie dem Operator .*
Ein anderes Mal a
voranstellen, teilt dies dem Compiler mit, für welches Objekt die Funktion aufgerufen werden soll.
int (*x)()
ist kein Zeiger auf die Mitgliedsfunktion. Ein Zeiger auf eine Mitgliedsfunktion wird folgendermaßen geschrieben: int (A::*x)(void) = &A::f;
.
Member-Funktion auf String-Befehl aufrufen
#include <iostream>
#include <string>
class A
{
public:
void call();
private:
void printH();
void command(std::string a, std::string b, void (A::*func)());
};
void A::printH()
{
std::cout<< "H\n";
}
void A::call()
{
command("a","a", &A::printH);
}
void A::command(std::string a, std::string b, void (A::*func)())
{
if(a == b)
{
(this->*func)();
}
}
int main()
{
A a;
a.call();
return 0;
}
Achten Sie auf (this->*func)();
Und die Deklaration des Funktionszeigers mit dem Klassennamen void (A::*func)()
Sie müssen einen Zeiger auf eine Elementfunktion verwenden, nicht nur einen Zeiger auf eine Funktion.
class A {
int f() { return 1; }
public:
int (A::*x)();
A() : x(&A::f) {}
};
int main() {
A a;
std::cout << (a.*a.x)();
return 0;
}
Während dies auf den Sterling-Antworten an anderer Stelle auf dieser Seite basiert, hatte ich einen Anwendungsfall, der von ihnen nicht vollständig gelöst wurde. Für einen Vektor von Zeigern auf Funktionen gehen Sie wie folgt vor:
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
class A{
public:
typedef vector<int> (A::*AFunc)(int I1,int I2);
vector<AFunc> FuncList;
inline int Subtract(int I1,int I2){return I1-I2;};
inline int Add(int I1,int I2){return I1+I2;};
...
void Populate();
void ExecuteAll();
};
void A::Populate(){
FuncList.Push_back(&A::Subtract);
FuncList.Push_back(&A::Add);
...
}
void A::ExecuteAll(){
int In1=1,In2=2,Out=0;
for(size_t FuncId=0;FuncId<FuncList.size();FuncId++){
Out=(this->*FuncList[FuncId])(In1,In2);
printf("Function %ld output %d\n",FuncId,Out);
}
}
int main(){
A Demo;
Demo.Populate();
Demo.ExecuteAll();
return 0;
}
So etwas ist nützlich, wenn Sie einen Befehlsinterpreter mit indizierten Funktionen schreiben, die mit Parametersyntax und Hilfetipps usw. verwechselt werden müssen. Möglicherweise auch nützlich in Menüs.
Obwohl Sie einen vorhandenen Member-Funktionszeiger leider nicht in einen einfachen Funktionszeiger konvertieren können, können Sie auf einfache Weise eine Adapterfunktionsvorlage erstellen, die einen zur Kompilierungszeit bekannten Member-Funktionszeiger in eine normale Funktion wie die folgende einschließt:
template <class Type>
struct member_function;
template <class Type, class Ret, class... Args>
struct member_function<Ret(Type::*)(Args...)>
{
template <Ret(Type::*Func)(Args...)>
static Ret adapter(Type &obj, Args&&... args)
{
return (obj.*Func)(std::forward<Args>(args)...);
}
};
template <class Type, class Ret, class... Args>
struct member_function<Ret(Type::*)(Args...) const>
{
template <Ret(Type::*Func)(Args...) const>
static Ret adapter(const Type &obj, Args&&... args)
{
return (obj.*Func)(std::forward<Args>(args)...);
}
};
int (*func)(A&) = &member_function<decltype(&A::f)>::adapter<&A::f>;
Beachten Sie, dass zum Aufrufen der Member-Funktion eine Instanz von A
angegeben werden muss.