In some cases, we want to prevent dynamic binding of a call to a virtual function; we want to force the call to use a particular version of that virtual. We can use the scope operator to do so. For example, this code:
// calls the version from the base class regardless of the dynamic type of baseP
double undiscounted = baseP->Quote::net_price(42);
calls the Quote
version of net_price
regardless of the type of the object to which baseP
actually points. This call will be resolved at compile time.
Ordinarily, only code inside member functions (or friends) should need to use the scope operator to circumvent the virtual mechanism.
Why might we wish to circumvent the virtual mechanism? The most common reason is when a derived-class virtual function calls the version from the base class. In such cases, the base-class version might do work common to all types in the hierarchy. The versions defined in the derived classes would do whatever additional work is particular to their own type.
If a derived virtual function that intended to call its base-class version omits the scope operator, the call will be resolved at run time as a call to the derived version itself, resulting in an infinite recursion.
Exercise 15.11: Add a virtual debug
function to your Quote
class hierarchy that displays the data members of the respective classes.
Exercise 15.12: Is it ever useful to declare a member function as both override
and final
? Why or why not?
Exercise 15.13: Given the following classes, explain each print
function:
class base {
public:
string name() { return basename; }
virtual void print(ostream &os) { os << basename; }
private:
string basename;
};
class derived : public base {
public:
void print(ostream &os) { print(os); os << " " << i; }
private:
int i;
};
If there is a problem in this code, how would you fix it?
Exercise 15.14: Given the classes from the previous exercise and the following objects, determine which function is called at run time:
base bobj; base *bp1 = &bobj; base &br1 = bobj;
derived dobj; base *bp2 = &dobj; base &br2 = dobj;
(a) bobj.print();
(b) dobj.print();
(c) bp1->name();
(d) bp2->name();
(e) br1.print();
(f) br2.print();