Online Book Reader

Home Category

Professional C__ - Marc Gregoire [115]

By Root 1312 0
cast or assignment is performed on a plain old object, this results in slicing:

Super mySuper = mySub; // SLICE!

Slicing occurs in situations like this because the end result is a Super object, and Super objects lack the additional functionality defined in the Sub class. However, slicing does not occur if a subclass is assigned to a pointer or reference to its superclass:

Super& mySuper = mySub; // No slice!

This is generally the correct way to refer to a subclass in terms of its superclass, also called upcasting. This is why it’s always a good idea to make your methods and functions take references to classes instead of directly using objects of those classes. By using references, subclasses can be passed in without slicing.

When upcasting, use a pointer or reference to the superclass to avoid slicing.

Casting from a superclass to one of its subclasses, also called downcasting, is often frowned upon by professional C++ programmers because there is no guarantee that the object really belongs to that subclass. For example, consider the following code:

void presumptuous(Super* inSuper)

{

Sub* mySub = static_cast(inSuper);

// Proceed to access Sub methods on mySub.

}

If the author of presumptuous() also wrote code that called presumptuous(), everything would probably be okay because the author knows that the function expects the argument to be of type Sub*. However, if other programmers were to call presumptuous(), they might pass in a Super*. There are no compile-time checks that can be done to enforce the type of the argument, and the function blindly assumes that inSuper is actually a pointer to a Sub.

Downcasting is sometimes necessary, and you can use it effectively in controlled circumstances. If you’re going to downcast, however, you should use a dynamic_cast, which uses the object’s built-in knowledge of its type to refuse a cast that doesn’t make sense. If a dynamic_cast fails on a pointer, the pointer’s value will be nullptr instead of pointing to nonsensical data. If a dynamic_cast fails on an object reference, a std::bad_cast exception will be thrown. Chapter 9 discusses casting in more detail and Chapter 10 explains more about exceptions.

The previous example should have been written as follows:

void lessPresumptuous(Super* inSuper)

{

Sub* mySub = dynamic_cast(inSuper);

if (mySub != nullptr) {

// Proceed to access Sub methods on mySub.

}

}

Use downcasting only when necessary and be sure to use a dynamic_cast.

INHERITANCE FOR POLYMORPHISM


Now that you understand the relationship between a subclass and its parent, you can use inheritance in its most powerful scenario — polymorphism. Chapter 3 discusses how polymorphism allows you to use objects with a common parent class interchangeably, and to use objects in place of their parents.

Return of the Spreadsheet

Chapters 6 and 7 use a spreadsheet program as an example of an application that lends itself to an object-oriented design. A SpreadsheetCell represents a single element of data. That element could be either a double or a string. A simplified class definition for SpreadsheetCell follows. Note that a cell can be set either as a double or a string. The current value of the cell, however, is always returned as a string for this example.

class SpreadsheetCell

{

public:

SpreadsheetCell();

virtual void set(double inDouble);

virtual void set(const std::string& inString);

virtual std::string getString() const;

protected:

static std::string doubleToString(double inValue);

static double stringToDouble(const std::string& inString);

double mValue;

std::string mString;

};

The preceding SpreadsheetCell class seems to be having an identity crisis — sometimes a cell represents a double, sometimes a string. Sometimes it has to convert between these formats. To achieve this duality, the class needs to store both values even though a given cell should be able to contain only a single value. Worse still, what if additional types of cells are needed, such as a formula cell or a date cell? The SpreadsheetCell class would

Return Main Page Previous Page Next Page

®Online Book Reader