Wes Groleau wrote:
[ ... ]
Class Wagon has method Draw.
Class Picture has method Draw.
If you multiply inherit to make
Class Picture_Of_A_Wagon, what does the method Draw do?
In C++ the result would be simple: attempting to call Draw without
qualification would cause an error due to ambiguity. Note that the mere
existence of the situation doesn't lead to an ambiguity or a compiler
error -- only when/if you attempt to use the name without qualification
does the error arise.
This ambiguity would typically be resolved by qualifying the name (i.e.
explicitly calling Wagon:
raw() or Picture:
raw()). If you think it
makes sense for the derived class to normally call one instead of the
other, a using declaration or a forwarding function can provide that.
For example, if we wanted the derived Draw to resolve to Picture:
raw,
here's how it looks with a using declaration:
#include <iostream>
struct Picture {
virtual void Draw() {
std::cout << "Drawing Picture";
}
};
struct Wagon {
virtual void Draw() {
std::cout << "Drawing Wagon";
}
};
struct Picture_Of_A_Wagon : Wagon, Picture {
using Picture:
raw;
};
For explicit forwarding you'd do this instead:
struct Picture_Of_A_Wagon : Wagon, Picture {
void Draw() { Picture:
raw(); }
};
Of course, in well-written code, you just wouldn't do anything like
this at all -- a picture of a wagon is NOT a wagon, and does not
satisfy the Liskov Substitution Principle, so having Picture_Of_A_Wagon
derive (publicly) from Wagon is just plain wrong.
For better or worse, however, compilers (at least for C++) aren't quite
smart enough to recognize such problems yet, so it would be up to a
person to point out that the code above is broken beyond repair.
Multiple inheritance can make sense, but should be restricted to
situations where a derived object really can be substituted for either
(or any) of the base types. Examples would be having an object with a
particular function made from a particular material:
class piece_of_aluminium {
int alloy;
std::string heat_treatment;
std::string hardness;
int density;
};
class pipe{
int diameter;
int wall_thickness;
int length;
};
class aluminium_pipe : public piece_of_aluminium, public pipe {
};
Now we have a perfectly reasonable situation: an aluminium pipe that
can be treated as either a piece of aluminium or as a pipe.
Unfortunately, right now I can't think of a name that would really make
good sense in both base classes, so we don't have a potential
ambiguity.