Overriding a virtual function and changing its return type --- dependency issues

C

ctor

Hi,

I'm experiencing an annoying issue. Here is a simplified idea of what
I am trying to do. Inclusion guards aren't shown for readability. I
hope this isn't too confusing; I don't think a description would be as
clear as an example.

-----[ParentA.h]------
class ParentA {};

-----[ChildA.h]------
#include "ParentA.h"
#include "ChildB.h"
class ChildA: public ParentA { ChildB foo; };

-----[ParentB.h]------
class ParentA;
class ParentB {
virtual ParentA& getA() = 0;
};

-----[ChildB.h]------
#include "ParentB.h"
class ChildA;
class ChildB: public ParentB {
ChildA& getA();
};

---

When I try to compile my project, MSVC 2002 gives me the following
error message:

error C2555: 'ChildB::getA': overriding virtual function return type
differs and is not covariant from 'ParentB::getA'

I took this to mean that the problem is that the compiler doesn't
realize that ChildA is a type of ParentA because I forward-declared
ChildA instead of including its header file, so ChildB::getA looks
like an invalid signature. The problem is that if I replace the
forward-declaration with "#include ChildA.h", I encounter a dependency
issue, since ChildA.h also has to include ChildB.h because the ChildA
class contains a ChildB object.

Is there a way to specify that ChildA is a child of ParentA in a
forward-declaration? If not, does anyone have any suggestions for
getting around this problem?

Thanks.
 
H

Howard

ctor said:
Hi,

I'm experiencing an annoying issue. Here is a simplified idea of what
I am trying to do. Inclusion guards aren't shown for readability. I
hope this isn't too confusing; I don't think a description would be as
clear as an example.

-----[ParentA.h]------
class ParentA {};

-----[ChildA.h]------
#include "ParentA.h"
#include "ChildB.h"
class ChildA: public ParentA { ChildB foo; };

-----[ParentB.h]------
class ParentA;
class ParentB {
virtual ParentA& getA() = 0;
};

-----[ChildB.h]------
#include "ParentB.h"
class ChildA;
class ChildB: public ParentB {
ChildA& getA();
};

---

Why not return a ParentA& from ChildB::getA(), just like you do in
ParentB::getA()? You're returning a reference, so polymorphism will come
into play, and any calls to virtual functions in the returned ParentA object
will correctly execute their ChildA counterparts. And by publicly
inheriting, you've said that ChildA "is a" ParentA, so there shouldn't be
any problem. Any reason this idea won't work?

-Howard
 
C

ctor

ctor said:
Hi,

I'm experiencing an annoying issue. Here is a simplified idea of what
I am trying to do. Inclusion guards aren't shown for readability. I
hope this isn't too confusing; I don't think a description would be as
clear as an example.

-----[ParentA.h]------
class ParentA {};

-----[ChildA.h]------
#include "ParentA.h"
#include "ChildB.h"
class ChildA: public ParentA { ChildB foo; };

-----[ParentB.h]------
class ParentA;
class ParentB {
virtual ParentA& getA() = 0;
};

-----[ChildB.h]------
#include "ParentB.h"
class ChildA;
class ChildB: public ParentB {
ChildA& getA();
};

---

Why not return a ParentA& from ChildB::getA(), just like you do in
ParentB::getA()? You're returning a reference, so polymorphism will come
into play, and any calls to virtual functions in the returned ParentA object
will correctly execute their ChildA counterparts. And by publicly
inheriting, you've said that ChildA "is a" ParentA, so there shouldn't be
any problem. Any reason this idea won't work?

-Howard

Hi Howard, thanks for the response. Unfortunately that won't suit my
purposes because ChildB::getA() is a function that only gets called by
ChildB itself. ChildB knows that it should be getting a ChildA
reference, and so it expects to be able to use ChildA's extended
interface.
 
H

Howard

ctor said:
ctor said:
Hi,

