18.3.3. Class Scope under Multiple Inheritance

Under single inheritance, the scope of a derived class is nested within the scope of its direct and indirect base classes (§ 15.6, p. 617). Lookup happens by searching up the inheritance hierarchy until the given name is found. Names defined in a derived class hide uses of that name inside a base.

Under multiple inheritance, this same lookup happens simultaneously among all the direct base classes. If a name is found through more than one base class, then use of that name is ambiguous.


Exercises Section 18.3.2

Exercise 18.23: Using the hierarchy in exercise 18.22 along with class D defined below, and assuming each class defines a default constructor, which, if any, of the following conversions are not permitted?

class D : public X, public C { ... };
D *pd = new D;

(a) X *px = pd;

(b) A *pa = pd;

(c) B *pb = pd;

(d) C *pc = pd;

Exercise 18.24: On page 807 we presented a series of calls made through a Bear pointer that pointed to a Panda object. Explain each call assuming we used a ZooAnimal pointer pointing to a Panda object instead.

Exercise 18.25: Assume we have two base classes, Base1 and Base2, each of which defines a virtual member named print and a virtual destructor. From these base classes we derive the following classes, each of which redefines the print function:

class D1 : public Base1 { /* ... */ };
class D2 : public Base2 { /* ... */ };
class MI : public D1, public D2 { /* ... */ };

Using the following pointers, determine which function is used in each call:

Base1 *pb1 = new MI;
Base2 *pb2 = new MI;
D1 *pd1 = new MI;
D2 *pd2 = new MI;

(a) pb1->print();

(b) pd1->print();

(c) pd2->print();

(d) delete pb2;

(e) delete pd1;

(f) delete pd2;


In our example, if we use a name through a Panda object, pointer, or reference, both the Endangered and the Bear/ZooAnimal subtrees are examined in parallel. If the name is found in more than one subtree, then the use of the name is ambiguous. It is perfectly legal for a class to inherit multiple members with the same name. However, if we want to use that name, we must specify which version we want to use.


Image Warning

When a class has multiple base classes, it is possible for that derived class to inherit a member with the same name from two or more of its base classes. Unqualified uses of that name are ambiguous.


For example, if both ZooAnimal and Endangered define a member named max_weight, and Panda does not define that member, this call is an error:

double d = ying_yang.max_weight();

The derivation of Panda, which results in Panda having two members named max_weight, is perfectly legal. The derivation generates a potential ambiguity. That ambiguity is avoided if no Panda object ever calls max_weight. The error would also be avoided if each call to max_weight specifically indicated which version to run—ZooAnimal::max_weight or Endangered::max_weight. An error results only if there is an ambiguous attempt to use the member.

The ambiguity of the two inherited max_weight members is reasonably obvious. It might be more surprising to learn that an error would be generated even if the two inherited functions had different parameter lists. Similarly, it would be an error even if the max_weight function were private in one class and public or protected in the other. Finally, if max_weight were defined in Bear and not in ZooAnimal, the call would still be in error.

As always, name lookup happens before type checking (§ 6.4.1, p. 234). When the compiler finds max_weight in two different scopes, it generates an error noting that the call is ambiguous.

The best way to avoid potential ambiguities is to define a version of the function in the derived class that resolves the ambiguity. For example, we should give our Panda class a max_weight function that resolves the ambiguity:

double Panda::max_weight() const
{
    return std::max(ZooAnimal::max_weight(),
                    Endangered::max_weight());
}


Exercises Section 18.3.3

Exercise 18.26: Given the hierarchy in the box on page 810, why is the following call to print an error? Revise MI to allow this call to print to compile and execute correctly.

MI mi;
mi.print(42);

Exercise 18.27: Given the class hierarchy in the box on page 810 and assuming we add a function named foo to MI as follows:

int ival;
double dval;

void MI::foo(double cval)
{
    int dval;
   // exercise questions occur here
}

(a) List all the names visible from within MI::foo.

(b) Are any names visible from more than one base class?

(c) Assign to the local instance of dval the sum of the dval member of Base1 and the dval member of Derived.

(d) Assign the value of the last element in MI::dvec to Base2::fval.

(e) Assign cval from Base1 to the first character in sval from Derived.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.18.218