とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

仮想フレンド関数イディオム 超簡単な説明

問題

friend は virtual ではないので,フレンド関数は動的束縛することができません。

struct base{
 virtual ~base(){}
 friend void friend_func();
};

struct derived : public base{
 virtual ~derived(){}
 friend void friend_func(); // virtual にしたい…
                            // ついでに言うと継承するたび(クラスごと)に
                            // friend 指定めんどい…
};

void friend_func(){
 // base か derived かで動作を変えたい!多態が欲しい!
}

では,実行時にクラスによってフレンド関数の動作を変えたい時にはどうしたらよいのでしょうか?

フレンド関数内で仮想メンバ関数を呼びます。これだけです。これを「仮想フレンド関数イディオム(virtual friend function idiom)」と呼ぶそうです。

struct base{
 virtual ~base(){}
 // friend 指定は base のみ。安心。
 friend void friend_func(const base& b);
protected:
 // 実際の仕事をする仮想メンバ関数を用意
 virtual void helper()const{}
};

struct derived : public base{
 virtual ~derived(){}
 // サブクラスには friend 一切不要!
protected:
 virtual void helper()const{}
};

void friend_func(const base& b){
 b.helper(); // 仮想メンバ関数を呼ぶだけ
             // 仕事はこいつに任せる。あとは勝手に多態してくれる。
}