Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!umich!samsung!sdd.hp.com!decwrl!uunet!brunix!sdm From: sdm@cs.brown.edu (Scott Meyers) Newsgroups: comp.std.c++ Subject: Declarations of Member Functions Outside Class Definitions Message-ID: <46393@brunix.UUCP> Date: 1 Aug 90 20:05:31 GMT Sender: news@brunix.UUCP Reply-To: sdm@cs.brown.edu (Scott Meyers) Organization: Brown University Department of Computer Science Lines: 144 Proposed: That it be possible to declare member functions outside of class declarations exclusively for the purpose of later friend declarations. Example: class Example; // currently legal void Example::f(int); // currently illegal, but would be ok class Sample { friend void Example::f(int); // currently legal, provided class // Example has been defined function() { void (Example::*pmf)(int) = Example::f; // currently illegal and would // remain illegal } }; Motivation: Such a change would make it easier to declare certain friend relationships without having to embed #include directives in the middle of header files. As an example, consider the following classes: - WithFriend, which has a private int member and which declares the constructor for class Derived as a friend. - Base, which has a constructor that takes an int as an argument. - Derived, a derived class of Base, that has a constructor that takes a WithFriend reference as an argument and initializes the Base constructor with the private int member of the referenced WithFriend. This must currently be declared as follows: class Base { protected: Base(int baseArg) {} }; class WithFriend; class Derived: public Base { public: Derived(WithFriend& derivedArg); }; class WithFriend { friend Derived::Derived(WithFriend&); private: int privateMember; }; inline Derived::Derived(WithFriend& derivedArg) : Base(derivedArg.privateMember) {} With the proposed change, it could be declared as follows: class WithFriend; extern Derived::Derived(WithFriend&); // currently illegal class WithFriend { friend Derived::Derived(WithFriend&); private: int privateMember; }; class Base { protected: Base(int baseArg) {} }; class Derived: public Base { public: Derived(WithFriend& derivedArg) : Base(derivedArg.privateMember) {} }; The latter declaration is a little cleaner, in my opinion, because all the forward declarations are at the beginning and there is no need to separate the inline body of the Derived constructor from the class declaration, but that's hardly compelling. The important situation -- and the common one -- is when WithFriend is declared in a different file from Base and Derived, say WithFriend.h and Base.h, respectively. Then the declaration must be as follows: class Base { protected: Base(int baseArg) {} }; class WithFriend; class Derived: public Base { public: Derived(WithFriend& derivedArg); }; #include "WithFriend.h" inline Derived::Derived(WithFriend& derivedArg) : Base(derivedArg.privateMember) {} In this case the #include directive must occur in the middle of the file, contrary to intuition and common convention for #include file usage. With the proposed change, the #include directives need only occur at the top of files: class WithFriend; // file WithFriend.h extern Derived::Derived(WithFriend&); class WithFriend { friend Derived::Derived(WithFriend&); private: int privateMember; }; ------------------------------------------------------------------------- #include "WithFriend.h" // file Base.h class Base { protected: Base(int baseArg) {} }; class Derived: public Base { public: Derived(WithFriend& derivedArg) : Base(derivedArg.privateMember) {} }; Note that allowing member functions to be declared but not used is similar to the standard C++ facility for allowing class names to be declared but no objects of those classes to be used prior to class definition. Scott sdm@cs.brown.edu