DiscussionBoth public member functions and nonmember functions form part of the public interface of a class. The Interface Principle states: For a class X, all functions (including nonmember functions) that both "mention" X and are "supplied with" X in the same namespace are logically part of X, because they form part of X's interface. (See Item 44 and [Sutter00].) The C++ language is explicitly designed to enforce the Interface Principle. The reason why argument-dependent lookup (ADL, also known as Koenig lookup) was added to the language was to ensure that code that uses an object x of type X can use its nonmember function interface (e.g., cout << x, which invokes the nonmember operator<< for X) as easily as it can use member functions (e.g., x.f(), which requires no special lookup because f is clearly to be looked up in the scope of X). ADL ensures that nonmember functions that take X objects and that are supplied with X's definition can participate as first-class members of X's interface, just like X's direct member functions naturally do. In particular, the primary motivating example for ADL was the case where X is std::string (see [Sutter00]). Consider a class X, defined in namespace N: class X { public: void f(); }; X operator+( const X&, const X& ); Callers will typically want to write code like this, where x1, x2 , and x3 are objects of type X: x3 = x1 + x2; If the operator+ is declared in the same namespace as X, there's no problem, and such code always just works, because the supplied operator+ will be looked up using ADL. If the operator+ is not declared in the same namespace as X, the caller's code fails to work. The caller has two workarounds to make it work. The first is to use explicit qualification: x3 = N::operator+( x1, x2 ); This is deplorable and shameful because it requires the user to give up natural operator syntax, which is the point of operator overloading in the first place. The only other option is to write a using statement:
using N::operator+;
// or: using namespace N;
x3 = x1 + x2;
Writing either of the indicated using statements is perfectly acceptable (see Item 59), but the caller doesn't have to jump through these hoops when the author of X does the right thing and puts operator+ for X objects into the same namespace as X. For the flip side of this issue, see Item 58). |