FAQ 19.10 What does it mean that friends aren t virtual?

FAQ 19.10 What does it mean that friends aren't virtual?

Friend functions don't bind dynamically. However there is a simple one-line idiom that enables the functionality of a virtual function (that is, dynamic binding) with the syntax of a friend function. This idiom is called the virtual friend function idiom.

The virtual friend function idiom provides the effect of friend functions that bind dynamically; it is used when the syntax of a friend function is desired but the operation must be dynamically bound.

Simply put, use a friend function that calls a protected: virtual member function. For example, suppose class Shape is an abstract base class (ABC), and a Shape is printed via cout << aShape, where aShape is a Shape&, which refers to an object of a derived class, such as Circle. To use the virtual friend function idiom, operator<< would be a friend of Shape and would call a protected: pure virtual member function such as print(ostream&) const.

 #include <iostream> using namespace std; class Shape { public:   virtual ~Shape() throw();   friend ostream& operator<< (ostream& ostr, const Shape& s)                               throw(); protected:   virtual void print(ostream& ostr) const throw() = 0; }; inline ostream& operator<< (ostream& ostr, const Shape& s)                             throw() {   s.print(ostr);                                     <-- 1   return ostr; } Shape::~Shape() throw() { } 

(1) The friend calls a protected: virtual

Because print() is virtual, the right implementation will always be invoked. Because print() is pure virtual, concrete derived classes are required to provide a definition Shape doesn't have enough knowledge about itself to print itself.

 class Circle : public Shape { public:   Circle() throw(); protected:   virtual void print(ostream& ostr) const throw();                                                      <-- 1   float radius_; }; Circle::Circle() throw() : radius_(42) { } void Circle::print(ostream& ostr) const throw() { ostr << "Circle of radius " << radius_; } 

(1) Derived classes override the member, not the friend

Because print() is protected:, users must use the official syntax provided by operator<< (this avoids cluttering the interface with two ways of doing the same thing).

 void userCode(Shape& s) { cout << s << '\n'; }                               <-- 1 int main() {   Circle c;   userCode(c); } 

(1) Users use the friend, not the member

The output is

 Circle of radius 42 

Note that there is only one operator<< for the entire Shape hierarchy. Derived classes provide a definition for print(ostream&) const, but they do not declare or define operator<<.



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net