I'm experiencing an annoying issue. Here is a simplified idea of what
I am trying to do. Inclusion guards aren't shown for readability. I
hope this isn't too confusing; I don't think a description would be as
clear as an example.

-----[ParentA.h]------
class ParentA {};

-----[ChildA.h]------
#include "ParentA.h"
#include "ChildB.h"
class ChildA: public ParentA { ChildB foo; };

-----[ParentB.h]------
class ParentA;
class ParentB {
virtual ParentA& getA() = 0;
};

-----[ChildB.h]------
#include "ParentB.h"
class ChildA;
class ChildB: public ParentB {
ChildA& getA();
};

---

Why not return a ParentA& from ChildB::getA(), just like you do in
ParentB::getA()? You're returning a reference, so polymorphism will come
into play, and any calls to virtual functions in the returned ParentA
object
will correctly execute their ChildA counterparts. And by publicly
inheriting, you've said that ChildA "is a" ParentA, so there shouldn't be
any problem. Any reason this idea won't work?

-Howard

Hi Howard, thanks for the response. Unfortunately that won't suit my
purposes because ChildB::getA() is a function that only gets called by
ChildB itself. ChildB knows that it should be getting a ChildA
reference, and so it expects to be able to use ChildA's extended
interface.

But it can! That's what polymorphism is all about. You don't show the
definition of getA(), but if it constructs (or otherwise obtains) a ChildA
object, then referring to it via a ParentA reference (or pointer) is
perfectly valid.

If you need to refer to members which exist ONLY in the ChildA object, then
you can use dynamic_cast on the returned reference where needed.

If you don't want to return a ParentA& reference from getA(), then why did
you make it a virtual function in ParentB in the first place?

-Howard
 
C

ctor

But it can! That's what polymorphism is all about. You don't show the
definition of getA(), but if it constructs (or otherwise obtains) a ChildA
object, then referring to it via a ParentA reference (or pointer) is
perfectly valid.

If you need to refer to members which exist ONLY in the ChildA object, then
you can use dynamic_cast on the returned reference where needed.

If you don't want to return a ParentA& reference from getA(), then why did
you make it a virtual function in ParentB in the first place?

-Howard

Thanks.

I didn't want to use a dynamic_cast because getA() will be called very
frequently (several hundred times per second).

I declared "virtual ParentA& ParentB::getA()" because ParentB needs to
call this function and use the interface pf the returned ParentA
reference.

Does that make sense?
 
N

Neil Cerutti

Hi,

I'm experiencing an annoying issue. Here is a simplified idea of
what I am trying to do. Inclusion guards aren't shown for
readability. I hope this isn't too confusing; I don't think a
description would be as clear as an example.

-----[ParentA.h]------
class ParentA {};

-----[ChildA.h]------
#include "ParentA.h"
#include "ChildB.h"
class ChildA: public ParentA { ChildB foo; };

-----[ParentB.h]------
class ParentA;
class ParentB {
virtual ParentA& getA() = 0;
};

-----[ChildB.h]------
#include "ParentB.h"
class ChildA;
class ChildB: public ParentB {
ChildA& getA();
};

---

When I try to compile my project, MSVC 2002 gives me the following
error message:

error C2555: 'ChildB::getA': overriding virtual function return type
differs and is not covariant from 'ParentB::getA'

Interesting problem. I think you need a proxy object for the A
hierarchy. Usually, an extra layer of indirection can solve this sort
of problem.

-----[ProxyA.h]-----
class ParentA;
struct ProxyA
{
ProxyA(ParentA& aa): a(aa) { }
ParentA& a; /* You can fiddle with this interface to meet your needs. */
};

Then modify ParentB.h, and ChildB.h:

-----[ParentB.h]-----
#include "ProxyA.h"
class ParentB
{
virtual ProxyA getA() = 0;
};


-----[ChildB.h]-----
#include "ParentB.h"
class ChildB: public ParentB
{
ProxyA getA();
};
Is there a way to specify that ChildA is a child of ParentA in a
forward-declaration?

I don't believe so.
 
N

Neil Cerutti

