モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

工作HardwareHub ロゴ画像 (Laptop端末利用時)
工作HardwareHub ロゴ画像 (Mobile端末利用時)

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

モーダルを閉じる

ステッカーを選択してください

モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2014/12/24
最終更新最終更新
2021/10/07
記事区分記事区分
一般公開

目次

    低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。

    0
    ステッカーを贈るとは?

    一般の関数ポインタ

    #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 は通常クラス内で初期化するが
    };
    
    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;
    }
    

    メンバ変数ポインタ

    あるオブジェクトのメモリ領域のどの範囲がメンバ変数の領域であるかを知るポインタです。オブジェクトに固有のポインタではなくクラスに固有のポインタです。メンバ変数ポインタに渡すオブジェクトのアドレスが毎回異なるだけです。

    #include <iostream>
    using namespace std;
    
    class MyClass {
    public:
        MyClass(int x, int y);
    
    public:
        void Show();
        void IncrementX();
        void IncrementY();
    
    private:
        void Increment(int MyClass::*mp); // typedef する場合:
        // typedef int MyClass::*MpXy; // "int MyClass::*" => "MpXy"
        // void Increment(MpXy mp);
    
    private:
        int m_x;
        int m_y;
    };
    
    MyClass::MyClass(int x, int y) :
        m_x(x), m_y(y)
    {
    }
    
    void MyClass::Show() {
        cout << m_x << ", " << m_y << endl;
    }
    
    void MyClass::IncrementX() {
        Increment(&MyClass::m_x);
    }
    
    void MyClass::IncrementY() {
        Increment(&MyClass::m_y);
    }
    
    void MyClass::Increment(int MyClass::*mp) { // typedef する場合:
    // void MyClass::Increment(MpXy mp) {
        ++(this->*mp);
    }
    
    int main() {
        MyClass obj(0,0);
        obj.IncrementX();
        obj.Show(); //=> 1, 0
        obj.IncrementY();
        obj.Show(); //=> 1, 1
    
        return 0;
    }
    
    0
    詳細設定を開く/閉じる
    アカウント プロフィール画像 (本文下)

    低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    さらに詳しく →
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      関連記事