Method overloading and inheritance

M

Mihai Osian

Hi everyone,

Given the code below, can anyone tell me:
a) Is this normal behaviour ?
b) If it is, what is the reason behind it ? I would expect the
A::method(int) to be inherited by B.

Compiler: gcc 4.1, Linux

Thanks,
Mihai

-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method();
};

void A::method(int n){
fprintf(stderr, "A::method(%d)\n", n);
}

void B::method(){
fprintf(stderr, "B::method\n");
}

int main(int argc, char** argv){

B b;
b.method(3);
return 0;
}


-----------------

mike@nemesis:~/work/inh_test$ g++ -o main main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no matching function for call to 'B::method(int)'
main.cpp:18: note: candidates are: virtual void B::method()
 
V

Victor Bazarov

Mihai said:
Hi everyone,

Given the code below, can anyone tell me:
a) Is this normal behaviour ?
b) If it is, what is the reason behind it ? I would expect the
A::method(int) to be inherited by B.

Compiler: gcc 4.1, Linux

Thanks,
Mihai

-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method();
};

Read about "name hiding" in the FAQ or on Google.

V
 
M

mlimber

Mihai said:
Hi everyone,

Given the code below, can anyone tell me:
a) Is this normal behaviour ?
b) If it is, what is the reason behind it ? I would expect the
A::method(int) to be inherited by B.

Compiler: gcc 4.1, Linux

Thanks,
Mihai

-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method();
};

void A::method(int n){
fprintf(stderr, "A::method(%d)\n", n);
}

void B::method(){
fprintf(stderr, "B::method\n");
}

int main(int argc, char** argv){

B b;
b.method(3);
return 0;
}


-----------------

mike@nemesis:~/work/inh_test$ g++ -o main main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no matching function for call to 'B::method(int)'
main.cpp:18: note: candidates are: virtual void B::method()

You haven't over-ridden the virtual function; you have hidden it since
your virtual function in B has a different function signature than that
in A.

Cheers! --M
 
A

Adrian

Mihai said:
Hi everyone,

Given the code below, can anyone tell me:
a) Is this normal behaviour ?
b) If it is, what is the reason behind it ? I would expect the
A::method(int) to be inherited by B.

Compiler: gcc 4.1, Linux

Thanks,
Mihai

-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method(); using A::method;
};

The prototype in B for method() hides all the function in A with the name
"method". You can use the keyword using as above to unhide the functions in A.
 
A

Alf P. Steinbach

* Mihai Osian:
[rearranged]
Given the code below,
-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method();
};

void A::method(int n){
fprintf(stderr, "A::method(%d)\n", n);
}

void B::method(){
fprintf(stderr, "B::method\n");
}

int main(int argc, char** argv){

B b;
b.method(3);
return 0;
}


-----------------

can anyone tell me:
a) Is this normal behaviour ?
A::method(int) to be inherited by B.
mike@nemesis:~/work/inh_test$ g++ -o main main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no matching function for call to 'B::method(int)'
main.cpp:18: note: candidates are: virtual void B::method()

Yes, it's normal behavior.

b) If it is, what is the reason behind it ?

Class B's 'method' declaration hides the inherited member function so
that it's not directly accessible.

The inherited member function can still be accessed via an A& or A*
referring to a B object. Or, you can make it available by including

using A::method;

in class B. Or by providing a wrapper in class B.

One rationale that's been put forward is that pure additions to class A,
such as introducing an overload of 'method', should not affect client
code using class B, unless that's explicitly specified in class B.
However, that ignores the fact that a B object is-an A wrt.
polymorphism, and can be referenced via A& or A* (oops, that client
code's still affected by pure additions to A). And it also ignores the
fact that this behavior is highly counter-intuitive, and the fact that
it restricts is-a behavior to runtime polymorphism, not supporting
compile time polymorphism, that is, template code working well with A
may not compile with B (counter-argument is that template code designed
for A may not otherwise necessarily have the intended effect with B (and
counter-counter that that problem is there anyway)).

I would expect the A::method(int) to be inherited by B.

It is; it's just not directly accessible the way the code is currently.

Btw., why don't you just use std::cerr instead of fprintf?
 
P

Phlip

Mihai said:
Given the code below, can anyone tell me:
a) Is this normal behaviour ?
b) If it is, what is the reason behind it ? I would expect the
A::method(int) to be inherited by B.

