Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Please explain: function overloading with virtual functions.

139 views
Skip to first unread message

Michael Hallman Morrissey

unread,
Dec 18, 1997, 3:00:00 AM12/18/97
to

I'm having trouble understanding what happens when you try to
overlay a function which is already overloaded. Consider the
following bit of code:

class Base
{
public:
int foo() {return 3;};
virtual int foo(int x) {reutrn x*x;};
};

class Derived : public Base
{
public:
int foo(int x) {return x*x*x;};
}

main()
{
Derived d;

cout << "Value of Base::foo() is " << d.foo() << endl;

}

When I try to compile this, the compiler thinks that d.foo() is
trying to call Derived::foo(int) rather than Base::foo(void), and so
I get that I'm trying to call foo(int) with too few arguments. Lame!

I can call the correct function by doing: ((Base&)d).foo(); but this
is beat. I'm not clear on *why* this happens, though. I can't find
anything in the C++ Reference Manual about this topic; I'm guessing
that it might not be part of the language but has to do with compiler
implementation issues.

Can anyone shed any light on this? Thanks!!

Michael Morrissey
mmorr...@mindspring.com

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

kjh...@mmm.com

unread,
Dec 19, 1997, 3:00:00 AM12/19/97
to

Michael Hallman Morrissey wrote:
>
> I'm having trouble understanding what happens when you try to
> overlay a function which is already overloaded. Consider the
> following bit of code:
>
> class Base
> {
> public:
> int foo() {return 3;};
> virtual int foo(int x) {reutrn x*x;};
> };
>
> class Derived : public Base
> {
> public:
> int foo(int x) {return x*x*x;};
> }
>
> main()
> {
> Derived d;
>
> cout << "Value of Base::foo() is " << d.foo() << endl;
>
> }
>
> When I try to compile this, the compiler thinks that d.foo() is
> trying to call Derived::foo(int) rather than Base::foo(void), and so
> I get that I'm trying to call foo(int) with too few arguments. Lame!
>
> I can call the correct function by doing: ((Base&)d).foo(); but this
> is beat. I'm not clear on *why* this happens, though. I can't find
> anything in the C++ Reference Manual about this topic; I'm guessing
> that it might not be part of the language but has to do with compiler
> implementation issues.
>
> Can anyone shed any light on this? Thanks!!

I'm not sure what "C++ Reference Manual" you're reading. If it's the
ARM from 1990, look in section 13.1, Declaration Matching. ("Name
hiding" in the index will also point you there.) Derived::foo(int) is
not in the same scope as Base::foo(void), so Derived::foo(int) *hides*
Base::foo(void) rather than overloading it. To get around this you can
add either of the following to Derived:
int foo() { return Base::foo(); }
using Base::foo;

You may want to verify the using statement with somebody who knows
namespaces -- I'm new to them.
--
Kevin J. Hopps, Imation. E-mail to: kjhopps-at-imation-dot-com
My opinions are my own. I speak neither for Imation nor 3M.
Support the anti-spam amendment, HR 1748. See http://www.cauce.org

Dietma...@izb-soft.de

unread,
Dec 19, 1997, 3:00:00 AM12/19/97
to

Hi,

mmorr...@mindspring.com (Michael Hallman Morrissey) wrote:
> I'm having trouble understanding what happens when you try to
> overlay a function which is already overloaded. Consider the
> following bit of code:

Before doing anything else, lets get the terminology straight: There is
no "overlaying" in C++. There is "overloading" and "overriding", which
are two quite different things with unfortunate similar names.

Overloading a function (or an operator, which can be seen as just a
function with a special name) means to have several functions all
with the same name but with different arguments. Overloading only on
the return type does not work in C++. Overloading has nothing to do
with inheritance. Instead, it only depends on the static type of the
arguments of the functions.

Overriding a function means to have a virtual function, either abstract
or non-abstract, in a base class which is overridden in a derived class.
Overriding is only useful when hierarchies are used: this is the very
mechanism which allows [run-time] polymorphism.

Although overriding and overloading sound very similar, they don't
mix well. The problem here is the [at other times useful] rule that
overloaded members in a base class are hidden by a members in a derived
class. Since you basically have to override functions in derived
classes,
this conflicts with the overloading rules.

> class Base
> {
> public:
> int foo() {return 3;};
> virtual int foo(int x) {reutrn x*x;};
> };

Here you are overloading the function 'foo()', declaring one of the
versions to be overridable.

>
> class Derived : public Base
> {
> public:
> int foo(int x) {return x*x*x;};
> }

Now, you do two things at once: you are overloading the method
'foo(int)',
taking a 'Derived&' as first, implicit, member and you are also
overriding
it. Overloading 'foo()' results in all methods in the base class to
be hidden. Thus, if you have an object of type 'Derived' you can only
apply 'foo(int)' without explicit scope resolution (or casting; well,
no, you should not use casts for this...).

> main()
> {
> Derived d;
>
> cout << "Value of Base::foo() is " << d.foo() << endl;
>
> }
>
> When I try to compile this, the compiler thinks that d.foo() is
> trying to call Derived::foo(int) rather than Base::foo(void), and so
> I get that I'm trying to call foo(int) with too few arguments. Lame!

Well, according to the C++ rules, this is exactly correct.
Unfortunately,
this is apparently not exactly what you want. Now the big question is,
how could this problem be avoided, if it can at all? The good news is,
that there is a very clean solution to this problem. Here we go: as a
general rule, every virtual function should be private with some name
which is not used somewhere else in the class hierarchy, if a function
is
both overloaded and has to be polymorph! What then, is the use of such a
function. Of course, you would add an inline forwarding function, which
is not private, to call this private version. Then, you can override
the private virtual function without conflicting with overloading.
At first, it looks somewhat strange to override a function which you
can't even call from the class where you are overriding it (the access
rules for virtual functions are determined by the base where it is first
declared). But once you see how (and that) it works, this rule is easy
to accept. Here is an example:

