Samstag, Januar 18, 2020

Übergeben einer Klasse member-Funktion als Funktion der parameter

Ich habe 2 C++ – Klassen-Fragen:

Die 1. Frage ist: Wie kann ich es machen, damit ich Vorbeigehen kann, ein Klasse member-Funktion als parameter in eine andere Funktion, die & wie kann ich dann/rufe diese Funktion? Und wie kann ich das gleiche tun mit einer Klasse statische Funktion. Es vielleicht leichter zu verstehen, meine Frage mit Blick auf diese code:

class DebuggingManager
{
    string testLog;

    bool test1()
    {
         //run test & return whether it passed or failed
    }    

    static bool test2()
    {

    }

    //How can I call a member function?
    void catalogueTest( string testName, bool DebuggingManager::*nMemberFunction )
    {
        testLog += "Status of " + testName + ": " + ((*)nMemberFunction()) + "\n"; 
    }

    //How can I call a static function?
    void catalogueTest( string testName, bool DebuggingManager::*nStaticFunction )
    {
        testLog += "Status of " + testName + ": " + DebuggingManager::nStaticFunction() + "\n"; 
    }

    //how do I pass a member function or a static function as a parameter in another function 
    bool runTests()
    {
         catalogueTest( "Test of member functin", test1() );
         catalogueTest( "Test of static functin", test2() );
    }

};

Die 2. Frage ist: Ist es schlimm(oder gefährlich) Praxis zu nennen, ein Schüler (oder statische) Funktion indirekt wie oben. Ich habe das Gefühl, das ist wirklich eine schlechte C++ – Praxis?

BEARBEITEN: Durchführung von Beratung
Danke für die Antwort, habe ich versucht zu implementieren, die Beratung, seine eine Menge in meinen Kopf zu kriegen, würde dies korrekt sein?

    //I have a feeling that ParameterList is incorect, would I pass the implicit obj as a parameter or is it done automatically like in normal object function calls?
    typedef bool (DebuggingManager::*MemberPointerType)(ParameterList); 

    void catalogueTest( tstring testName, DebuggingManager* obj, MemberPointerType *nMemberFunction )
    {
        debugLog += _T("Status of ") + testName + _T(": ") + (obj->*nMemberFunction)() + _T("\r\n");
    }

    void catalogueStaticTest( tstring testName, bool DebuggingManager::nStaticFunction )
    {
        debugLog += _T("Status of ") + testName + _T(": ") + nStaticFunction + _T("\r\n");
    }
  • Ich bin überrascht, dass dies nicht bereits beantwortet. Vielleicht jeder andere ist müde und will nicht, um die syntax für die Funktion Zeiger für den 500sten mal.
  • siehe stackoverflow.com/questions/2463112/… gibt einen link zu parashift.com/c++-faq-lite/pointers-to-members.html die die syntax und die Dinge zu achten, wenn die Deklaration/Verwendung von normal-und statische member-Funktion-Zeiger. Als ob es schlecht würde ich sagen: wahrscheinlich nicht in einem bestimmten Fall (wie testen, oder vielleicht andere), aber es wäre nicht gut zu tun, wie ein Tag-zu-Tag Praxis für das schreiben von code, da es schwierig ist, und da gibt es bessere Mechanismen, die für die meisten alles, was Sie würden Sie für den Einsatz.
InformationsquelleAutor user593747 | 2011-08-28

2 Kommentare

  1. 13

    Statische member-Funktionen von Klassen sind letztlich nicht anders als normale Funktionen. Sie sind wirklich nur syntaktischer Zucker; die Funktion ist einfach die einen Namen hat, gehören Classname::.

    Nicht-statische member sind eine ganz andere Sache. Es gibt zwei wichtige Dinge zu erinnern, über die nicht-statische member-Funktionen (NSMF).

    Zunächst jedes nicht-statische member-Funktion hat Zugriff auf nicht-statische member der Klasse, in der Sie Mitglied sind. Dies ist möglich, obwohl Sie können auch zwei Objekte derselben Klasse, die zufällig zum speichern verschiedener Daten. Wenn Sie zwei std::string Objekte, die Sie jedem Shop unterschiedliche Zeichenfolgen. Ausführen einer find auf der einen string zurückgeben kann gefunden in einer Folge, aber nicht die anderen.

    Dies ist, weil jeder NSMF hat eine implizite this Zeiger. this bezieht, nicht nur eine Klasse, sondern die tatsächliche Objekt auf die, die NSMF betreibt. Wenn Sie dies tun:

    std::string aString("data");
    aString.find("da");

    Den find – Funktion nimmt einen string-argument, aber es wird auch aString als seine this. Jedes mal, wenn find sieht für die Mitglieder der Klasse, es wird gesucht aString’s Daten.

    Also schauen wir uns an Ihren zukünftigen Ruf eines NSMF:

    ((*)nMemberFunction())

    Wo ist das Objekt, das es bekommt seine this Zeiger aus? Ohne ein Objekt, das NSMF konnte nicht auf die nicht-statische member des Objekts, da es kein Objekt für Sie zu finden, Sie in. Dies ist nicht legal.

    So, Regel #1 zu NSMFs: Sie muss rufen Sie mit einem aktuellen Instanz der Klasse, die NSMF ist ein Mitglied (oder eine abgeleitete Klasse davon). Sie können nicht nehmen Sie nur eine NSMF Zeiger und nennen es wie ein Funktionszeiger; Sie rufen es auf einem live-Objekt von diesem Typ.

    Regel #2: die syntax für NSMF Zeiger ist wirklich hässlich.

    Definieren Sie eine variable (oder argument) mit dem Namen arg von NSMF Zeiger geben Sie dies tun:

    ReturnType (ClassName::*arg)(ParameterList);

    Wo ReturnType ist der Rückgabetyp der Funktion, ParameterList ist die Liste von Argumenten, die Funktion und die ClassName ist der name der Klasse, zu der die NSMF Zeiger gehört.

    Angesichts der Hässlichkeit, ist es normalerweise am besten, um wickeln Sie es in ein typedef:

    typedef ReturnType (ClassName::*MemberPointerType)(ParameterList);

    Somit die typedef MemberPointerType, das ist ein NSMF Zeiger.

    Gegeben ein Objekt mit dem Namen object, die den Typ ClassName rufen Sie das Mitglied Zeiger arg wie folgt:

    ReturnType value = (object.*arg)(Params);

    Wo Params sind die Argumente, die Sie übergeben möchten. Wenn object ist ein Zeiger auf eine ClassName statt eine Referenz oder einen Wert, dann verwenden Sie object->*arg statt.

    Eins noch: Sie muss verwenden & um die member-Zeiger-Namen. Im Gegensatz zu Funktionszeigern, NSMF Zeiger nicht automatisch konvertieren member-Zeiger. Sie haben Fragen, für die Sie direkt. Also, wenn ClassName hat ein Mitglied namens Funktion, passen die oben genannten ReturnType und ParameterList Sie füllen würde arg wie folgt:

    arg = &ClassName::Function;

    Regel #3: nicht-statische member-Zeiger sind keine Zeiger. Ja, Sie können auf NULL gesetzt werden (technisch, Sie kann auf 0 gesetzt werden), aber Sie sind nicht das gleiche wie ein Zeiger.

    Meisten realen C-und C++ – Compiler ermöglichen Ihnen die cast-Funktion Zeiger auf eine void* – und Rückseite. Die standards berücksichtigen Sie dies zu undefiniertem Verhalten, aber es ist nicht-ganz-unbekannt, dies zu tun. Sie absolut nicht dies mit einer NSMF Zeiger, die auf praktisch allen C++ – Compilern. In der Tat, die sizeof(MemberPointerType) wird wahrscheinlich nicht die gleiche Größe wie void*.

    So, NSMF Zeiger sind keine gewöhnlichen Zeiger. Nicht behandeln Sie als solche.

    • Würden Sie nicht sagen (object.*arg)(Params); weil der Rangfolge?
    • SB: ja, .* hat eine geringere Priorität als ein Funktionsaufruf.
    • Bolas: vielen Dank für Ihre Antwort. Ich habe versucht, das umzusetzen, was Sie gesagt haben, ist es richtig?
    • Behoben. Danke.
  2. 2

    In C++ 11 kamen Sie mit einem Weg, dies zu tun. Lesen Sie über Funktion und binden Operationen.

    In deinem Fall, sagen wir mal, Sie wollten zum aufrufen von Funktionen des Typs test1. (d.h. von der form bool-FunctionName().

    void catalogueTest( string testName, std::function<bool()> myFunction)
    {
        testLog += "Status of " + testName + ": " + myFunction() + "\n"; 
    }

    – Und nennen es wie folgt:

    DebuggingManager myInstance
    myInstance->catalogueTest("TestName", std::bind(&DebuggingManager::test1, myInstance));

Kostenlose Online-Tests