Problem with covariant return types

R

Rob.

I originally thought this was a compiler error but it seems the standard
prohibits the code below. Has anyone got any good ideas about how to code
around it?

class A;
class B;
class X;
class Y;

class X
{
public:

virtual A* g () const;
};

class Y : public X
{
public:

virtual B* g () const;
};

[The compiler signals an error (non-covariant return types) at this point
because it doesn't know that B is derrived from A]

class A
{
public:

virtual X* f () const;
};


class B : public A
{
public:

virtual Y* f () const;
};

Thanks,

Rob.
 
A

Alf P. Steinbach

* Rob.:
I originally thought this was a compiler error but it seems the standard
prohibits the code below. Has anyone got any good ideas about how to code
around it?

class A;
class B;
class X;
class Y;

class X
{
public:

virtual A* g () const;
};

class Y : public X
{
public:

virtual B* g () const;
};

[The compiler signals an error (non-covariant return types) at this point
because it doesn't know that B is derrived from A]

class A
{
public:

virtual X* f () const;
};


class B : public A
{
public:

virtual Y* f () const;
};


Off the cuff:


class A;
class B;
class X;
class Y;

class X
{
public:
virtual A* g() const;
A* gA() const;
};

class Y : public X
{
public:
virtual A* g() const;
B* gB();
};


class A
{
public:
virtual X* f() const;
X* fX() const;
};


class B : public A
{
public:
virtual X* f() const;
Y* fY();
};


A* X::gA() const { return g(); }
B* Y::gB() const { return static_cast<B*>( g() ); }
X* A::fX() const { return f(); }
Y* B::fY() const { return static_cast<Y*>( f() ); }
 
B

Bob Hairgrove

I originally thought this was a compiler error but it seems the standard
prohibits the code below. Has anyone got any good ideas about how to code
around it?
[snip]

What compiler is it? MSVC 6.0, for example, did not yet support
covariant return types IIRC. It supports them in version 7.x, however.
 
S

Siemel Naran

Alf P. Steinbach said:
class X
class Y : public X
class A
{
public:
virtual X* f() const;
X* fX() const;
};


class B : public A
{
public:
virtual X* f() const;
Y* fY();
};


A* X::gA() const { return g(); }
B* Y::gB() const { return static_cast<B*>( g() ); }
X* A::fX() const { return f(); }
Y* B::fY() const { return static_cast<Y*>( f() ); }

This is a great idea. One can use it for user types. Say the base class
returns a shared_ptr<X> and the derived class returns a shared_ptr<Y>, which
we know is covariant but the compiler doesn't.

Only thing I've done in the past is to to rename fX() and fY() to f(). So
my class looks like this:

class A
{
private/protected:
virtual X* dof() const;
public:
counted_ptr<X> f() const { return dof(); }
};

class B : public A
{
private/protected:
virtual X* dof() const;
public:
counted_ptr<Y> f() const { return static_cast<Y*>(dof()); }
};

But wait a sec. I've violated the guideline that you ought not to override
a non-virtual function. In general, this is a fine rule that we ought to
respect. Because when we call a function from a pointer to the base class,
the system ought to call the derived class function -- and the most popular
example of this is the virtual destructor.

But in the above class design, we are calling the derived class function,
namely dof(). It's just that A::f() casts the return type to something
class A knows about, namely an X* or counted_ptr<X>. Presumably A.h
includes X.h or forward declares class X. And B::f() also calls the derived
class function, namely dof() again. Assuming B::dof() returns an object
that is Y or higher cast as an X*, it's perfectly OK for B::f() to cast this
to a counted_ptr<Y>. It's the same object after all.

So when we follow the above idiom, it seems perfectly OK to break the
guideline that you ought not to override a non-virtual function. Any
thoughts?
 
J

JKop

Rob. posted:
I originally thought this was a compiler error but it seems the standard
prohibits the code below. Has anyone got any good ideas about how to code
around it?

class A;
class B;
class X;
class Y;

Have you tried:

class A;
Class B : public A;
class X;
class Y : public X;

?

-JKop
 
B

Bob Hairgrove

I originally thought this was a compiler error but it seems the standard
prohibits the code below. Has anyone got any good ideas about how to code
around it?

class A;
class B;
class X;
class Y;

class X
{
public:

virtual A* g () const;
};

class Y : public X
{
public:

virtual B* g () const;
};

[The compiler signals an error (non-covariant return types) at this point
because it doesn't know that B is derrived from A]

class A
{
public:

virtual X* f () const;
};


class B : public A
{
public:

virtual Y* f () const;
};

Thanks,

Rob.

I don't think this will work because of the implicit circular
reference(s) you have. You might try just returning a pointer to the
base class in each instance.
 
R

Rob.

JKop said:
Rob. posted:


Have you tried:

class A;
Class B : public A;
class X;
class Y : public X;

?

-JKop

Yes I've tried that. Thought it might be possible to tell the compiler that
B was derived from A before fully defining the class. Apparently not (well
not in msvc 7.1 a least).

Thanks,

Rob.
 
A

Alf P. Steinbach

* Siemel Naran:
This is a great idea.

Now that I'm awake: actually for type safety the calls should go the
other way, e.g. Y::g should invoke Y::gB, with no casts.

Am I stupid, or what?
 
A

Alf P. Steinbach

* Alf P. Steinbach:
Now that I'm awake: actually for type safety the calls should go the
other way, e.g. Y::g should invoke Y::gB, with no casts.

Am I stupid, or what?

Yes, definitely; I had it right the first time. Grr. And now I'm
holding a conversation with myself...
 

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,020
Latest member
GenesisGai

Latest Threads

Top