Compiler: gcc 4.1, Linux

Thanks,
Mihai

-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method();
};

Overrides must match a signature, which is (roughly) everything from
'method' to the ';'. That includes the int, so you really have two
signatures there. You can test this by independently overloading
method(int).

Next; don't do it. Never willingly give any two things the same name unless
you expressly expect them to override each other. A real-life method(int)
should instead have a deliberately different name.

Your experiment reveals "hiding", where the name of method() in one scope
hides a method with the same name but a different signature in another
scope. That's exactly the same kind of hiding as this:

int x = 42;
{
float x = 42.0;
assert(sizeof (float) = sizeof x);
}
assert(sizeof (int) = sizeof x);

The x in the inner scope hides the one in the outer scope.
 
S

Salt_Peter

Mihai said:
Hi everyone,

Given the code below, can anyone tell me:
a) Is this normal behaviour ?
b) If it is, what is the reason behind it ? I would expect the
A::method(int) to be inherited by B.

Compiler: gcc 4.1, Linux

Thanks,
Mihai

-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method();
};

void A::method(int n){
fprintf(stderr, "A::method(%d)\n", n);
}

void B::method(){
fprintf(stderr, "B::method\n");
}

int main(int argc, char** argv){

B b;
b.method(3);
return 0;
}


-----------------

mike@nemesis:~/work/inh_test$ g++ -o main main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no matching function for call to 'B::method(int)'
main.cpp:18: note: candidates are: virtual void B::method()

The member function B::method() hides all/any member functions that A
has with the name method(...), Regardless of the parameters involved
and it doesn't matter whether A::method(..) is virtual or not You could
however, call any version of A::method(..) from within B::method().

void B::method()
{
fprintf(stderr, "B::method\n");
A::method(99);
}

In a case like this, i'ld probably make A::method(int) pure virtual.
 
M

Mihai Osian

Alf said:
* Mihai Osian:
[rearranged]
Given the code below,
-----------------------

#include <stdio.h>

class A{
public:
virtual void method(int);
};

class B: public A{
public:
virtual void method();
};

void A::method(int n){
fprintf(stderr, "A::method(%d)\n", n);
}

void B::method(){
fprintf(stderr, "B::method\n");
}

int main(int argc, char** argv){

B b;
b.method(3);
return 0;
}


-----------------

can anyone tell me:
a) Is this normal behaviour ?
A::method(int) to be inherited by B.
mike@nemesis:~/work/inh_test$ g++ -o main main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no matching function for call to 'B::method(int)'
main.cpp:18: note: candidates are: virtual void B::method()

Yes, it's normal behavior.

Thanks, apparently everybody knew that, but me :) I've learned something
new today.
Class B's 'method' declaration hides the inherited member function so
that it's not directly accessible.

The inherited member function can still be accessed via an A& or A*
referring to a B object. Or, you can make it available by including

using A::method;

in class B. Or by providing a wrapper in class B.

One rationale that's been put forward is that pure additions to class A,
such as introducing an overload of 'method', should not affect client
code using class B, unless that's explicitly specified in class B.

I am not familiar with the term "pure addition", so before I start
arguing I will have to do my Google homework first.

