pdevries@watserv1.waterloo.edu (Peter DeVries) (07/23/90)
example: Class A: { virtual void SetSomething(int,double); virtual void SetSomething(int,long); }; Class B: public A { void SetSomething(int,double); }; main() { B b; long l; int i; b.SetSomething(i,l); //CALLS B.SetSomething(int,double) } I REALLY don't understand this. Walter replied to this problem that it is NOT a compiler bug. That declaring SetSomething(int,double) in the derived class hides ALL inherited declarations of SetSomething, INCLUDING overloaded ones. SAY WHAT? This goes against any common sense that I may have. Why would overloaded functions work so differently than the intuitive approach. (ie. as inheritance usually works). The function name is completely different since the parameters are of different types, so why would one function in the derived class have any affect on accessing the other ones? By the way, it will call B.SetSomething(int,double) even if I explicitly cast the value to a LONG. Peter DeVries Mutual Life of Canada c/o pdevries@watserv1.waterloo.edu (519) 888-3523, (416) 972-0594 -- Peter DeVries Mutual Life of Canada c/o pdevries@watserv1.waterloo.edu (519) 888-3523, (416) 972-0594
sdm@cs.brown.edu (Scott Meyers) (07/24/90)
In article <1990Jul23.161817.23460@watserv1.waterloo.edu> pdevries@watserv1.waterloo.edu (Peter DeVries) writes: | I REALLY don't understand this. Walter replied to this problem that it is | NOT a compiler bug. That declaring SetSomething(int,double) in the derived | class hides ALL inherited declarations of SetSomething, INCLUDING overloaded | ones. | | SAY WHAT? This goes against any common sense that I may have. Why would | overloaded functions work so differently than the intuitive approach. (ie. | as inheritance usually works). The function name is completely different since | the parameters are of different types, so why would one function in the derived | class have any affect on accessing the other ones? | | By the way, it will call B.SetSomething(int,double) even if I explicitly cast | the value to a LONG. This is the way the language is defined to work. It's counterintuitive, yes, but it was defined to work this way to keep you from accidently inheriting functions from libraries with signatures that would cause the "wrong" (from your point of view) function to be called. The same rationale results in the fact that access restrictions are not taken into account when disambiguating calls to multiply inherited function names, an oddity that is arguably even more unintuitive. If this goes against any "common sense" you may have, think about it again in the context of software engineering and you may find that your common sense changes. Scott
wmmiller@cup.portal.com (William Michael Miller) (07/25/90)
pdevries@watserv1.waterloo.edu (Peter DeVries) writes: > I REALLY don't understand this. Walter replied to this problem that it is > NOT a compiler bug. That declaring SetSomething(int,double) in the derived > class hides ALL inherited declarations of SetSomething, INCLUDING overloaded > ones. > > SAY WHAT? This goes against any common sense that I may have. This should go into the "frequently asked questions" file, if it has not already. This is discussed in more detail in E&S section 13.1, especially page 311, but the short answer is that a derived class is a separate scope from the base class, and you only look in the base class for a match if you can't find one in the derived class. There's good justification for this rule. Consider the following case: struct B { foo(char*); }; struct D: B { foo(short); }; D d; d.foo(1); This resolves to D::foo(short). Now you get a new release of the library that defines B and somebody has had the bright idea of adding B::foo(int). Under the "intuitive approach" you mentioned, your code stops working because d.foo(1) now resolves to B::foo(int), not to your D::foo(short). Under the current definition, your program continues to work because any D::foo() hides all the B::foo()s, regardless of argument type. If you want to make a B::foo() available to consumers of D, it's very easy: struct D: B { foo(char* cp) { return B::foo(cp); } }; It doesn't even add any execution overhead. I think the potential nasty surprise factor of the "intuitive approach" completely outweighs the minor inconvenience of requiring forwarding functions. ------------------------------------------------------------------------------ William M. Miller, Glockenspiel, Inc.; P. O. Box 366, Sudbury, MA 01776-0003 wmmiller@cup.portal.com BIX: wmiller CI$: 72105,1744