Movatterモバイル変換


[0]ホーム

URL:




Chapter 15: Friends

In all examples discussed up to now, we've seen thatprivate members areonly accessible by the members of their class. This isgood, as itenforcesencapsulation anddata hiding. By encapsulating functionalitywithin a class we prevent that a class exposes multiple responsibilities; byhiding data we promote a class'sdata integrity and we prevent that otherparts of the software becomeimplementation dependent on the data thatbelong to a class.

In this (very) short chapter we introduce thefriend keyword and theprinciples that underly its use. The bottom line being that by using thefriend keyword functions are granted access to a class'sprivatemembers. Even so, this does not imply that the principle of data hiding isabandoned when thefriend keyword is used.

In this chapter the topic offriendship among classes is not discussed. Situations in which it isnatural to use friendship among classes are discussed in chapters17 and21 and such situations are naturalextensions of the way friendship is handled for functions.

There should be a well-defined conceptual reason for declaring friendship(i.e., using thefriend keyword). The traditionally offered definition ofthe class concept usually looks something likethis:

A class is a set of data together with the functions that operate on that data.

As we've seen in chapter11 some functions have to be definedoutside of a class interface. They are defined outside of the class interfaceto allow promotions for their operands or to extend the facilities of existingclasses not directly under our control. According to the above traditionaldefinition of the class concept those functions that cannot be defined in theclass interface itself should nevertheless be considered functions belongingto the class. Stated otherwise: if permitted by the language's syntax theywould certainly have been defined inside the class interface. There are twoways to implement such functions. One way consists of implementing thosefunctions using available public member functions. This approach was used,e.g., in section11.2. Another approach applies the definition ofthe class concept to those functions. By stating that those functions in factbelong to the class they should be given direct access to the data members ofobjects. This is accomplished by thefriend keyword.

As a general principle we state that all functionsoperating on the data of objects of a class that are declared in the same fileas the class interface itself belong to that class and may be granted directaccess to the class's data members.

15.1: Friend functions

In section11.2 the insertion operator of the classPerson (cf. section9.3) was implemented like this:
    ostream &operator<<(ostream &out, Person const &person)    {        return            out <<                "Name:    " << person.name() <<  ", "                "Address: " << person.address() <<  ", "                "Phone:   " << person.phone();    }

Person objects can now be inserted into streams.

However, this implementation required three member functions to be called,which may be considered a source of inefficiency. An improvement would bereached by defining a memberPerson::insertInto and letoperator<<call that function. These two functions could be defined as follows:

    std::ostream &operator<<(std::ostream &out, Person const &person)    {        return person.insertInto(out);    }    std::ostream &Person::insertInto(std::ostream &out)    {        return            out << "Name:    " << d_name << ", "                   "Address: " << d_address << ", "                   "Phone:   " << d_phone;    }

AsinsertInto is a member function it has direct access to theobject's data members so no additional member functions must be called wheninsertingperson intoout.

The next step consists of realizing thatinsertInto is only definedfor the benefit ofoperator<<, and thatoperator<<, as it is declaredin the header file containingPerson's class interface should beconsidered a function belonging to the classPerson. The memberinsertInto can therefore be omitted whenoperator<< is declared as afriend.

Friend functions must be declared as friends in the class interface. Thesefriend declarations are notmemberfunctions, and so they are independent of the class'sprivate, protectedandpublic sections. Friend declaration may be placed anywhere in theclass interface. Convention dictates that friend declarations are listeddirectly at the top of the class interface. The classPerson, usingfriend declaration for its extraction and insertion operators starts likethis:

    class Person    {        friend std::ostream &operator<<(std::ostream &out, Person &pd);        friend std::istream &operator>>(std::istream &in, Person &pd);        // previously shown interface (data and functions)    };

The insertion operator may now directly access aPerson object's datamembers:

    std::ostream &operator<<(std::ostream &out, Person const &person)    {        return            cout << "Name:    " << person.d_name << ", "                    "Address: " << person.d_address << ", "                    "Phone:   " << person.d_phone;    }

Friend declarations are true declarations. Once a class contains frienddeclarations these friend functions do not have to be declared again below theclass's interface. This also clearly indicates the class designer's intent:the friend functions are declared by the class, and can thus be consideredfunctions belonging to the class.

15.2: Extended friend declarations

C++ has addedextended frienddeclarations to the language. When a class is declared as a friend, then theclass keyword no longer has to be provided. E.g.,
    class Friend;                   // declare a class    using FriendClass = Friend;           // and maybe a using declaration    class Class1    {        friend FriendClass;              // Friend: also OK    };

In the pre-C++11 standards the friend declaration required an explicitclass; e.g.,friend class Friend.

The explicit use ofclass remains required if the compiler hasn't seenthe friend's name yet. E.g.,

    class Class1    {        // friend Unseen;           // fails to compile: Unseen unknown.        friend class Unseen;        // OK    };

Section22.10 covers the use of extended friend declarations inclass templates.




[8]ページ先頭

©2009-2025 Movatter.jp