class Base
{
private:
virtual int private_foo(int x) { return x * x; }


public:
int foo() { return 3; }

int foo(int x) { private_foo(x); }
};

class Derived
{
int private_foo(int x) { return x * x * x; }
};

The whole trick is, that the overriding function
('Derived::private_foo(int)'
does not overload the function 'foo()'. Thus, the conflict between
overloading and overriding is avoided. If you are not using overloading
within your class, you can go without the forwarding function since
there is no conflict.

> I can call the correct function by doing: ((Base&)d).foo(); but this
> is beat.

If you have to call a function a bas class, for whatever reason, you
should use scope resolution instead of cast. That is, you would write
the code like this:

d.Base::foo();

... and, of course, you should use new-style casts instead of the
[deprecated] old-fashioned cast, if you have to cast for whatever
reason:

static_cast<Base&>(d).foo();



> I'm not clear on *why* this happens, though. I can't find
> anything in the C++ Reference Manual about this topic; I'm guessing
> that it might not be part of the language but has to do with compiler
> implementation issues.

Nope. It is part of the language that members in base classes are hidden
by members in derived classes. If your C++ Reference Manual does not say
so, you should get a better/newer one (I'm not quite sure when this rule
was introduced into the C++ language). For example, you might want to
get
"The C++ Programming Language, 3rd Edition", B.Stroustrup,
Addison-Wesley.
--
<email:dietma...@claas-solutions.de>
<http://www.informatik.uni-konstanz.de>

Steve Jaffe

unread,
Dec 19, 1997, 3:00:00 AM12/19/97
to

This rather annoying feature is called 'lexical hiding'; the bottom line
is that if you override (ie redefine) any one of a set of inherited
overloaded functions, you must redefine _all_ of them; otherwise, the
ones you do not redefine will be inaccessible from the derived class.
See, for example, Stanley Lippman, "C++ Primer", p. 402.

BTW, I find this a good argument _against_ the somewhat popular idiom of
pairing set-get methods with a single overloaded name: eg instead of
setFoo(aFoo) vs getFoo(), using foo(aFoo) vs foo(); if a derived class
want's to alter one method (typically the 'set' method), it must
redundantly redeclare and redefine the 'get' method as well.

Michael Hallman Morrissey wrote:
>
> I'm having trouble understanding what happens when you try to
> overlay a function which is already overloaded. Consider the
> following bit of code:
>

> class Base
> {
> public:
> int foo() {return 3;};
> virtual int foo(int x) {reutrn x*x;};
> };
>

> class Derived : public Base
> {
> public:
> int foo(int x) {return x*x*x;};
> }

{ please don't quote needlessly, especially sig and banner. -jep }

--
Steven Jaffe-------------------------------------
Merrill Lynch Mortgage-Backed Securities Research
4 World Financial Center, North Tower, 15th Floor
New York NY 10281
Tel 212 449 9668 Fax 212 449 0912
------------------------------------sja...@ml.com

Herb Sutter

unread,
Dec 20, 1997, 3:00:00 AM12/20/97
to

Steve Jaffe <sja...@ml.com> wrote:
>This rather annoying feature is called 'lexical hiding'; the bottom line
>is that if you override (ie redefine) any one of a set of inherited
>overloaded functions, you must redefine _all_ of them; otherwise, the
>ones you do not redefine will be inaccessible from the derived class.
>See, for example, Stanley Lippman, "C++ Primer", p. 402.

(2nd ed?) Actually, Stan's example is slightly different. He's talking
about inheriting from two base classes that have the same virtual
function. (The solution is to use an intermediate base class to change the
function's name, so that you don't lose the virtualness; I didn't see that
solution on that page, but I didn't read around so maybe this solution was
mentioned somewhere nearby.)

Getting back to the original question, though:

>BTW, I find this a good argument _against_ the somewhat popular idiom of
>pairing set-get methods with a single overloaded name: eg instead of
>setFoo(aFoo) vs getFoo(), using foo(aFoo) vs foo(); if a derived class
>want's to alter one method (typically the 'set' method), it must
>redundantly redeclare and redefine the 'get' method as well.

This is a common misconception, but it's not really so. You just need to
write a "using" declaration:

struct Base {
virtual void f( double, double );
virtual void f( int );
virtual void f( complex<double> );
};

struct Derived : Base {
void f( int ); // override
using Base::f; // bring other inherited functions into scope,
// no need to redeclare or redefine
};

See also GotW #5 at www.peerdirect.com/resources/gotw005a.html#Solution
for more details.

Nathan Myers

unread,
Dec 20, 1997, 3:00:00 AM12/20/97
to

>Michael Hallman Morrissey wrote:
>> I'm having trouble understanding what happens when you try to
>> over[ride] a function which is already overloaded.

Steve Jaffe <sja...@ml.com> wrote:
>This rather annoying feature is called 'lexical hiding' ...

This "rather annoying feature" has been demonstrated
to prevent errors. (Some of us find errors annoying.)

>BTW, I find this a good argument _against_ the somewhat popular idiom of
>pairing set-get methods with a single overloaded name: eg instead of
>setFoo(aFoo) vs getFoo(), using foo(aFoo) vs foo(); if a derived class
>want's to alter one method (typically the 'set' method), it must
>redundantly redeclare and redefine the 'get' method as well.

There is no need to "redeclare and redefine the 'get' method as well",
redundantly or otherwise. The declaration "using Base::foo;" suffices
to bring in all the overloaded definitions except what is overridden.
Look up "using" in the index of any any quality C++ reference manual.

Nathan Myers
n...@nospam.cantrip.org http://www.cantrip.org/

Michael Hallman Morrissey

unread,
Dec 20, 1997, 3:00:00 AM12/20/97
to

he...@cntc.com (Herb Sutter) wrote:

...

>
>>BTW, I find this a good argument _against_ the somewhat popular idiom of
>>pairing set-get methods with a single overloaded name: eg instead of
>>setFoo(aFoo) vs getFoo(), using foo(aFoo) vs foo(); if a derived class
>>want's to alter one method (typically the 'set' method), it must
>>redundantly redeclare and redefine the 'get' method as well.
>

>This is a common misconception, but it's not really so. You just need to
>write a "using" declaration:
>
> struct Base {
> virtual void f( double, double );
> virtual void f( int );
> virtual void f( complex<double> );
> };
>
> struct Derived : Base {
> void f( int ); // override
> using Base::f; // bring other inherited functions into scope,
> // no need to redeclare or redefine
> };
>

Of course, there are many C++ compilers in use which do not
support namespaces. For example, I believe the Sun SC4.0 compiler
lacks this feature.

Steve Jaffe

unread,
Dec 22, 1997, 3:00:00 AM12/22/97
to

1) Would it be asking too much to request examples of the errors this
feature is intended to prevent?

b) All the 'quality C++ reference manuals' in the world will not change
the fact that many (I daresay the vast majority) of professional C++
programmers are now working with compilers which do not support
namespaces. And, to anticipate, anyone who needs to ask 'why?' must have
no experience of real-life corporate development.

