l VisualC フレンドクラス・多重継承 '97.00.00
l.お知らせ 内容 LINK FILE   HTML Win PC Unix MS-DOS C C++ Mfc Java 
目次.C++言語_ 1 クラス 2 派生クラス 5 演算子のオーバーロード クラス(1)
 準備 3 オブジェクト 6 テンプレート 8 etc クラス(2)
 CC++ 4 フレンド・多重継承 7 メモリ確保・例外処理 未使用

フレンドクラス   フレンド関数   多重継承   多重継承の用例

T フレンドクラス
クラスのプライベートメンバは、他のクラスからはアクセスできません。

しかし、あらかじめフレンドの指定をしておけば、フレンドに指定したクラスからはプライベートメンバにアクセスできます。

#include <iostream.h>    /* フレンドクラス */
class C1  // クラス C1 の宣言
{ private :         // すべてプライベートメンバ
   int a;    
   C1(int i) { a=i; }            // コンストラクタ
  friend class C2;               // C2 をフレンドクラスに指定
  // フレンドの指定を記述する位置(行)は、特に制限がありません。
};
// クラス C1 が、クラス C2 をお友達に選びました。
class C2  // クラス C2 の宣言
// このクラス C2 は、C1 からお友達として認められています。
{ public:
  void func2()
  { C1 OB(5);  // クラス C1 のオブジェクトを宣言
    cout << OB.a << endl; // クラス C1 メンバ OB.a を表示します。
  } // クラス C1 の、プライベートメンバにアクセスできます。
};
void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }

このように、フレンドに指定されたクラスは、フレンドの指定をしたクラスのプライベートメンバにアクセスできます。
 
ところで、派生クラスのメンバ関数は、基本クラスからコピーされたプライベートメンバデータを直接操作することはできません。
 
この場合、基本クラスで派生クラスをフレンドクラスに指定すれば、 基本クラスからコピーされたプライベートメンバデータを 派生クラスのメンバ関数で直接操作することができます。

T フレンド関数
フレンド関数はどこからでもアクセスできる(皆とお友達になる)関数です。
参考 : {クラス}の外側で宣言した関数はグローバル関数になり、どこからでも呼び出すことができます。
(この意味では、C言語の関数はすべてグローバル関数でした。)
フレンド関数は、グローバル関数をクラスの中に書いたものです。
フレンド関数の呼び出し方は、グローバル関数の場合とまったく同じです。
#include <iostream.h> /* フレンド関数(1)=グローバル関数 */
class C1  // クラス C1 の宣言
{ private : int a;    // メンバデータ
  public:   C1(int i) { a=i; }                 // コンストラクタ  
  friend void funcF() { cout << "AA" << endl;} // フレンド関数
};
class C2 // クラス C2 の宣言 { public: void func2() { funcF(); } // フレンド関数を呼び出します。(AA と表示) }; void funcG() { cout << "AA" << endl;} // グローバル関数の例 void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し funcF(); // フレンド関数を呼び出します。(AA と表示) cout << "文字を入力して下さい"; char x; cin >> x; }

このままではグローバル関数と同じなので、引数にそのクラスのオブジェクトを受け取るように変更します。
そのクラスのオブジェクトだけを受け取るから、メンバ関数であるということができます。
#include <iostream.h> /* フレンド関数(2) */
class C1  // クラス C1 の宣言
{ private : int a;    // メンバデータ
  public:   C1(int i) { a=i; }                      // コンストラクタ  
  friend void funcF(C1 ob) { cout << ob.a << endl;} // フレンド関数
};
class C2 // クラス C2 の宣言 { public: void func2() { C1 OB(5); // クラス C1 のオブジェクトを宣言 funcF(OB); // フレンド関数を呼び出します。(a を表示) } // オブジエクト OB は、宣言した関数 func2() の動作が終了すれば消滅します。 }; void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }

