473,513 Members | 6,210 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Covariant return types

Hi,

I would like to use covariant return types in mutual dependent classes like:

class IB;
class IA {
virtual IB* getIB() = 0;
};
class IB{
virtual IA* getIA() = 0;
};

class B;
class A : public IA{
B *getIB(); /// Here I get an error!
// If I replace with IB * getIB(); everything works fine
};

class B : public IB {
A* getIA();
};

I understand, that the compiler cannot know - at the time of the
declaration of A::getIB() - that B derives from IB. Is there a way to do
some sort of forward declaration with "inheritance information" in order
to get the example to work?

thanks in advance

Martin
Jul 23 '05 #1
8 2641

"Martin Stettner" <no****@martin.dot.stettner.at.complement.dot.at > wrote in
message news:ct*********@newsreader1.utanet.at...
Hi,

I would like to use covariant return types in mutual dependent classes like:
class IB;
class IA {
virtual IB* getIB() = 0;
};
class IB{
virtual IA* getIA() = 0;
};

class B;
class A : public IA{
B *getIB(); /// Here I get an error!
// If I replace with IB * getIB(); everything works fine
};

class B : public IB {
A* getIA();
};

I understand, that the compiler cannot know - at the time of the
declaration of A::getIB() - that B derives from IB.
That is not the problem. The problem is that you're trying
to override a virtual function, but your return value is not
the same as that of the function you're trying to override.
This is not allowed. All of: the name, arguments, and return
type must be identical.
Is there a way to do
some sort of forward declaration with "inheritance information" in order
to get the example to work?


What specifically are you trying to do?

-Mike
Jul 23 '05 #2
"Mike Wahler" <mk******@mkwahler.net> wrote in message
news:GZ****************@newsread3.news.pas.earthli nk.net...

"Martin Stettner" <no****@martin.dot.stettner.at.complement.dot.at > wrote in
message news:ct*********@newsreader1.utanet.at...
Hi,

I would like to use covariant return types in mutual dependent classes

like:

class IB;
class IA {
virtual IB* getIB() = 0;
};
class IB{
virtual IA* getIA() = 0;
};

class B;
class A : public IA{
B *getIB(); /// Here I get an error!
// If I replace with IB * getIB(); everything works fine
};

class B : public IB {
A* getIA();
};

I understand, that the compiler cannot know - at the time of the
declaration of A::getIB() - that B derives from IB.


That is not the problem. The problem is that you're trying
to override a virtual function, but your return value is not
the same as that of the function you're trying to override.
This is not allowed. All of: the name, arguments, and return
type must be identical.

No, they need not all be identical. Specifically, the
return type can vary, as long as, for an override in
a derived class, the return type has a base that is
the return type in the base class. That is what the
phrase 'covariant return types' means. For example,
this is legal C++:

class BR {};
class DR : public BR {};

class B {
public: virtual BR & covaret();
};
class D : public B {
public: virtual DR & covaret();
};

--
--Larry Brasfield
email: do***********************@hotmail.com
Above views may belong only to me.
Jul 23 '05 #3
Mike Wahler wrote:
"Martin Stettner" <no****@martin.dot.stettner.at.complement.dot.at > wrote in
message news:ct*********@newsreader1.utanet.at...
...
class IB;
class IA {
virtual IB* getIB() = 0;
};
class IB{
virtual IA* getIA() = 0;
};

class B;
class A : public IA{
B *getIB(); /// Here I get an error!
// If I replace with IB * getIB(); everything works fine
};

class B : public IB {
A* getIA();
};

That is not the problem. The problem is that you're trying
to override a virtual function, but your return value is not
...

There's already an answer to this in the thread: The return type of a
derived function can be derived from the return type of the base function...
...
What specifically are you trying to do?
I'm trying to separate interface and implementation (I heard that's a
good thing :-) ...)

IA and IB in the above code represent some interface classes to a
module. A and B implement these interfaces. From outside the module, a
client only knows that getIA returns an IA (and getIB and IB).

But inside the module, it would be nice to indicate that the methods
actually return the respective subclasses (if not, I'd either have to
implement a second method pair getA/getB or to do some nasty casting...)

Perhaps there's someone who can tell me how to solve the problem (or at
least tell me, that there's certainly no solution...)

-Mike


--
Martin
Jul 23 '05 #4
Martin Stettner wrote:
Mike Wahler wrote:
class IB;
class IA {
virtual IB* getIB() = 0;
};
class IB{
virtual IA* getIA() = 0;
};

class B;
class A : public IA{
B *getIB(); /// Here I get an error!
// If I replace with IB * getIB(); everything works fine
};

class B : public IB {
A* getIA();
};
That's tricky :).
The standard says that the covariant return type shall be complete at
the point of declaration of the method in the derived class (or it can
be the derived class type) I'm trying to separate interface and implementation (I heard that's a

good thing :-) ...) I heard that too :). But now I'm learning c# :(
Perhaps there's someone who can tell me how to solve the problem (or at least tell me, that there's certainly no solution...)

