関数ポインタ関連 (C++をもう一度)
[最終更新] (2019/06/03 00:41:34)

一般の関数ポインタ

#include <iostream>
using namespace std;

void MyFunc() {
    cout << "MyFunc" << endl;
}

int MyFuncA(int intval) {
    return intval;
}

int MyFuncB(int intval) {
    return intval;
}

int main() {
    // const を付与したい場合
    void (*const FP)() = MyFunc;
    FP(); //=> MyFunc

    // 同じ型の関数ポインタは配列で利用可能
    int (*const FP_AB[])(int intval) = {
        MyFuncA, MyFuncB
    };
    cout << FP_AB[0](1) << endl; //=> 1
    cout << FP_AB[1](1) << endl; //=> 1

    // 関数ポインタの型は長ったらしいので typedef することが多い
    typedef int (*FpMyFuncAB)(int intval);
    const FpMyFuncAB FP_A = MyFuncA;
    cout << FP_A(1) << endl; //=> 1

    return 0;
}

「静的メンバ関数」ポインタ

#include <iostream>
using namespace std;

class MyClass {
public:
    static void Show();

private:
    typedef void (*FpShow)();

public:
    static const FpShow FP_SHOW;

private:
    static const int m_intval; // static const は通常クラス内で初期化するが
                               // https://www.qoosky.io/techs/fc41205299
};

void MyClass::Show() {
    cout << m_intval << endl;
}

const MyClass::FpShow MyClass::FP_SHOW = MyClass::Show;
const int MyClass::m_intval = 1; // static const であってもここで初期化できる


int main() {
    MyClass::Show(); //=> 1
    MyClass::FP_SHOW(); //=> 1
    return 0;
}

「静的でないメンバ関数」ポインタ

#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass(int intval);

public:
    void Show();
    void SShow();

private:
    typedef void (MyClass::*FpShow)(); // 静的メンバ関数と異なり "MyClass::" が必要

public:
    static const FpShow FP_SHOW; // オブジェクトが異なってもメンバ関数のアドレス自体は一定。
    // (メモリ上のある定位置に展開されているメンバ関数に渡す、オブジェクトのアドレスが毎回異なるだけ)
    // そのため、オブジェクト間で FP_SHOW を共有しても問題にならない。

private:
    int m_intval;
};

const MyClass::FpShow MyClass::FP_SHOW = &MyClass::Show; // 静的メンバ関数ポインタと異なり & が必要

MyClass::MyClass(int intval) :
    m_intval(intval)
{
}

void MyClass::Show() {
    cout << m_intval << endl;
}

void MyClass::SShow() {
    // メンバ関数ポインタ FP_SHOW に呼び出しもとオブジェクト this を渡します。
    // "->*" や ".*" は渡すための演算子です。演算の優先順位が低いため、全体を () で囲みます。
    (this->*FP_SHOW)();
}

int main() {
    MyClass objA(1);
    MyClass objB(-1);
    objA.Show(); //=> 1
    objB.Show(); //=> -1
    (objA.*MyClass::FP_SHOW)(); //=> 1
    (objB.*MyClass::FP_SHOW)(); //=> -1

    MyClass* ptrA = &objA;
    MyClass* ptrB = &objB;
    (ptrA->*MyClass::FP_SHOW)(); //=> 1
    (ptrB->*MyClass::FP_SHOW)(); //=> -1

    objA.SShow(); //=> 1
    objB.SShow(); //=> -1

    return 0;
}

仮想関数のポインタ

アップキャスト時の仮想関数の呼び分けは正常に行われます。

#include <iostream>
using namespace std;

class MyClass {
public:
    virtual ~MyClass() {}

public:
    virtual void Show();
};

class MySubClass :
    public MyClass
{
public:
    virtual void Show();
};

void MyClass::Show() {
    cout << "MyClass::Show" << endl;
}

void MySubClass::Show() {
    cout << "MySubClass::Show" << endl;
}

int main() {
    MySubClass obj;
    MyClass& ref = obj; // アップキャスト

    ref.Show(); //=> MySubClass::Show

    void (MyClass::*fp)() = &MyClass::Show;
    (ref.*fp)(); //=> MySubClass::Show
    // ↑仮想関数の呼び分けが正常に行われた (MyClass::Showとはならない)

    return 0;
}

メンバ変数ポインタ

この続きが気になる方は

関数ポインタ関連 (C++をもう一度)

残り文字数は全体の約 23 %
tybot
100 円
関連ページ
    概要 C++11 で導入されたラムダ式について簡単なサンプルコードを記載します。 ラムダ式の構文 以下のように記述します。 #include <iostream> int main() { auto f = [](std::string mystr){ std::cout << mystr << std::endl;}; f("Hello World"); retur
    概要 C++ を Python から利用する方法の一つに pybind11 があります。C++11 をサポートするコンパイラが必要です。サンプルコードを記載します。 pybind11 — Seamless operability between C++11 and Python Reference 簡単なサンプル