[comp.lang.c++] More ZOrtech c++

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