Nathan Myers wrote:
>
> >Michael Hallman Morrissey wrote:
> >> I'm having trouble understanding what happens when you try to
> >> over[ride] a function which is already overloaded.
>
> Steve Jaffe <sja...@ml.com> wrote:
> >This rather annoying feature is called 'lexical hiding' ...
>
> This "rather annoying feature" has been demonstrated
> to prevent errors. (Some of us find errors annoying.)
>

> >BTW, I find this a good argument _against_ the somewhat popular idiom of
> >pairing set-get methods with a single overloaded name: eg instead of
> >setFoo(aFoo) vs getFoo(), using foo(aFoo) vs foo(); if a derived class
> >want's to alter one method (typically the 'set' method), it must
> >redundantly redeclare and redefine the 'get' method as well.
>

> There is no need to "redeclare and redefine the 'get' method as well",
> redundantly or otherwise. The declaration "using Base::foo;" suffices
> to bring in all the overloaded definitions except what is overridden.
> Look up "using" in the index of any any quality C++ reference manual.

--

Steven Jaffe-------------------------------------
Merrill Lynch Mortgage-Backed Securities Research
4 World Financial Center, North Tower, 15th Floor
New York NY 10281
Tel 212 449 9668 Fax 212 449 0912
------------------------------------sja...@ml.com

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

0 new messages