Try this:
|struct IA
|{
| struct IB
| {
| virtual IA* getIA();
| };
| virtual IB* getIB();
|};
|typedef IA::IB IB;
|struct A : public IA
|{
| struct B : public IB
| {
| virtual A* getIA();
| };
| virtual B* getIB();
|};
|typedef A::B B;

Comeau c++ online say it's ok. VC 7.1 doesn't like it :).
....
Best regards,
Bogdan Sintoma

Jul 23 '05 #5
"Martin Stettner" <no****@martin.dot.stettner.at.complement.dot.at >
wrote in message news:ct**********@newsreader1.utanet.at...
Mike Wahler wrote:
"Martin Stettner" <no****@martin.dot.stettner.at.complement.dot.at > wrote in
message news:ct*********@newsreader1.utanet.at...
...
class IB;
class IA {
virtual IB* getIB() = 0;
};
class IB{
virtual IA* getIA() = 0;
};

class B;
class A : public IA{
B *getIB(); /// Here I get an error!
// If I replace with IB * getIB(); everything works fine
};

class B : public IB {
A* getIA();
};

That is not the problem. The problem is that you're trying
to override a virtual function, but your return value is not
...

There's already an answer to this in the thread: The return type of a derived function can be derived from the return type of the
base function...
... What specifically are you trying to do?


I'm trying to separate interface and implementation (I heard that's a good thing :-) ...)


Often it is, but not as a matter of dogma.
IA and IB in the above code represent some interface classes to a module. A and B implement these interfaces. From outside the
module, a client only knows that getIA returns an IA (and getIB and IB).
It seems to me that having the interface methods
return implementation classes rather than simply
the interface is confounding the boundary between
interface and implementation. Is there a particular
reason you need to blur that distinction?
But inside the module, it would be nice to indicate that the methods actually return the respective subclasses (if not, I'd either
have to implement a second method pair getA/getB or to do some nasty casting...)
You are free, inside the module, and within the
implementation class, to add methods and friends
as necessary to get the functionality you need
internally. The second method pair need not be
expensive. In fact, the interface implementation
can use that pair to do the real work.
Perhaps there's someone who can tell me how to solve the problem (or at least tell me, that there's certainly no solution...)


I am not expert enough to claim no solution exists, but I
could not think of any way to do exactly what you asked.
The problem is that the inheritance relationship cannot be
described independently of the class definition, so there
is an inherent circularity (as you have found) where each
subclass, to be defined as you desire, must have the other
class already defined. Without breaking the subclasses
into two, (separating out some more interface), there is
no way to break that circular dependency.

The answer, IMHO, is to get interface and implementation
considerations more cleanly separated, first in your own
thinking then in the code.

--
--Larry Brasfield
email: do***********************@hotmail.com
Above views may belong only to me.

Jul 23 '05 #6
Larry Brasfield wrote:
"Martin Stettner" <no****@martin.dot.stettner.at.complement.dot.at >
wrote in message news:ct**********@newsreader1.utanet.at...
Mike Wahler wrote:
"Martin Stettner" <no****@martin.dot.stettner.at.complement.dot.at > wrote in
message news:ct*********@newsreader1.utanet.at...
...
class IB;
class IA {
virtual IB* getIB() = 0;
};
class IB{
virtual IA* getIA() = 0;
};

class B;
class A : public IA{
B *getIB(); /// Here I get an error!
// If I replace with IB * getIB(); everything works fine
};

class B : public IB {
A* getIA();
};
[some snip]

Often it is, but not as a matter of dogma.


I agree with you on that point...
IA and IB in the above code represent some interface classes to a module. A and B implement these interfaces. From outside the
module, a client only knows that getIA returns an IA (and getIB and IB).

It seems to me that having the interface methods
return implementation classes rather than simply
the interface is confounding the boundary between
interface and implementation. Is there a particular
reason you need to blur that distinction?


I think I understand your arguments, but I'm not sure if I agree with
them: The interface is clearly defined using IA and IB (whose methods
also just return interface pointers). So no class using the interfaces
will have any clue about the implementation.

On the other hand, it's also well defined (in my case), that A and B
implement the methods in a way, that they always return objects of type
B and A respectively. And every part that works with the two
implementation classes knows about this.

So I would like to express this fact in code, and I think, that's one of
the reasons, covariant return types were introduced (but I may be wrong
on this last point).


[...]
internally. The second method pair need not be
expensive. In fact, the interface implementation
can use that pair to do the real work.
Actually, it wouldn't be expensive at all: The implementation just
returns an internal member pointer. But writing two methods which do
exactly the same thing the same way bothers me.
[...]
The problem is that the inheritance relationship cannot be
described independently of the class definition, so there
That's what I wasn't sure about: It could have been that there were some
syntax to do this kind of forward declaration for inheritances. But if
this is impossible, of course I have to find some other way.
...
The answer, IMHO, is to get interface and implementation
considerations more cleanly separated, first in your own
thinking then in the code.


