Pure Virtual Function Hiding

R

Ryan H.

A very simple example of something that acts quite odd:

class TopClass
{
public:
TopClass(){ }
virtual ~TopClass(){ }
virtual int myFunc() = 0;
};

class MiddleClass : public TopClass
{
public:
MiddleClass() : TopClass(){ }
virtual ~MiddleClass(){ }
virtual int myFunc( int x ) { return TopClass::myFunc()+x; }
};

class BottomClass : public MiddleClass
{
public:
BottomClass() : MiddleClass(){ }
virtual ~BottomClass(){ }
virtual int myFunc() { return 5; }
};

int
main( int argc, char* argv[] )
{
BottomClass c1;
c1.myFunc( 4 ); //will not compile: "'BottomClass::myFunc' : function
does not take 1 arguments"
return 0;
}

It seems that an instantiation of BottomClass cannot "see" the version
of myFunc that takes an int, declared in MiddleClass. However, both are
public and virtual, so why not?

I'm sure there is some very subtle reason why (probably having to do
with virtual function naming and overloading), but if anyone could
shine some light on this, we'd appreciate it. Some very experienced C++
guys I know have looked at it, without much luck.

Thanks all!
 
B

Ben Pope

Ryan said:
A very simple example of something that acts quite odd:

class TopClass
{
public:
TopClass(){ }
virtual ~TopClass(){ }
virtual int myFunc() = 0;
};

class MiddleClass : public TopClass
{
public:
MiddleClass() : TopClass(){ }
virtual ~MiddleClass(){ }
virtual int myFunc( int x ) { return TopClass::myFunc()+x; }
};

That looks a bit fishy. TopClass::myFunc is pure virtual.
class BottomClass : public MiddleClass
{
public:
BottomClass() : MiddleClass(){ }
virtual ~BottomClass(){ }
virtual int myFunc() { return 5; }
};

int
main( int argc, char* argv[] )
{
BottomClass c1;
c1.myFunc( 4 ); //will not compile: "'BottomClass::myFunc' : function
does not take 1 arguments"
return 0;
}

Thats right.
It seems that an instantiation of BottomClass cannot "see" the version
of myFunc that takes an int, declared in MiddleClass. However, both are
public and virtual, so why not?

Because the myFunc in BottomClass hides the definition of myFunc in
TopClass (because it's prototype is different). Add a using myFunc to
the BottomClass definition to unhide it.


Ben Pope
 
P

Pete Becker

Ryan said:
I'm sure there is some very subtle reason why (probably having to do
with virtual function naming and overloading), but if anyone could
shine some light on this, we'd appreciate it.

It has nothing to do with virtual. Take out the virtual tags and you'll
have the same problem. (Take out TopClass and you'll have the same
problem, too.)

Overloading only occurs among functions defined in the same scope.
BottomClass only defines one version of myFunc, and it takes no
arguments. End of story.

To get the overloading that you seem to want, hoist MiddleClass::myFunc
into BottomClass with 'using MiddleClass::myFunc'.
 
G

Greg

Ryan said:
A very simple example of something that acts quite odd:

class TopClass
{
public:
TopClass(){ }
virtual ~TopClass(){ }
virtual int myFunc() = 0;
};

class MiddleClass : public TopClass
{
public:
MiddleClass() : TopClass(){ }
virtual ~MiddleClass(){ }
virtual int myFunc( int x ) { return TopClass::myFunc()+x; }
};

class BottomClass : public MiddleClass
{
public:
BottomClass() : MiddleClass(){ }
virtual ~BottomClass(){ }
virtual int myFunc() { return 5; }
};

int
main( int argc, char* argv[] )
{
BottomClass c1;
c1.myFunc( 4 ); //will not compile: "'BottomClass::myFunc' : function
does not take 1 arguments"
return 0;
}

It seems that an instantiation of BottomClass cannot "see" the version
of myFunc that takes an int, declared in MiddleClass. However, both are
public and virtual, so why not?

I'm sure there is some very subtle reason why (probably having to do
with virtual function naming and overloading), but if anyone could
shine some light on this, we'd appreciate it. Some very experienced C++
guys I know have looked at it, without much luck.

Yes, the name "myFunc" in the BottomClass is said to "hide" the
identical name in the MiddleClass from which it inherits. I believe the
motivation for this behavior is avoid accidentally pulling in some
inherited name that happens to be the same as the one in the local
class that is more likely to be the name which the programmer intended
to reference.

In any case, the programmer can "unhide" the name in the base class
with a using declaration. So adding:

using MiddleClass::MyFunc;

to BottomClass's declaration should unhide MyFunc in the MiddleClass.
Once unhidden, code in the BottomClass should be able to call it.

Greg
 
R

Ryan H.

Sorry if there was any confusion created over the TopClass::myFunc
reference. The myFunc function in MiddleClass could just read

virtual int myFunc( int x ) { return 5; }

and it would still generate the error. The basic question I have is why
does the myFunc( int ) hide myFunc()? As a side note, adding a pure
virtual myFunc() to TopClass won't help either.

Put another way, in the classic Shapes examples, if there was a pure
virtual draw() function, and I inherited a 3DShape class with a virtual
draw( int perspective ), then my 3DBoxShape class couldn't call 3D's
draw( SIDE ), only the top-level draw().

I understand you can use using to unhide, but you shouldn't have to.
myFunc with the int is a member of MiddleClass, and therefore should
automatically be a member of BottomClass.
 
P

Pete Becker

Greg said:
Once unhidden, code in the BottomClass should be able to call it.

Just a bit of a clarification: code in BottomClass (and code outside it,
talking to a BottomClass object) can call MiddleClass::myFunc, provided
the name is explicitly qualified. In the original example, the
unqualified call doesn't work:

c1.myFunc( 4 ); //will not compile

But this works:

c1.MiddleClass::myFunc( 4 ); // okay

However, adding a using declaration is, of course, almost always the
right answer.
 
R

Ryan H.

Ah, I see now. In my example, BottomClass was hiding MiddleClass's
myFunc. I was getting distracted worrying why it <u>appeared</u>
TopClass was somehow hiding MiddleClass. I understand now. Thanks
everyone for all your help, it was greatly appreciated!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top