From: steve@taumet.com (Steve Clamage)
Subject: Re: Who is wrong? me, BC , G
Organization: TauMetric Corporation
Date: Sun, 13 Dec 1992 16:57:26 GMT

chris.sokol@factory.com (Chris Sokol)  writes:

|48ganelin@cua.edu writes:

|>class A
|>{
|>public:
|>  A & operator += ( const A & x ) ;
|>};

|>class B : public A
|>{
|>public:
|>  B & operator += ( const int x ) ;
|>};

|>void main ()
|>{
|> B  x , y ;
|> x += y ;            //  BorlandC complains here !!!!
|>}

|>WHY !!!!!

|If you wish to use a method of class B which has been derived from class A by
|name, several dos compilers (BC/Zortech) complain if the overloading function
|does not take the same number/type of parameters.

This is not the explanation.  We are not looking at compiler dependencies,
but at a fundamental language rule.  If g++ compiles this code, it is
wrong.  Perhaps a later version would report the error.

Let's consider the basic scoping rule in C, C++, and many other languages:

An identifier in a scope hides all instances of that identifier in all
outer scopes.  For example:

	void f();
	int g()
	{
	    int f = 1;
	    f();	// illegal, 'f()' is hidden
	    {
		double f = 2.0;
		if( ... )
		    return f;	// returns (int)2.0, since 'int f' is hidden
	    }
	    return f;		// returns 1
	}

Overloading in C++ applies only within the same scope because of this 
fundamental rule.  Example:

	void f(int);
	void g()
	{
	    void f(double);	//hides 'f(int)'
	    f(1);		// calls f((double)1), the only visible f()
	}

This, by the way, is why you don't want to declare functions anywhere
but file (or class) scope.

A derived class does not have the same scope as a base class, so no
function in a derived class can overload any function in a base class.
This is true for virtual functions as well, a point that is sometimes
missed.  "Virtual" is a concept independent of "overloading" and
only loosely tied to scope.

In the specific example, function B::operator+=() hides A::operator+=().
There is no visible += which can be applied to 2 objects of type B, and
the code is in error.  There are basically three ways to proceed:

1.  (not recommended) Use scope overriding to call the base-class function:
	x.A::operator+=(y)
    The compiler will quietly cast the B objects and apply the operator
    to their A portions.

2.  (not recommended) Cast the objects yourself:
	(A&)x += (A&)y	// exactly the same effect as #1

3.  (recommended) Supply the appropriate operator in class B:
	inline B& B::operator+=(const B& b) {
	    ((A*)this)->operator+=(b);
	    return *this;
	    }
    This will ensure the proper overloading in class B.  It will also
    ensure the right operations if B should change so that += has more
    to do.  For example, if a data member is added to B, one would expect
    it to take part in assignment.  You would add an operator+=() then,
    but the existing code in examples 1 and 2 would still call the
    base-class version, a subtle bug.  If you define your own
    operator+= now, only it need change when the class changes.

    You might want to supply
	inline B& B::operator+=(const A& a)
	    ((A*)this)->operator+=(a);
	    return *this;
	    }
    instead, or in addition, depending on the nature of the classes.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com