By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,778 Members | 1,957 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,778 IT Pros & Developers. It's quick & easy.

Virtual function parameter variance

P: n/a

Hello all,

Quoting from page 24 of "The Boost Graph Library; User Guide and Reference
Manual":

"It turns out that by the contravariance subtyping rule, the parameter type
in the derived classes member function must be either the same type or a
base class of the type as the parameter in the base class."

Now please consider this code:

#include <iostream>

struct base_1 {};
struct derived_1: base_1 {};

struct base_2
{
virtual void foo(derived_1 *p) {std::cout << "base_2::foo()\n";}
};

struct derived_2: base_2
{
virtual void foo(base_1 *p) {std::cout << "derived_2::foo()\n";}
};

int main()
{
base_2 *ptr = new derived_2;
ptr->foo(new derived_1);
}

This outputs base_2::foo(). Why?

The quoted passage implies derived_2::foo() should override base_2::foo().
Clearly, it does not. Furthermore, I cannot find anything in the Standard
that indicates it should. So, I am clearly misinterpreting the quoted
passage. Can anybody explain to me what was meant in that passage?

Thank you,
Dave
Jul 22 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
On Sat, 7 Aug 2004 23:38:14 -0700, "Dave" <be***********@yahoo.com>
wrote:

Hello all,

Quoting from page 24 of "The Boost Graph Library; User Guide and Reference
Manual":

"It turns out that by the contravariance subtyping rule, the parameter type
in the derived classes member function must be either the same type or a
base class of the type as the parameter in the base class."

Now please consider this code:

#include <iostream>

struct base_1 {};
struct derived_1: base_1 {};

struct base_2
{
virtual void foo(derived_1 *p) {std::cout << "base_2::foo()\n";}
};

struct derived_2: base_2
{
virtual void foo(base_1 *p) {std::cout << "derived_2::foo()\n";}
};

int main()
{
base_2 *ptr = new derived_2;
ptr->foo(new derived_1);
}

This outputs base_2::foo(). Why?

The quoted passage implies derived_2::foo() should override base_2::foo().
Clearly, it does not. Furthermore, I cannot find anything in the Standard
that indicates it should. So, I am clearly misinterpreting the quoted
passage. Can anybody explain to me what was meant in that passage?

Thank you,
Dave


Unfortunately, it doesn't work the way you propose in C++.

Here is an interesting discussion about co- and contravariance WRT
C++. It is a little dated (1995), so maybe there is something new in
the works??

http://tinyurl.com/54f3d

--
Bob Hairgrove
No**********@Home.com
Jul 22 '05 #2

P: n/a
On Sun, 08 Aug 2004 12:29:21 +0200, Bob Hairgrove
<wouldnt_you_like@to_know.com> wrote:
On Sat, 7 Aug 2004 23:38:14 -0700, "Dave" <be***********@yahoo.com>
wrote:

Hello all,

Quoting from page 24 of "The Boost Graph Library; User Guide and Reference
Manual":

"It turns out that by the contravariance subtyping rule, the parameter type
in the derived classes member function must be either the same type or a
base class of the type as the parameter in the base class."

[snip]

Sorry, it wasn't your proposal ... I got out my copy of the BGL and
looked up the quoted passage. It is confusing to me, too.

In context of what follows (namely, replacing inheritance and virtual
functions with non-member template functions to ensure type safety) I
interpret the quoted passage as a kind of "wishful thinking". The
example given BEFORE the passage illustrates something entirely
different, namely an attempt to use covariant parameter types (which
don't exist in C++ and hence the resulting error message).

But contravariant parameter types, although conceptually feasible,
also don't exist in C++ (yet??). That's the only sense I can make of
it. Note that the second example (ColorPoint2) uses a Point* as
parameter, which is the same type as the base class function "equal()"
takes. It wouldn't work if the derived class took a ColorPoint2* as an
argument (that would be contravariance) because the derived class
equal() would then hide the base class function.

--
Bob Hairgrove
No**********@Home.com
Jul 22 '05 #3

P: n/a
On Sun, 08 Aug 2004 13:24:45 +0200, Bob Hairgrove
<wouldnt_you_like@to_know.com> wrote:

[snip]
But contravariant parameter types, although conceptually feasible,
also don't exist in C++ (yet??). That's the only sense I can make of
it. Note that the second example (ColorPoint2) uses a Point* as
parameter, which is the same type as the base class function "equal()"
takes. It wouldn't work if the derived class took a ColorPoint2* as an
argument (that would be contravariance) because the derived class
equal() would then hide the base class function.


Oops ... taking a ColorPoint2* in ColorPoint2::equal() would yet again
be covariance!

Contravariance would mean that Point::equal() would have to take a
more derived type pointer, and ColorPoint2::equal() a Point*.
Nevertheless, ColorPoint2::equal() would still hide Point::equal() if
the argument types aren't exactly the same.

(Slippery stuff, this contravariance ... no wonder it hasn't yet made
it into the language...)

--
Bob Hairgrove
No**********@Home.com
Jul 22 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.