473,657 Members | 2,771 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 "inheritanc e information" in order
to get the example to work?

thanks in advance

Martin
Jul 23 '05 #1
8 2648

"Martin Stettner" <no****@martin. dot.stettner.at .complement.dot .at> wrote in
message news:ct******** *@newsreader1.u tanet.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 "inheritanc e information" in order
to get the example to work?


What specifically are you trying to do?

-Mike
Jul 23 '05 #2
"Mike Wahler" <mk******@mkwah ler.net> wrote in message
news:GZ******** ********@newsre ad3.news.pas.ea rthlink.net...

"Martin Stettner" <no****@martin. dot.stettner.at .complement.dot .at> wrote in
message news:ct******** *@newsreader1.u tanet.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************* **********@hotm ail.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.u tanet.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.u tanet.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************* **********@hotm ail.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.u tanet.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
2147
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
1541
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 allow todo the same, why does C++ allow it and then the C# and VB.NET don't allow? I just want to understand the logical reasoning behind this decision if there is one.
14
1998
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
4258
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 abstract new System.Data.IDbConnection Connection }
2
1475
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 extent, but causes other problems that occur with explicit definitions and also leads to much more code that is also more difficult to maintain. The new keyword is not even an option, if used in the example below Offspring on a Dog when in the...
16
3193
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
2548
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 inherit a class. The best workaround and one that I use is the new keyword and cast the base class reference, but in my opinion this is a bad practice leading to error prone code. Can someone from MS chime in on this and provide some feedback?
8
2174
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 virtual destructor virtual void draw() = 0; // A pure virtual function virtual void move() = 0; ...
3
4547
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 = base class Triangle, Square = classes derived from Shape Prism = class derived from Shape TriangularPrism, SquarePrism = classes derived from Triangle and Prism, or Square and Prism respectively
9
1872
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
8394
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8306
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8825
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8732
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8605
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
5632
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 then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4152
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4304
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
1955
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.