 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Philip Guest
|
Posted: Thu Nov 10, 2005 5:55 pm Post subject: Virtual functions and return values |
|
|
The following code compiles clean on MSVC++ 7.1:
class Base
{
public:
virtual int test1(int);
virtual int test2(int);
virtual int test3(int);
virtual int test4(int);
};
class Derived : public Base
{
public:
// why no virtual function return error in following two?
int* test1(const int);
int* test2(const int&);
// uncomment to receive virtual fuunction return error
// int* test3(int);
int test4(int*);
};
int test5(int);
// uncomment to get compile error about differing only by return type
// int* test6(const int);
int test6(int);
int* test6(const int&);
void
testIt()
{
Derived derived;
int integer = 0;
// why no ambiguous call error in following two?
int* ret1 = derived.test1(integer);
int* ret2 = derived.test2(integer);
// uncomment to prove that Derived::test4 hides Base::test3
// derived.test4(integer);
derived.test4(&integer);
// uncomment to prove that test6 call is ambiguous
// test6(integer);
}
I understand why test4 will not compile and that is because the return
value differs and it is not co-variant return value.
I understand why test4 compiles and why Base::test4 is hidden (roughly
because you can't overload virtual functions).
I understand why the call to test6 is ambiguous (rougly because const&
decays away with integral types).
I don't understand why test1 and test2 compile. Is this a compiler bug
or a C++ standard quirk?
Of course specifying const int& is sort of silly, but enquiring minds
still want to know.
Philip
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
richard@ex-parrot.com Guest
|
Posted: Thu Nov 10, 2005 8:21 pm Post subject: Re: Virtual functions and return values |
|
|
Philip wrote:
| Quote: | The following code compiles clean on MSVC++ 7.1:
class Base
{
public:
virtual int test1(int);
virtual int test2(int);
virtual int test3(int);
virtual int test4(int);
};
class Derived : public Base
{
public:
// why no virtual function return error in following two?
int* test1(const int);
|
Legal. It is an entirely different function to the one in Base (which
it hides). It does not override the base function. (Incidentally, the
const here does not affect the signature, so int test1(const int) would
override the base class function.)
| Quote: | int* test2(const int&);
|
Again, no error -- it's simply a new function.
| Quote: | // uncomment to receive virtual fuunction return error
// int* test3(int);
|
This is legal. If your compiler gives an error, it is wrong. (Giving
a warning might be sensible, however.)
| Quote: | int test4(int*);
};
int test5(int);
|
| Quote: | // uncomment to get compile error about differing only by return type
// int* test6(const int);
int test6(int);
|
These two functions have the same parameters -- the top-level const is
irrelevant. (Non-template) functions of the same name cannot differ by
just their return types.
| Quote: | int* test6(const int&);
void
testIt()
{
Derived derived;
int integer = 0;
// why no ambiguous call error in following two?
int* ret1 = derived.test1(integer);
int* ret2 = derived.test2(integer);
|
The derived name hides the one in the base class.
| Quote: | // uncomment to prove that Derived::test4 hides Base::test3
// derived.test4(integer);
|
Yes. If you wanted them to overload each other, rather than to hide
each other, you'd have needed to have put a using declaration into the
derived class:
class Derived : public Base {
public:
using Base::test4;
int test4(int *);
};
But needing to do this often (though not always) reflects a design flaw
in your class -- do you really need them to have the same name?
| Quote: | derived.test4(&integer);
// uncomment to prove that test6 call is ambiguous
// test6(integer);
|
Indeed. Overload resolution will not favour pass-by-const-reference
over pass-by-value (or vice versa).
| Quote: | }
I understand why test4 will not compile and that is because the return
value differs and it is not co-variant return value.
I understand why test4 compiles and why Base::test4 is hidden (roughly
because you can't overload virtual functions).
|
You can overload virtual fuctions (though it not often a good idea).
There are three concepts involved -- overloading, overriding and
hiding:
class B {
virtual void f( int );
virtual void g( int );
virtual void h( int );
virtual void j( int );
};
class D : public B {
virtual void f( int ); // overrides B::f
virtual void g( double ); // hides B::g
using B::h;
virtual void h( double ); // overloads B::h
virtual void j( int ); // overrides B::j
virtual void j( double ); // overloads B::j
};
To overload one in a base class with one in a derived class, you either
need an explicit using declaration or you need to override the base
class function; otherwise, the derived function simply hides it.
| Quote: | I understand why the call to test6 is ambiguous (rougly because const&
decays away with integral types).
|
It's not specific to integral types.
--
Richard Smith
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Thu Nov 10, 2005 8:25 pm Post subject: Re: Virtual functions and return values |
|
|
Philip wrote:
| Quote: | The following code compiles clean on MSVC++ 7.1:
class Base
{
public:
virtual int test1(int);
virtual int test2(int);
virtual int test3(int);
virtual int test4(int);
};
class Derived : public Base
{
public:
// why no virtual function return error in following two?
int* test1(const int);
This one is an error. The const on the parameter doesn't affect |
the signature. Derived::test1(const int) overrides Base::test1(int).
| Quote: | int* test2(const int&);
This function has a different signature than the base. It |
doesn't override Base::test2(int).
| Quote: | // uncomment to get compile error about differing only by return type
// int* test6(const int);
int test6(int);
|
This is correct... Again the constness of the parameter itself HAS no
bearing on the signature. You have two overloads with the same
signature.
| Quote: | // why no ambiguous call error in following two?
int* ret1 = derived.test1(integer);
int* ret2 = derived.test2(integer);
|
Because there's only one overload for function test1 and test2,
what's ambiguous?
| Quote: | I don't understand why test1 and test2 compile. Is this a compiler bug
or a C++ standard quirk?
Of course specifying const int& is sort of silly, but enquiring minds
still want to know.
|
Other than the compiler not flagging test1's return type mismatch, I
don't see what's confusing.
int test(int);
int test(const int)
are the same function signature.
Do you know the difference between overloading and overriding and
how the name hiding really works?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Fri Nov 11, 2005 9:00 am Post subject: Re: Virtual functions and return values |
|
|
[email]richard (AT) ex-parrot (DOT) com[/email] wrote:
| Quote: | // why no virtual function return error in following two?
int* test1(const int);
Legal. It is an entirely different function to the one in Base (which
it hides). It does not override the base function. (Incidentally, the
const here does not affect the signature, so int test1(const int) would
override the base class function.)
|
test1(const int) overrides test1(int). The const has no bearing here.
Whatever compiler he is using is broken.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Fri Nov 11, 2005 9:10 am Post subject: Re: Virtual functions and return values |
|
|
Philip wrote:
| Quote: |
I understand why the call to test6 is ambiguous (rougly because const&
decays away with integral types).
|
const& doesn't decay with integral types. In fact it doesn't decay ever.
Ganesh
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Philip Guest
|
Posted: Sat Nov 12, 2005 10:29 am Post subject: Re: Virtual functions and return values |
|
|
Richard,
Thanks for the detailed reply and the concise explanation of the
difference between overriding and overloading. Also, I note that there
were a few typos in my message where I referred to the wrong member
function which you sorted out, so my thanks for that (and to the other
posters for their time and effort as well).
I got this issue compiling on MSVC 7.1, and when I compiled against gcc
3.4.4 I got much more explainable results. I then got an error for
Derived::test1, because gcc considered it to be a virtual fucntion of
Base::test1 but the returned types differed.
However, gcc accepted the Derived::test2. Here are the two signatures
(not valid code but just to illustrate).
virtual int Base::test2(int);
int* Derived::test2(const int&);
So, I regard MSVC as having a bug here. It should have produced an
error just like gcc.
Both compilers decided that Derived::test2 overrides Base::test2. I
believe because the added int reference makes the signature
sufficiently different (removing the const has no effect). I am not
sure this is correct in a pragmatic sense, because there is no real
difference in terms of outcome between above two signatures: The code
in both test2 routines does not get change the caller's data (unless a
const cast is done) so to my mind the signature is the same. But never
mind.
Lastly, you said the following:
| Quote: | // uncomment to receive virtual fuunction return error
// int* test3(int);
This is legal. If your compiler gives an error, it is wrong. (Giving
a warning might be sensible, however.)
|
I don't believe it is legal. For virtual functions to work, the return
type has to be the same (or co-variant) so that the following works:
virtual int Base::test5(int);
int Derived::test5(int);
Base* pBase = new Derived();
int ret = pBase->test5(integer); // run-time choice of test5 routines.
Thanks again for all your help (and to the other posters), and by the
way this is not my code. I actually renamed the base functions and
removed all the base virtual qualifiers to make the class structure
less "mentally" ambiguous. That is all I could do in the time given.
Philip
"The only reason this parrot is sitting on its perch is because it is
nailed there!"
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|