関数の引数にオブジェクトを受け取るのは非効率的です。
次のように、ポインタや参照を使うと効率が高くなります。
#include <iostream.h> /* フレンド関数(3) */
class C1  // クラス C1 の宣言
{ private : int a;    // メンバデータ
  public:   C1(int i) { a=i; }                    // コンストラクタ 
  friend void f1(C1 *p)  { cout << p->a << endl;} // フレンド関数(引数はポインタ)
  friend void f2(C1 &ob) { cout << ob.a << endl;} // フレンド関数(引数は参照)
};
class C2 // クラス C2 の宣言 { public: void func2() { C1 OB(5); // クラス C1 のオブジェクトを宣言 f1(&OB); // フレンド関数を呼び出します。(ポインタで呼出し) f2(OB); // フレンド関数を呼び出します。(OB の参照が受取られる) } // オブジエクト OB は、宣言した関数 func2() の動作が終了すれば消滅します。 }; void main() { C2 OB2; // クラス C2 のオブジェクトを宣言 OB2.func2(); // クラス C2 のメンバ関数を呼び出し cout << "文字を入力して下さい"; char x; cin >> x; }


T 多重継承
複数のクラスを基本クラスにします。
多重継承を行うには、基本クラスを複数指定します。
class C1{ public: int D1; };        // 基本クラス 1
class C2{ public: int D2; };        // 基本クラス 2
class C3{ public: int D3; };        // 基本クラス 2

class C4 : public C1, public C2, public C3 // 多重継承クラス
{ /*クラスの内容*/ };
クラス C4 には、クラス C1, C2, C3 のメンバがコピーされます。

次のように同じクラスを複数継承することはできません。
class C1{ public: int D1; };        // 基本クラス
class C2 : public C1, public C1 { /**/ }; // 多重継承クラス


しかし次のように、間接的になら、同じクラスを複数継承することができます。
class C1{ public: int D1; };       // 基本クラス
class C2 : public C1 { /**/ };     // 中間の多重継承クラス
class C3 : public C1 { /**/ };     // 中間の多重継承クラス
class C4 : public C2, public C3 { /**/ }; // 多重継承クラス
クラス C4 には、クラス C1 のメンバ D1 が、ふたつコピーされます。
クラスC4 のオブジェクト OB4 を構築した場合に、ふたつの D1 を区別するには次のようにします。
OB4.C2::D1 ...C2 からコピーされた D1
OB4.C3::D1 ...C3 からコピーされた D1

複数段に多重継承する場合に、同じメンバをコピーしないようにするには
基本クラスで、そのクラスの基本クラスを仮想クラスに指定します。
class C1{ public: int D1; };        // 基本クラス 1
class C2{ public: int D2; };        // 基本クラス 2
class C3{ public: int D3; };        // 基本クラス 3

class C4 : public C1, public virtual C2 { /**/ }; // C4 には D1 D2 がコピーされます。
class C5 : virtual public C2, public C3 { /**/ }; // C5 には D2 D3 がコピーされます。
// C4 C5 は、基本クラス C2 を仮想クラスに指定して、
// C4 C5 の派生クラス C6 に、同一メンバ D2 の重複コピーを禁止します。
 
class C6 : public C4, public C5 { /**/ }; // C6 には D1 D2 D3 がコピーされます。
// C6 の基本クラス C4 C5 で、C2 を仮想クラスに指定しているので、C2 の D2 は二重コピーされません。

T 多重継承の用例
#include <iostream.h> /* 多重継承 */
class C1{ public: int D1; };          // 基本クラス 1
class C2{ public: int D2; };          // 基本クラス 2
class C3{ public: int D3; };          // 基本クラス 3

class C4 : public C1, public C2      // 中間の多重継承クラス
{ public: int F; C4(){ D1=401; D2=402; } };

class C5 : public C2, public C3      // 中間の多重継承クラス
{ public: int F; C5(){ D2=502; D3=503; } };

class C6 : public C4, public C5      // 多重継承クラス
{ public: int F;
  C6(){ C5::D2=652; D3=653; }        // C5 からのコピーに代入
};

void main()
{ C6 OB6;
  cout << OB6.D1 << "\t" << OB6.C4::D2 << endl;
  cout << "\t"           << OB6.C5::D2 << "\t" << OB6.D3 << endl;
  int x; cin >> x;
}

T

C++言語 3 オブジェクト 4 フレンド・多重継承 5 演算子のオーバーロード
 
  mtoga@sannet.ne.jp   登録日 '96. 6.15
URL : http://www.page.sannet.ne.jp/mtoga/index.html