However, that ignores the fact that a B object is-an A wrt.
polymorphism, and can be referenced via A& or A* (oops, that client
code's still affected by pure additions to A). And it also ignores the
fact that this behavior is highly counter-intuitive, and the fact that
it restricts is-a behavior to runtime polymorphism, not supporting
compile time polymorphism, that is, template code working well with A
may not compile with B (counter-argument is that template code designed
for A may not otherwise necessarily have the intended effect with B (and
counter-counter that that problem is there anyway)).

Sorry, you lost me. A concrete example would be more useful. To me,
the current behaviour is counter-intuitive. IMHO any change in the
ancestor class is _supposed_ to change the behaviour of all descendents.
It is; it's just not directly accessible the way the code is currently.

Btw., why don't you just use std::cerr instead of fprintf?

Old habbits, I guess. The first thing I learned (long ago) in C/C++
was "printf".

Anyway, thanks for the answer. Apparently I think differently than
everybody else. Which probably means I'm wrong :)

Mihai
 
M

Mihai Osian

Phlip said:
Overrides must match a signature, which is (roughly) everything from
'method' to the ';'. That includes the int, so you really have two
signatures there. You can test this by independently overloading
method(int).

Next; don't do it. Never willingly give any two things the same name unless
you expressly expect them to override each other. A real-life method(int)
should instead have a deliberately different name.


Actually, I have to write C++ wrapper classes around JNI calls (Java
Native Intefaces), which will mirror the functionality of the Java peer
classes.
The Java classes are organized in the way I described, so it is not
really my decision.

Your experiment reveals "hiding", where the name of method() in one scope
hides a method with the same name but a different signature in another
scope. That's exactly the same kind of hiding as this:

int x = 42;
{
float x = 42.0;
assert(sizeof (float) = sizeof x);
}
assert(sizeof (int) = sizeof x);

The x in the inner scope hides the one in the outer scope.

I don't think your argument is valid. In your outer scope there can
be only one "x" variable. In my "outer scope" - class A, there can be
any number of "method"s, with different signatures.
What you probably mean is that overloaded methods are just "flavours"
of a single function, so I should either overload them all, or overload
none. Except that I don't agree with this point of view. By the way -
the people who designed Java seem to share my opinion. Please, please, I
don't want to start a Java versus C++ flamewar. I am a C++ developer, it
just happens that I agree with the Java approach on this one.

Mihai
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Mihai said:
What you probably mean is that overloaded methods are just "flavours"
of a single function, so I should either overload them all, or overload
none. Except that I don't agree with this point of view. By the way -
the people who designed Java seem to share my opinion. Please, please, I
don't want to start a Java versus C++ flamewar. I am a C++ developer, it
just happens that I agree with the Java approach on this one.

If you are writing C++ code you must agree with the C++ standard. Trying to
change it will take several years, in the best case.
 
?

=?iso-8859-1?q?Kirit_S=E6lensminde?=

Mihai said:
Actually, I have to write C++ wrapper classes around JNI calls (Java
Native Intefaces), which will mirror the functionality of the Java peer
classes.
The Java classes are organized in the way I described, so it is not
really my decision.

Actually I don't think the advice there is the best. Use of the same
name isn't in and of itself a problem, but using the same name to do a
different things is confusing for people using the classes.

Hopefully the Java design you have to copy follows this with the
differing arguments reflecting differing situations where you want to
do the same thing. If it doesn't then the classes are probably a lot
harder to understand than they should be.
I don't think your argument is valid. In your outer scope there can
be only one "x" variable. In my "outer scope" - class A, there can be
any number of "method"s, with different signatures.
What you probably mean is that overloaded methods are just "flavours"
of a single function, so I should either overload them all, or overload
none. Except that I don't agree with this point of view. By the way -
the people who designed Java seem to share my opinion. Please, please, I
don't want to start a Java versus C++ flamewar. I am a C++ developer, it
just happens that I agree with the Java approach on this one.

Actually there is no real reason to overload either all or none. This
depends on the design of the classes and what the methods should be
doing. C++ like Java makes no rule about how you should do this.

What is different though are the rules for exposing the names in
sub-classes and the syntax for dealing with it. Not unreasonable. What
you want to add to your class B is this:

using A::method;

This pulls all of the methods called 'method' from A and makes them
available to B and you can then add or change them as you want. I
suppose you might consider this done automatically in Java, but it
isn't in C++.


K
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top