friend 属性を継承する

C++ では,クラスを継承しても friend 属性は継承されない.継承させたい場合,どうするか?

friend は使わない方がいいといわれることがあるが,operator<<や operator>> の定義など,使った方がよい場合もある (e.g. When should you use ‘friend’ in C++?).

問題設定

  • クラス TItem は private メンバ変数 x_ を持つ.x_ はユーザに書き換えられてはならない
  • クラス TTest は TItem を要素に持ち, x_ を書き換えることがある
    • TItem はあくまで TTest の要素.TItem を派生させたりはしない
  • ユーザがクラス TTest と類似のクラスを作られるようにしたい
    • そのクラスは TItem の x_ を書き換えることがある

ユーザが作るクラスの識別子は不明なので,ユーザが作るクラスを TItem の friend クラスにするのは無理.

そこで,TItem の friend クラスを基本クラスとして作成,そこから TTest などを派生するようにする.ただし,派生しても friend 属性は継承されないから,基本クラスに TItem の private メンバにアクセスする関数群を作る.

#include <iostream>
using namespace std;

class TItem
{
private:
  double x_;
  friend class TBase;
};

class TBase
{
protected:
  static double& x_(TItem &i) {return i.x_;}
  static const double& x_(const TItem &i) {return i.x_;}
};

class TTest : public TBase
{
public:
  TTest(const double &init)
    {
      x_(i_)= init;
        // NOTE: i_.x_ は private なのでアクセスできない(TTest は TItem の friend じゃない)
      cerr<<"x_(i_) has been initialized by "<<x_(i_)<<endl;
    }
private:
  TItem i_;
};


int main(int argc, char**argv)
{
  TTest t1(0.5);
  TTest t2(3.14);
  return 0;
}

これで,ユーザは基本クラス TBase から派生させたクラスからでないと,TItem のメンバ変数を書き換えることは不可能.逆に,TBase から派生させたどんなクラスでも,TItem のメンバ変数を書き換えられる.