When should you use 'friend' in C++?

前端 未结 30 1534
孤街浪徒
孤街浪徒 2020-11-22 10:12

I have been reading through the C++ FAQ and was curious about the friend declaration. I personally have never used it, however I am interested in exploring the language.

相关标签:
30条回答
  • 2020-11-22 10:43

    To do TDD many times I've used 'friend' keyword in C++.

    Can a friend know everything about me?


    Updated: I found this valuable answer about "friend" keyword from Bjarne Stroustrup site.

    "Friend" is an explicit mechanism for granting access, just like membership.

    0 讨论(0)
  • 2020-11-22 10:45

    At work we use friends for testing code, extensively. It means we can provide proper encapsulation and information hiding for the main application code. But also we can have separate test code that uses friends to inspect internal state and data for testing.

    Suffice to say I wouldn't use the friend keyword as an essential component of your design.

    0 讨论(0)
  • 2020-11-22 10:45

    This may not be an actual use case situation but may help to illustrate the use of friend between classes.

    The ClubHouse

    class ClubHouse {
    public:
        friend class VIPMember; // VIP Members Have Full Access To Class
    private:
        unsigned nonMembers_;
        unsigned paidMembers_;
        unsigned vipMembers;
    
        std::vector<Member> members_;
    public:
        ClubHouse() : nonMembers_(0), paidMembers_(0), vipMembers(0) {}
    
        addMember( const Member& member ) { // ...code }   
        void updateMembership( unsigned memberID, Member::MembershipType type ) { // ...code }
        Amenity getAmenity( unsigned memberID ) { // ...code }
    
    protected:
        void joinVIPEvent( unsigned memberID ) { // ...code }
    
    }; // ClubHouse
    

    The Members Class's

    class Member {
    public:
        enum MemberShipType {
            NON_MEMBER_PAID_EVENT,   // Single Event Paid (At Door)
            PAID_MEMBERSHIP,         // Monthly - Yearly Subscription
            VIP_MEMBERSHIP,          // Highest Possible Membership
        }; // MemberShipType
    
    protected:
        MemberShipType type_;
        unsigned id_;
        Amenity amenity_;
    public:
        Member( unsigned id, MemberShipType type ) : id_(id), type_(type) {}
        virtual ~Member(){}
        unsigned getId() const { return id_; }
        MemberShipType getType() const { return type_; }
        virtual void getAmenityFromClubHouse() = 0       
    };
    
    class NonMember : public Member {
    public:
       explicit NonMember( unsigned id ) : Member( id, MemberShipType::NON_MEMBER_PAID_EVENT ) {}   
    
       void getAmenityFromClubHouse() override {
           Amenity = ClubHouse::getAmenity( this->id_ );
        }
    };
    
    class PaidMember : public Member {
    public:
        explicit PaidMember( unsigned id ) : Member( id, MemberShipType::PAID_MEMBERSHIP ) {}
    
        void getAmenityFromClubHouse() override {
           Amenity = ClubHouse::getAmenity( this->id_ );
        }
    };
    
    class VIPMember : public Member {
    public:
        friend class ClubHouse;
    public:
        explicit VIPMember( unsigned id ) : Member( id, MemberShipType::VIP_MEMBERSHIP ) {}
    
        void getAmenityFromClubHouse() override {
           Amenity = ClubHouse::getAmenity( this->id_ );
        }
    
        void attendVIPEvent() {
            ClubHouse::joinVIPEvent( this->id );
        }
    };
    

    Amenities

    class Amenity{};
    

    If you look at the relationship of these classes here; the ClubHouse holds a variety of different types of memberships and membership access. The Members are all derived from a super or base class since they all share an ID and an enumerated type that are common and outside classes can access their IDs and Types through access functions that are found in the base class.

    However through this kind of hierarchy of the Members and its Derived classes and their relationship with the ClubHouse class the only one of the derived class's that has "special privileges" is the VIPMember class. The base class and the other 2 derived classes can not access the ClubHouse's joinVIPEvent() method, yet the VIP Member class has that privilege as if it has complete access to that event.

    So with the VIPMember and the ClubHouse it is a two way street of access where the other Member Classes are limited.

    0 讨论(0)
  • 2020-11-22 10:45

    You could adhere to the strictest and purest OOP principles and ensure that no data members for any class even have accessors so that all objects must be the only ones that can know about their data with the only way to act on them is through indirect messages, i.e., methods.

    But even C# has an internal visibility keyword and Java has its default package level accessibility for some things. C++ comes actually closer to the OOP ideal by minimizinbg the compromise of visibility into a class by specifying exactly which other class and only other classes could see into it.

    I don't really use C++ but if C# had friends I would that instead of the assembly-global internal modifier, which I actually use a lot. It doesn't really break incapsulation, because the unit of deployment in .NET is an assembly.

    But then there's the InternalsVisibleToAttribute(otherAssembly) which acts like a cross-assembly friend mechanism. Microsoft uses this for visual designer assemblies.

    0 讨论(0)
  • 2020-11-22 10:47

    The short answer would be: use friend when it actually improves encapsulation. Improving readability and usability (operators << and >> are the canonical example) is also a good reason.

    As for examples of improving encapsulation, classes specifically designed to work with the internals of other classes (test classes come to mind) are good candidates.

    0 讨论(0)
  • 2020-11-22 10:47

    Probably I missed something from the answers above but another important concept in encapsulation is hiding of implementation. Reducing access to private data members (the implementation details of a class) allows much easier modification of the code later. If a friend directly accesses the private data, any changes to the implementation data fields (private data), break the code accessing that data. Using access methods mostly eliminates this. Fairly important I would think.

    0 讨论(0)
提交回复
热议问题