讓類成員函數指針成爲可調用對象

    類成員函數指針實踐上是一個指針類型,不可直接通過調用運算符()作爲可調用對象調用,一般調用該類成員函數指針需要指定該指針對應的對象。

    一般情況下調用類成員函數指針:

// a.h
#ifndef A_H
#define A_H
#include <iostream>
using std::cout;
using std::endl;

class A{
public:
    void print();
};
#endif

// a.cpp
#include "a.h"
void A::print()
{
    cout << "A::print" << endl;
}

// main.cpp
#include "a.h"
using pClassF = void (A::*)(); // 聲明類A的成員函數指針類型

int main()
{
    pClassF pf= &A::print; // 定義類成員函數指針,不支持函數到指針的自動轉換
    A a;
    (a.*pf)(); // .*、->*成員訪問符,因爲訪問優先級則(a.*pf)的括號必須添加
    return 0;
}

其中A::*表示是類A的成員指針,接着的()表示是無參的函數類型;

如果直接是pf()則出錯,因爲pf不是可調用對象其未指定對象執行;


使用<functional>的std::function<T>模板類:

因爲類的成員函數執行時,會在參數列表添加參數--隱式的this實參,在function模板類調用時可以傳入對象實現this的功能(傳入的對象不一定是指針類型),function<T>判斷如果是類成員函數指針,則會將通過該對象使用成員訪問運算符,實現類成員函數指針的調用功能(具體function如何判斷是類成員函數指針還是普通函數指針,本人現在不清楚,如果有理解錯誤地方望指正):

// main.cpp ,頭文件a.h與源文件a.cpp之前相同
#include <functional>
#include "a.h"
using std::function;
using pClassF = void (A::*)(); // 聲明類A的成員函數指針類型

int main()
{
    auto pf= &A::print; // 定義類成員函數指針,不支持函數到指針的自動轉換
    A a;
    
    // void 表示成員函數的返回值,A表示傳入的參數類型爲A,因爲是模板類型則要求可以準確匹配,且A類型可以調用對應的成員函數,如果是const A類要調用const成員函數
    function<void (A)> fnt = pf;
    fnt(a);
    return 0;
}

通過fnt(a)傳入對象a,在function<T>裏通過a與成員訪問符調用成員函數。


使用std::mem_fn標準庫函數<functional>:

mem_fn函數可以通過成員函數指針的類型自動推斷可調用對象類型,用戶無須指定。在可調用對象裏有接收對象與對象指針的一組調用運算符重載函數,可使用對象或對象指針調用該成員函數,使用方式與function<T>相同:

// main.cpp,頭文件a.h與源文件a.cpp之前相同
#include <functional>
#include "a.h"
using std::mem_fn;
using pClassF = void (A::*)() const; // 聲明類A的成員函數指針類型

int main()
{
    auto pf= &A::print; // 定義類成員函數指針,不支持函數到指針的自動轉換
    A a;
    auto fnt = mem_fn(pf); // mem_fn通過成員函數指針自動推導可調用對象類型
    fnt(a); // 使用對象調用成員函數
    fnt(&a); // 使用對象指針調用成員函數
    return 0;
}

fnt(a)與fnt(&a)的結果一致。


使用通用的函數適配器bind生成可調用對象,需要命名空間std::placeholders表示在bind傳給函數的參數:

與function<T>類似,將隱式傳入this形參轉爲顯示傳入對象;與mem_fn類似,生成的可調用對象有接收對象與對象指針的一組重載調用運算符函數:

// main.cpp,頭文件a.h與源文件a.cpp之前相同
#include <functional>
#include "a.h"
using namespace std::placeholders; // 用於表示bind傳入指定函數的形參位置,即bind的_1、_2、...、_n等
using pClassF = void (A::*)() const; // 聲明類A的成員函數指針類型

int main()
{
    auto pf= &A::print; // 定義類成員函數指針,不支持函數到指針的自動轉換
    A a;
    auto fnt = bind(pf,_1); // _1表示在bind該位置的參數傳給pf,併成爲pf的第一個形參
    fnt(a); // 使用對象調用成員函數
    fnt(&a); // 使用對象指針調用成員函數
    return 0;
}

詳細說明可查閱bind函數,fnt(a)與fnt(&a)的結果一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章