I think, the way I want to do this is not so wrong. But this possibly
leads us to some sort of dogmatic discussion we both want do avoid here,
don't we?

But thank you very much for your thoughts, they push me to rethink my
design (which isn't a bad thing too, as i heard ...)

Martin

P.S: Sorry to the newsgroup purists: This subthread evolves away from a
language-specific topic, so I'll stop it here...
Jul 23 '05 #7
Bogdan Sintoma wrote:
Martin Stettner wrote:

[...[

That's tricky :).
Isn't it? :-)
The standard says that the covariant return type shall be complete at
the point of declaration of the method in the derived class (or it can
be the derived class type)
Would be nice to drop that restriction and instead allow to declare
incomplete types with inheritance relations... (what speaks against this
idea? But that's just a thought of mine, not a serious proposal, please
don't blame me for it...)
...
Try this:
|struct IA
|{
| struct IB
| {
| virtual IA* getIA();
| };
| virtual IB* getIB();
|};
|typedef IA::IB IB;
|struct A : public IA
|{
| struct B : public IB
| {
| virtual A* getIA();
| };
| virtual B* getIB();
|};
|typedef A::B B; Wow, I wouldn't have come up with this! But sadly there's no good reason
why my IB should be a member of IA (if I'd use this, it'd have to mean
something...)

Comeau c++ online say it's ok. Interesting: At the point of the declaration of B::getIA, A is not a
complete type, and getIA() is not a member of A (but of A::B). So,
conforms this to the standard?
VC 7.1 doesn't like it :). Bad news, as this is the compiler I have to use for this project.
...
Best regards,
Bogdan Sintoma

Thanks a lot

Martin
Jul 23 '05 #8

Martin Stettner wrote:
Bogdan Sintoma wrote:
Martin Stettner wrote:
The standard says that the covariant return type shall be complete at the point of declaration of the method in the derived class (or it can be the derived class type)
Would be nice to drop that restriction and instead allow to declare
incomplete types with inheritance relations... (what speaks against

this idea? But that's just a thought of mine, not a serious proposal, please don't blame me for it...)
I think you should search (and maybe post this question) on
comp.std.c++.
...
Try this:
|struct IA
|{
| struct IB
| {
| virtual IA* getIA();
| };
| virtual IB* getIB();
|};
|typedef IA::IB IB;
|struct A : public IA
|{
| struct B : public IB
| {
| virtual A* getIA();
| };
| virtual B* getIB();
|};
|typedef A::B B; Wow, I wouldn't have come up with this!

:)
I cannot take credit for this. I've saw that code a while ago on
c++.moderated.

Comeau c++ online say it's ok.

Interesting: At the point of the declaration of B::getIA, A is not a
complete type, and getIA() is not a member of A (but of A::B). So,
conforms this to the standard?

I'm not sure.
The main problem here is that you cannot forward declare the
inheritance relationship. Since, in this example the type of A is well
known (at compile time) at the point of declaration of getIA, I think
it should be ok.

..
..
Bogdan

Jul 23 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
2140
by: Alex Vinokur | last post by:
Hello, Here is some program with virtual constructors. Is there any difference between * clone1() vs. clone2() * create1() vs. create2() ? It seems that it should be.
3
1537
by: Sankar Nemani | last post by:
Hi, Does anyone know what the reason behind not allowing to use "covariant return types when overriding methods in derived classes" in C# is? Also while other OO languages such as Java, don't...
14
1988
by: Stefan Slapeta | last post by:
Hi, this code does not compile in C#: class base_class {} class derived_class : base_class {} class A { public virtual base_class f()
13
4238
by: Stephen Walch | last post by:
Error C2392 is hitting me hard! I have a managed C++ library that implements a bunch of fixed interfaces. For example, one interface is: public abstract interface IDbCommand { public...
2
1469
by: Mike | last post by:
I keep running into the scenario below over and over again. Currently I get around not having covariant return types by using an interface and explicit property definitions which works to some...
16
3178
by: Bob Hairgrove | last post by:
Consider the classic clone() function: class A { public: virtual ~A() {} virtual A* clone() const = 0; }; class B : public A { public:
6
2539
by: miked | last post by:
Why are there still no covariant return types? All searches reveal no workarounds accept for using an interface which is a real pain. I wind up missing this capability almost every time I...
8
2166
by: Alex Vinokur | last post by:
Here is a code from http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.8 -------------------------------------- class Shape { public: virtual ~Shape() { } // A...
3
4533
by: kikazaru | last post by:
Is it possible to return covariant types for virtual methods inherited from a base class using virtual inheritance? I've constructed an example below, which has the following structure: Shape...
9
1861
by: Rahul | last post by:
Hi Everyone, I was trying to implement covariant return types and i get a compilation error, class BB : public AA { }; class A
0
7254
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7432
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
7094
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
7519
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5677
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
4743
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3218
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1585
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
796
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.