サーチ…


前書き

うまく設計されたクラスは、その機能をカプセル化し、実装を隠しながら、きれいに文書化されたインターフェイスを提供します。これにより、インタフェースが変更されていない限り、再設計または変更が可能になります。

より複雑なシナリオでは、お互いの実装の詳細に依存する複数のクラスが必要になることがあります。フレンドクラスとファンクションは、ドキュメント化されたインタフェースのカプセル化と情報隠蔽を損なうことなく、これらのピアが互いの詳細にアクセスできるようにします。

フレンド機能

クラスまたは構造体は、それが友人である関数を宣言することができます。関数がクラスのフレンドである場合、関数は保護されているメンバーとプライベートメンバーのすべてにアクセスできます。

// Forward declaration of functions.
void friend_function();
void non_friend_function();

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
private:
    int private_value;
    // Declare one of the function as a friend.
    friend void friend_function();
};

void non_friend_function() {
    PrivateHolder ph(10);
    // Compilation error: private_value is private.
    std::cout << ph.private_value << std::endl;
}

void friend_function() {
    // OK: friends may access private values.
    PrivateHolder ph(10);
    std::cout << ph.private_value << std::endl;
}

アクセス修飾子は、友人セマンティクスを変更しません。友人の公開、保護、私的宣言は同等です。

フレンドの宣言は継承されません。たとえば、私たちがPrivateHolderをサブクラス化しているとしPrivateHolder

class PrivateHolderDerived : public PrivateHolder {
public:
    PrivateHolderDerived(int val) : PrivateHolder(val) {}
private:
    int derived_private_value = 0;
};

メンバーにアクセスしようとすると、次のようになります:

void friend_function() {
    PrivateHolderDerived pd(20);
    // OK.
    std::cout << pd.private_value << std::endl;
    // Compilation error: derived_private_value is private.
    std::cout << pd.derived_private_value << std::endl;
}

PrivateHolderDerivedメンバ関数は、 PrivateHolder::private_valueにアクセスすることはできませんが、friend関数はそれを実行できます。

友人の方法

メソッドは、関数としてだけでなく、関数として宣言することもできます:

class Accesser {
public:
    void private_accesser();
};

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
    friend void Accesser::private_accesser();
private:
    int private_value;
};

void Accesser::private_accesser() {
    PrivateHolder ph(10);
    // OK: this method is declares as friend.
    std::cout << ph.private_value << std::endl;
}

フレンドクラス

クラス全体が友人として宣言されるかもしれません。フレンドクラス宣言は、フレンドの任意のメンバーが宣言クラスのプライベートで保護されたメンバーにアクセスできることを意味します。

class Accesser {
public:
    void private_accesser1();
    void private_accesser2();
};

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
    friend class Accesser;
private:
    int private_value;
};

void Accesser::private_accesser1() {
    PrivateHolder ph(10);
    // OK.
    std::cout << ph.private_value << std::endl;
}

void Accesser::private_accesser2() {
    PrivateHolder ph(10);
    // OK.
    std::cout << ph.private_value + 1 << std::endl;
}

Friendクラス宣言は反射的ではありません。クラスに双方向のプライベートアクセスが必要な場合は、両方ともフレンド宣言が必要です。

class Accesser {
public:
    void private_accesser1();
    void private_accesser2();
private:
    int private_value = 0;
};

class PrivateHolder {
public:
    PrivateHolder(int val) : private_value(val) {}
    // Accesser is a friend of PrivateHolder
    friend class Accesser;
    void reverse_accesse() {
        // but PrivateHolder cannot access Accesser's members.
        Accesser a;
        std::cout << a.private_value;
    }
private:
    int private_value;
};


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow