Topic: Overloading of inherited operations?


Author: dharley@aztec.co.za (David Harley)
Date: 1995/11/14
Raw View
Steve Clamage (clamage@Eng.Sun.COM) wrote:

: In article 021F9BA0@slip6-2.acs.ohio-state.edu, Sergey Zhupanov <sergey@cis.ohio-state.edu> writes:
: >Folks,
: >
: >Can derived functions overload each other instead of hiding
: >or (worse yet) producing ambiguity?

[ eg. foo(char) hides foo(int) in a superclass ]
[ Steve responds ... ]

: A using-directive will solve your problem without generating any extra code.

: class B1 { public: int foo(int); };
: class B2 { public: int foo(char); };
: class D : public B1, public B2 {
: public:
:  using B1::foo; // "using" applies to a name, not to a signature
:  using B2::foo;
:  double foo(double); // new overload
: };

[ snip ]

I have never understood why an overloaded member of a subclass hides a
superclass's member. It seems to be illogical and contradicts the
behaviour of non-class members. (It is also very irritating.)

What is 'using'? It does not seem to be standard.


---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1995/11/14
Raw View
In article 779@aztec.co.za, dharley@aztec.co.za (David Harley) writes:
>
>Steve Clamage (clamage@Eng.Sun.COM) wrote:
>
>: A using-directive will solve your problem without generating any extra code.
>
>: class B1 { public: int foo(int); };
>: class B2 { public: int foo(char); };
>: class D : public B1, public B2 {
>: public:
>:  using B1::foo; // "using" applies to a name, not to a signature
>:  using B2::foo;
>:  double foo(double); // new overload
>: };
>
>[ snip ]
>
>I have never understood why an overloaded member of a subclass hides a
>superclass's member. It seems to be illogical and contradicts the
>behaviour of non-class members. (It is also very irritating.)

The fundamental rule of scopes is that a name declared in a scope hides
all instances of that name in all outer scopes. Therefore, overloading
cannot occur across scopes. Base class scope is a different scope from
derived class scope, and encloses the derived class scope.

If overloading could occur across scopes, you would need a lot of special
rules. Example:

 class A { ... int f(int); };
 class B : public A { ... char* f; };
 class C : public B { ... double f(double); };

 A a;
 B b;
 C c;

 a.f(1)  // OK, call A::f(int)
 b.f[0]  // OK, access B::f
 b.f(1)  // If OK, why? If not, why not?
 c.f(1.0) // OK, call C::f(double)
 c.f[0]  // If OK, why? If not, why not?
 c.f(1)  // call C::f(double) or A::f(int), and why?

This simple example would require special-case rules if we don't keep the
existing fundamental rule of scopes.

>What is 'using'? It does not seem to be standard.

It was added to the C++ draft standard 2 or 3 years ago. You can read about
it in the discussion of namespaces in "The Design and Evolution of C++" or
in the public-review copy of the draft standard which was posted on
several public FTP sites last May.

---
Steve Clamage, stephen.clamage@eng.sun.com



---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: Sergey Zhupanov <sergey@cis.ohio-state.edu>
Date: 1995/11/13
Raw View
Folks,

Can derived functions overload each other instead of hiding
or (worse yet) producing ambiguity?  Trivial examples are:

Example 1:
---------

class A { public: void foo (int i); };
class B : public A { public: void foo (char c); };

Instead of overloading A::foo, B::foo hides it!

Example 2:
---------

class A { public: void foo (int i); }
class B { public: void foo (char c); }
class C : public A, public B {};

C exports both A::foo and B::foo but in a way that required fully-qualified
naming (e.g. c.A::foo(3)) to resolve ambiguity.  Worse yet, one of the
inheritance links could even be private with same effect...

This is the way the language is defined to behave.  Unfortunately, this
single "feature" prevents many interesting idioms from working.  (I can
elaborate
if any one is interested.)

Commonly proposed solutions are:
-------------------------------

(1) re-defining the operation and using call-through (e.g. in example 1, B
would also define void foo (int i) that would call through to A::foo)

(2) Using fully qualified names (only helps in ambiguity with MI case)

However, for the situations I mentioned, these solutions are unacceptable.

My question is:
--------------

Does any one know of a way to make the above code (modified in some way)
behave in the way intended, as opposed to "the C++ way?"

Thanks very much in advance for your comments.

sergey
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/11/13
Raw View

Sergey Zhupanov <sergey@cis.ohio-state.edu> writes:

>Can derived functions overload each other instead of hiding
>or (worse yet) producing ambiguity?  Trivial examples are:
>
>Example 1:
>---------
>
>class A { public: void foo (int i); };
>class B : public A { public: void foo (char c); };
>
>Instead of overloading A::foo, B::foo hides it!

You can solve this problem with a `using' declaration.

 class B : public A { public: using A::foo; void foo (char c); };
                              ^^^^^^^^^^^^^

Now the two definitions of `foo' will be overloaded.
See section 7.3.3 [namespace.udecl] of the draft standard,
which includes an example that is almost identical to the above.

>Example 2:
>---------
>
>class A { public: void foo (int i); }
>class B { public: void foo (char c); }
>class C : public A, public B {};

Again, you can use `using' declarations to solve the problem:

 class C : public A, public B {
 public:
  using A::foo;
  using B::foo;
 };

Of course, whether or not the compiler you are currently using
supports `using' declarations yet is another question... they
are a relatively new feature (introduced along with namespaces)
and many compilers don't yet support them.

--
Fergus Henderson              WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au               PGP: finger fjh@128.250.37.3

---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1995/11/13
Raw View
In article 021F9BA0@slip6-2.acs.ohio-state.edu, Sergey Zhupanov <sergey@cis.ohio-state.edu> writes:
>Folks,
>
>Can derived functions overload each other instead of hiding
>or (worse yet) producing ambiguity?

[ examples of functions in different classes in the hierarchy causing
  ambiguity instead of overloading ]

>This is the way the language is defined to behave.  Unfortunately, this
>single "feature" prevents many interesting idioms from working.  (I can
>elaborate if any one is interested.)
>
> ...
>
>Does any one know of a way to make the above code (modified in some way)
>behave in the way intended, as opposed to "the C++ way?"

A using-directive will solve your problem without generating any extra code.

class B1 { public: int foo(int); };
class B2 { public: int foo(char); };
class D : public B1, public B2 {
public:
 using B1::foo; // "using" applies to a name, not to a signature
 using B2::foo;
 double foo(double); // new overload
};

Now all the overloaded "foo" functions in B1 and B2 are added to D's
scope, meaning they overload one another when called from a D object.

 D d;
 d.foo(1);   // calls B1::foo(int)
 d.foo('a'); // calls B2::foo(char)
 d.foo(1.0); // calls D::foo(double)

Notice how this differs from putting a forwarding function in D. There is no
overhead of any kind with a using-declaration.
---
Steve Clamage, stephen.clamage@eng.sun.com



---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]