Interesting problem. I think you need a proxy object for the A
hierarchy. Usually, an extra layer of indirection can solve this sort
of problem.

-----[ProxyA.h]-----
class ParentA;
struct ProxyA
{
ProxyA(ParentA& aa): a(aa) { }
ParentA& a; /* You can fiddle with this interface to meet your needs. */
};

Based on one of you other replies in this thread, you actually need:

-----[ProxyA.h]-----
class ChildA;
struct ProxyA
{
ProxyA(ChildA& aa): a(aa) { }
ChildA& a;
};

No other changes necessary.
Then modify ParentB.h, and ChildB.h:

-----[ParentB.h]-----
#include "ProxyA.h"
class ParentB
{
virtual ProxyA getA() = 0;
};


-----[ChildB.h]-----
#include "ParentB.h"
class ChildB: public ParentB
{
ProxyA getA();
};
 
H

Howard

ctor said:
Thanks.

I didn't want to use a dynamic_cast because getA() will be called very
frequently (several hundred times per second).

That's not very frequently, and I doubt the cost of several hundred
dynamic_casts would be very high. (I'm not familiar with exactly how it's
accomplished, however.) Have you profiled the use of dynamic cast, and seen
that it causes problems?
I declared "virtual ParentA& ParentB::getA()" because ParentB needs to
call this function and use the interface pf the returned ParentA
reference.

Then why is ParentB::getA() _pure_ virtual, if ParentB needs to call it?

And what's the problem using a ChildB reference as it if were a reference to
a ParentB object? Every ChildB object IS A ParentB object.
Does that make sense?

Not really. Without seeing how any of this code is used, I can't really
guess what you're trying to accomplish. (But I still think returning
Parent& from the overriding function is what you need.)

-Howard
 
C

ctor

That's not very frequently, and I doubt the cost of several hundred
dynamic_casts would be very high. (I'm not familiar with exactly how it's
accomplished, however.) Have you profiled the use of dynamic cast, and seen
that it causes problems?

If you're not familiar with it, why are you giving me a lecture?
Then why is ParentB::getA() _pure_ virtual, if ParentB needs to call it?

Obviously ParentB is an abstract class, so when I say ParentB needs to
call getA(), I'm talking about a sub-object ParentB within a ChildB
object.
And what's the problem using a ChildB reference as it if were a reference to
a ParentB object? Every ChildB object IS A ParentB object.

The ChildA class has a public function "doSomething()" that ParentA
doesn't have.

ChildB needs to call getA().doSomething();
 
C

ctor

Interesting problem. I think you need a proxy object for the A
hierarchy. Usually, an extra layer of indirection can solve this sort
of problem.

-----[ProxyA.h]-----
class ParentA;
struct ProxyA
{
ProxyA(ParentA& aa): a(aa) { }
ParentA& a; /* You can fiddle with this interface to meet your needs. */
};

Based on one of you other replies in this thread, you actually need:

-----[ProxyA.h]-----
class ChildA;
struct ProxyA
{
ProxyA(ChildA& aa): a(aa) { }
ChildA& a;
};

No other changes necessary.

Interesting idea, but I don't think that does what I need. Sometime
in the future, ChildB may get a sibling whose getA() function needs to
return a reference to a sibling of ChildA.

Thanks for the suggestion, though. I do have a workaround for this
that depends on the implementation specifics, but I really didn't want
to have to do it that way.
Then modify ParentB.h, and ChildB.h:

-----[ParentB.h]-----
#include "ProxyA.h"
class ParentB
{
virtual ProxyA getA() = 0;
};


-----[ChildB.h]-----
#include "ParentB.h"
class ChildB: public ParentB
{
ProxyA getA();
};
 
H

Howard

ctor said:
If you're not familiar with it, why are you giving me a lecture?

Have you profiled the use of dynamic cast, and seen that it _actually_
causes problems for you? If not, why are you assuming it will be a
significant problem? There's a common saying here: "Premature optimization
is the root of all evil."
Obviously ParentB is an abstract class, so when I say ParentB needs to
call getA(), I'm talking about a sub-object ParentB within a ChildB
object.


