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

C++ inheritance misunderstanding

0 views
Skip to first unread message

Michael B. Johnson

unread,
Oct 17, 1996, 3:00:00 AM10/17/96
to

I have a feeling I'm letting what I know about the way I'd write in
Objective-C cloud my C++ thinking, but I'm really getting annoyed I can't
figure this out. I have 3 classes, each inheriting from the one in front of
it. I have a smorgasbord of "setValue()" routines, which get defined as you
move down the inheritance hiearchy. The ones at the leaves want to call the
ones defined in their superclass (or their super's superclass), and I'd like
to be able to have the calls resolve just based on their calling signature,
not by prepending class:: in front (the reason being that these are
autogenerated classes, and right now two different things autogenerate them,
and anyway, this seems it should work, darn it!).

I've written a small example; note that if I change the call to

setValue(xy);

to

A::setValue(xy);

it compiles fine; but it seems to me that it should work without the A::,
since all the various setValue() routines are public, and I'm doing public
inheritance...

so what obvious thing am I missing (since both gcc 2.7.2 and CC on the SGI
complain, I must be wrong).

#include <iostream.h>

class A {

protected:
float _value[2];

public:
A() {
_value[0] = _value[1] = 0.0f;
}

void setValue(float* value) {
_value[0] = value[0];
_value[1] = value[1];
}
};

//////////////////////
class B : public A {
public:
B() : A() {
}

void setValue(float x, float y) {
_value[0] = x;
_value[1] = y;
}
};

//////////////////////
class C : public B {
protected:
float _timestamp;

public:
C() : B(), _timestamp(0.0f) {
}
void setValue(float timestamp, float* xy) {
_timestamp = timestamp;
//A::setValue(xy); // don't want to have to do this
setValue(xy);
}

};


main()
{
C *c = new C();
float a[2] = {3.3, 2.2};


c->setValue(0.0, a);
cout << "hi wave!\n";

return 1;
}

--
--> Michael B. Johnson, SMVS, Ph.D. -- wa...@pixar.com|wa...@media.mit.edu
--> Media Arts Technologist, Pixar Animation Studios (Eastern Office)
--> alumnus, MIT Media Lab, Computer Graphics & Animation Group
--> http://wave.www.media.mit.edu/people/wave/

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

Pete Becker

unread,
Oct 17, 1996, 3:00:00 AM10/17/96
to

Let's simplify the problem:

class Base
{
public:
void f(int);
};

class Derived : public Base
{
public:
void f(int, int);
};

int main()
{
Derived d;
d.f(1); // error
}

The problem is that the two versions of f() are defined in different
scopes. This means that they do not overload, and the only version of
f() that can be called on an object of type Derived without using a
scope override is f(int,int).
The same problem arises in the original code: there is a definition of
setValue in C, and the versions in the base classes do not overload with
it. You can call the base version with an explicit scope qualifier or
you can give the base version of the function a different name.
Another approach is to hoist the base version into the derived class.
You can do this by writing a forwarding function in the derived class:

class Derived : public Base
{
public:
void f(int i) { Base::f(i); }
void f(int, int);
};

or, if your compiler supports this relatively new usage, you can add a
using declaration:

class Derived : public Base
{
public:
using Base::f;
void f(int, int);
};

The using declaration has the advantage that it pulls in all of the
versions of f from Base, without having to write a forwarding function
for each one. In this example it doesn't matter, but if there's more
than one (as in the original example, where B has two versions of
setValue, one defined in B and one hoisted from A with the same
technique) you can save some writing.
-- Pete

David Hammond

unread,
Oct 17, 1996, 3:00:00 AM10/17/96
to

Michael B. Johnson wrote:
>
> I have a feeling I'm letting what I know about the way I'd write in
> Objective-C cloud my C++ thinking, but I'm really getting annoyed I can't
> figure this out. I have 3 classes, each inheriting from the one in front of
> it. I have a smorgasbord of "setValue()" routines, which get defined as you
> move down the inheritance hiearchy. The ones at the leaves want to call the
> ones defined in their superclass (or their super's superclass), and I'd like
> to be able to have the calls resolve just based on their calling signature,
> not by prepending class:: in front (the reason being that these are
> autogenerated classes, and right now two different things autogenerate them,
> and anyway, this seems it should work, darn it!).
>
> So what obvious thing am I missing (since both gcc 2.7.2 and CC on the SGI

> complain, I must be wrong).
>

Well, Mike...

I doubt if this is any consolation, but when I read your thread I had to
agree with you when you said "this seems it should work, darn it!"

But I have just consulted my Lippman primer, and he says you can't do
this. Pgs. 401-3, Inherited Member Access, says:

"In most cases, use of the class scope operator is redundant. The
compiler can find the intended member without the additional lexical
aid. In two cases, however, this additional aid is necessary:
1. When an inherited member's name is reused in the derived class.
2. When two or more base classes define an inherited member with the
same name.

"Reuse of an inherited member's name within the derived class hides
the inherited member...

"When a name is reused by the inherited members of two or more base
classes, use of the unmodified name within the derived class is
ambiguous
and results in a compile time error. The class scope operator must be
used to disambiguate between the multiple instances of the inherited
members."

He even lists a somewhat similar example using zoo animals:

ZooAnimal::locate(void)
and
Bear::locate(int), where Bear is derived from ZooAnimal.

Sorry, dude.
Dave Hammond

David Vandevoorde

unread,
Oct 18, 1996, 3:00:00 AM10/18/96
to

>>>>> "MJ" == Michael B Johnson <wa...@pixar.com> writes:
[...]
MJ> I have a smorgasbord of
MJ> "setValue()" routines, which get defined as you move down the
MJ> inheritance hiearchy. The ones at the leaves want to call the
MJ> ones defined in their superclass (or their super's superclass),
MJ> and I'd like to be able to have the calls resolve just based on
MJ> their calling signature, not by prepending class:: in front (the
MJ> reason being that these are autogenerated classes, and right now
MJ> two different things autogenerate them, and anyway, this seems it
MJ> should work, darn it!).

Actually, this is FAQ 23.3. See there for an answer
(http://www.cerfnet.com/~mpcline/On-Line-C++-FAQs/).

Daveed

Bill Seurer

unread,
Oct 18, 1996, 3:00:00 AM10/18/96
to

When you re-use a name in an inheritance heirarchy the name at the lower
level hides all the names at the higher level. Thus you must use the
scope resolution operator to get to the base class's similarly named
function. See section 23.3 in the C++ FAQ:

http://www.cerfnet.com/~mpcline/C++-FAQs-Lite/strange-inheritance.html#[2
3.3]
--

- Bill Seurer ID Tools and Compiler Development IBM Rochester,
MN
Business: BillS...@vnet.ibm.com Home:
BillS...@aol.com
WWW: http://members.aol.com/BillSeurer

Bill Seurer

unread,
Oct 27, 1996, 2:00:00 AM10/27/96
to

Harri Haanp{{

unread,
Oct 27, 1996, 2:00:00 AM10/27/96
to

Pete Becker <pbe...@oec.com> writes:

> or, if your compiler supports this relatively new usage, you can add a
> using declaration:

>=20


> class Derived : public Base
> {
> public:
> using Base::f;
> void f(int, int);
> };

Is that real, working C++? Does any version of g++ support that yet?
Does using work with operators as well? Can I force inheritance of
operator=3D() (which to my knowledge isn't normally inherited) by

using Base::operator=3D; ?

Wondering why they eliminate the problems I have worked around so hard,
Harri Haanp=E4=E4

0 new messages