📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の3版が非表示)
86行目: 86行目:
上記の用途以外でのフレンド関数の使用は原則として避けて、他の設計を検討した方がよい。<br>
上記の用途以外でのフレンド関数の使用は原則として避けて、他の設計を検討した方がよい。<br>
<br><br>
<br><br>
== フレンドクラス ==
<code>friend</code>指定子はクラスに対しても使用でき、指定されたクラスをフレンドクラスと呼ぶ。<br>
メンバ関数をフレンド関数にする場合と異なり、<code>private</code>メンバ関数もフレンドになる。<br>
<br>
フレンドクラスは、フレンド関数よりも許可を与える範囲が広いため、必要な場合に限り、フレンドクラスを使用するように検討する方がよい。<br>
<br>
フレンドクラスを指定する場合は、<code>friend class <クラス名>;</code>のように<code>class</code>キーワードを付加する。<br>
構造体の場合は、<code>friend struct <構造体名>;</code>を付加する。<br>
<br>
フレンドクラスを使用する場合、クラスや構造体であることが明示できるため、その定義が見えていなくても問題ない。<br>
<br>
また、フレンドクラスを指定する時、<code>class</code>や<code>struct</code>は省略できるため、<code>friend <クラス名または構造体名>;</code>と記述できる。<br>
この場合、クラスの定義が明示されていないため、エラーになる。<br>
<syntaxhighlight lang="c++">
class CSampleClass1
{
    friend class CSampleClass2;  // CSampleClass2の定義が見えていないが、classキーワードがあればOK
    friend CSampleClass2;        // CSampleClass2の定義が見えていないのでエラー (ただし、クラスの前方宣言があればOK)
};
class CSampleClass2
{
    // ...略
};
</syntaxhighlight>
<br>
テンプレートクラスもフレンドクラスとして指定することができる。<br>
<br>
また、テンプレート仮引数の名前は省略することができる。<br>
この場合、<code>class</code>キーワードを省略できないことに注意する。<br>
これは、テンプレートクラス自体はクラスではないため、テンプレートクラスの定義が<code>friend</code>指定子よりも前方に記述されているからといって、<br>
テンプレートクラスが見えていることにはならないからである。<br>
<syntaxhighlight lang="c++">
template <typename T>
class CSampleClass2
{
    // ...略
};
class CSampleClass1
{
    template <typename>
    friend class CSampleClass2;
};
</syntaxhighlight>
<br><br>
== 前方宣言 ==
フレンドクラスを使用する場合、2つのクラスが互いの定義を求めることにより、どちらの定義を前方に記述してもコンパイルエラーが起きる。<br>
この時、クラス名のみを宣言することことにより、解決できる。<br>
<br>
以下の例では、<code>class <クラス名2>;</code>のことをクラスの前方宣言と呼ぶ。<br>
構造体の場合は、<code>struct <構造体名>;</code>と記述する。<br>
<syntaxhighlight lang="c++">
class <クラス名2>;
class <クラス名1>
{
    friend <クラス名2>;
};
</syntaxhighlight>
<br>
前方宣言により解決できるものは、<code>friend</code>指定子に指定するための名前が必要である場合、または、クラス型のポインタや参照が必要な場合に限られる。<br>
例えば、クラス型の実体を必要とする場合には、前方宣言では解決できない。(クラスの大きさが必要な場合は、前方宣言では対応できず、定義が必要)<br>
<syntaxhighlight lang="c++">
// クラスの前方宣言で解決できない場合
class <クラス名2>;
class <クラス名1>
{
    <クラス名2> m_cls2;  // エラー (実体が必要な場合は、<クラス名2>の定義が必要)
};
</syntaxhighlight>
<br>
ポインタや参照は、コンパイラにはクラスの大きさが理解できるため、定義は不要である。<br>
<syntaxhighlight lang="c++">
// クラスの前方宣言で解決できる場合
class <クラス名2>;
class <クラス名1>
{
    <クラス名2> *m_pcls2;  // OK (ポインタや参照の場合は、<クラス名2>の定義は不要)
    <クラス名2> &m_rcls2;  // OK (ポインタや参照の場合は、<クラス名2>の定義は不要)
};
</syntaxhighlight>
<br>
<u>クラスのメンバへアクセスする必要がある場合は、クラスの定義が必要である。</u><br>
<br>
ただし、実体の場合でも、引数や戻り値に使用するのみであれば、前方宣言で解決できる。<br>
<syntaxhighlight lang="c++">
class <クラス名2>;
class <クラス名1>
{
public:
    void Set(<クラス名2> cls2);
    <クラス名2> Get() const;
};
</syntaxhighlight>
<br>
以下の例において、Set関数やGet関数の宣言を行うのみの場合、クラスの大きさは不要である。
クラスの大きさが必要なのはこれらのメンバ関数を呼び出している側であるため、呼び出し側には<code>#include <クラス名2の定義があるヘッダファイル></code>の記述が必要となる。<br>
<br>
また、Set関数やGet関数をインライン関数にする場合、<クラス名2>の定義が必要になる。<br>
つまり、他のクラスを使用するようなインライン関数を記述する場合、クラスの前方宣言では解決できない。<br>
<br>
インクルードするヘッダファイルが増加する場合は依存するソースコードの量も増加するため、コンパイルに時間が掛かる。<br>
そこで、クラスの前方宣言を活用することにより、インクルードするヘッダファイルの量を減少させて、コンパイルに掛かる時間を削減することができる。<br>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:C++]]
[[カテゴリ:C++]]