FAQ 27.12 What is an alternative to using downcasts?

Move the user code into the object in the form of virtual functions.

An if-downcast pair can often be replaced by a virtual function call. The key insight is to replace the capability query with a service request. A service request is a virtual function that the client can use to politely ask an object to perform some action (such as "Try to liquidate yourself").

To help find the segments of code that will need to be moved into the service requests, look for those segments of code that use capability queries and depend on the type of the class. Segments of code that depend on the type of the class should be moved into the hierarchy as virtual functions; segments of code that don't depend on the type of the class can remain user code or can be nonvirtual member functions in the base class.

In the previous FAQ, the service request in the user code included the entire tryToLiquidate operation (this entire operation depended on the derived class). To apply this guideline, move the code for this operation into the class hierarchy as a virtual function.

 #include <iostream> using namespace std; class Asset { public:   virtual ~Asset() throw();   virtual int tryToLiquidate() throw(); }; Asset::~Asset() throw() { } int Asset::tryToLiquidate() throw() {   cout << "Sorry, couldn't liquidate this asset\n";   return 0; } class LiquidAsset : public Asset { public:   LiquidAsset(int value=100) throw();   virtual int tryToLiquidate() throw(); protected:   int value_;    //value of this asset }; LiquidAsset::LiquidAsset(int value) throw() : value_(value) { } int LiquidAsset::tryToLiquidate() throw() {   int value = value_;   value_ = 0;   cout << "Liquidated $" << value << '\n';   return value; } int sample(Asset& asset) { return asset.tryToLiquidate(); } int main() {   Asset       a;   LiquidAsset b;   sample(a);   sample(b); } 

The output of this program follows.

 Sorry, couldn't liquidate this asset Liquidated $100 

In the previous FAQ, the downcast was explicit and was therefore subject to human error. In the revised solution, the conversion from Asset* to LiquidAsset* is implicitly part of the virtual function call mechanism. LiquidAsset::tryToLiquidate() does not need to downcast the this pointer into a LiquidAsset*.

Think of a virtual function call as an extensible if-downcast pair that always down casts to the right type.



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