The ChildA class has a public function "doSomething()" that ParentA
doesn't have.

ChildB needs to call getA().doSomething();

So... doSomething is ONLY called by code in a ChildB object, and the code
for doSomething ONLY exists in a ChildA object? Then why not remove getA
from ParentB? It's never called, and it's not properly overriden. You only
need a virtual function if you're planning on using polymorphism to execute
the appropriate function via a base class reference or pointer.

Alternatively, you could add a virtual ParentA::doSomething(). That would
allow you to return a ParentA reference, and call doSomething on it.

Or use dynamic_cast.

If none of those ideas help, you might post a more complete example,
including the code that calls getA (and perhaps even the code within getA).

-Howard
 
C

ctor

Have you profiled the use of dynamic cast, and seen that it _actually_
causes problems for you? If not, why are you assuming it will be a
significant problem? There's a common saying here: "Premature optimization
is the root of all evil."

No argument here. You're right that I haven't determined that
dynamic_cast would be a bottleneck in my program, and I apologize for
coming across aggressively.
So... doSomething is ONLY called by code in a ChildB object, and the code
for doSomething ONLY exists in a ChildA object? Then why not remove getA
from ParentB? It's never called, and it's not properly overriden. You only
need a virtual function if you're planning on using polymorphism to execute
the appropriate function via a base class reference or pointer.

ParentB does call getA(), and it modifies the returned object via
ParentA's interface. ChildB calls getA() and modifies the returned
object via ChildA's interface. The reason I am using this design is
that there will be classes that are siblings of ChildB whose getA()
functions return siblings of ChildA. In ChildB and all of its
siblings, ParentB takes care of the same generic stuff that applies to
ParentA objects.
Alternatively, you could add a virtual ParentA::doSomething(). That would
allow you to return a ParentA reference, and call doSomething on it.

Or use dynamic_cast.

If none of those ideas help, you might post a more complete example,
including the code that calls getA (and perhaps even the code within getA).

Actually, I think I have the issue sorted out. My solution wouldn't
be very enlightening without posting my code in its entirely, however.

Thanks.
 
A

Andrei Zavidei

By the way, if "ChildB knows that it should be getting a ChildA..."
then there's no need for dynamic_cast. Simple static_cast could[and
should] be used.

Regards,
Andrei
ctor said:
Hi,

I'm experiencing an annoying issue. Here is a simplified idea of what
I am trying to do. Inclusion guards aren't shown for readability. I
hope this isn't too confusing; I don't think a description would be as
clear as an example.

-----[ParentA.h]------
class ParentA {};

-----[ChildA.h]------
#include "ParentA.h"
#include "ChildB.h"
class ChildA: public ParentA { ChildB foo; };

-----[ParentB.h]------
class ParentA;
class ParentB {
virtual ParentA& getA() = 0;
};

-----[ChildB.h]------
#include "ParentB.h"
class ChildA;
class ChildB: public ParentB {
ChildA& getA();
};

---

Why not return a ParentA& from ChildB::getA(), just like you do in
ParentB::getA()? You're returning a reference, so polymorphism will come
into play, and any calls to virtual functions in the returned ParentA object
will correctly execute their ChildA counterparts. And by publicly
inheriting, you've said that ChildA "is a" ParentA, so there shouldn't be
any problem. Any reason this idea won't work?

-Howard

Hi Howard, thanks for the response. Unfortunately that won't suit my
purposes because ChildB::getA() is a function that only gets called by
ChildB itself. ChildB knows that it should be getting a ChildA
reference, and so it expects to be able to use ChildA's extended
interface.
 
H

Howard

Andrei Zavidei said:
By the way, if "ChildB knows that it should be getting a ChildA..."
then there's no need for dynamic_cast. Simple static_cast could[and
should] be used.

Regards,
Andrei

You're correct, of course.

-Howard
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top