Topic: return types for virtual overriden functions
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Sun, 17 Aug 2003 23:14:24 +0000 (UTC) Raw View
gp1@paradise.net.nz (Graeme Prentice) writes:
> On Wed, 13 Aug 2003 16:33:29 +0000 (UTC), gp1@paradise.net.nz (Graeme
> Prentice) wrote:
>
>>
>>Or the language defines the return value to be a special case lvalue as
>>if it were created locally on the stack and allow it to bind to a non
>>const reference which would be more useful. That makes me think we need
>>another new feature - allow non const references to bind to
>>temporaries, perhaps with a new keyword or symbol :)
>>
>
> Why can't local non const references with automatic storage duration
> bind to temporaries? Bjarne Stroustrup says it's because it's highly
> error prone since the modifiable object is soon to go out of scope but
> as far as I can see its no different to any other local automatic
> object. i.e.
>
> void f1()
> {
> atype object1;
> atype & ref1 = atype(); // illegal
> atype & ref2 = function_that_returns_an_atype(); // illegal
> // ...
> }
>
> why is using ref1 or ref2 any more error prone than using object1?
Stroustrup's reasons for disallowing the binding of temporaries to
references to non-const are given in D&E 3.7 . His example looks
like this:
# void incr(int& rr) { rr++; }
#
# void g()
# {
# double ss = 1;
# incr(ss); // note: doubel passed, int expected
# // (fixed: error in Release 2.0)
# }
#
# Because of the difference in type the int& cannot refer to the
# double passed so a temporary was generated to hold an int
# initialized by ss's value. Thus, incr() modified the temporary ,
# and the result wasn't reflected back to the calling function.
However his reasons don't apply to all the situations people would
like to bind references to temporaries (such as yours). Note that
in your exampl, if the language were to allow references to
non-const to bind to temporaries, the lifetime of such temporaries
would have to be extended (as it is for temporaries to which
references to const are bound.)
There are endless threads in this and related newsgroups on this
topic, I'll let you search the archives.
I seem to recall finding some papers on the topic on the comittee's
website, but I can't seem to turn them up now.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Sat, 9 Aug 2003 21:31:06 +0000 (UTC) Raw View
On Fri, 8 Aug 2003 20:12:03 +0000 (UTC), hyrosen@mail.com (Hyman Rosen)
wrote:
>Daniel Frey wrote:
>> The caller of fun() needs to provide a memory block that can hold the
>> result. As it cannot know which of the above implementations is called,
>> it cannot know whether it needs to allocate space for an A or a B. This
>> is why the standard only allows you to return A* and B* in the above
>> example as a pointer has always the same size.
>
>As is often the case, Ada has been there and done that.
>In Ada, functions may return classwide types or variable
>sized arrays, and yet space for these is allocated on the
>stack. (The OP's case would be written in Ada as returning
>an object of type A'Class, and could then return a B.)
>
>Think of these functions as generalizations of alloca.
>Just as alloca(n) allocates an n-sized object on the stack,
>so could a call to fun(). Naturally, the Ada langugae provides
>support for this construct, with the 'Class and then ability to
>query an array for its bounds.
>
I agree with Daniel's comments in this thread. The author of the
original question in this thread doesn't want a sliced object - he wants
the full object A or B - the size of which isn't known at compile time.
The called function has to return the object on the stack in the same
manner as if the size of the object was known at compile time since the
called function can't know how it was called.
It would be possible for the called function to allocate space on the
stack for the returned object after first removing the return address
and any passed parameters and placing them higher (or lower, depending
on the machine) on the stack, then returning the address of that object
to the caller - however this would be inefficient and affect all return
values and a good enough reason not to allow what the OP wants. The
standard method for C and C++ compilers is for the caller to allocate
the space for the return value.
Maybe ADA is not as efficient as C++.
Graeme
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: hyrosen@mail.com (Hyman Rosen)
Date: Sun, 10 Aug 2003 02:23:52 +0000 (UTC) Raw View
Graeme Prentice wrote:
> Maybe ADA is not as efficient as C++.
Smile when you say that.
In Ada (not ADA), the syntax of the language allows the compiler
to tell at the call and in the function definition whether the
function returns a fixed-size object or a variable-sized object.
So any funny stack stuff can be done only when necessary.
Furthermore, the ability to do this generally replaces a need for
a dynamic memory allocation, so the Ada way is tremendously more
efficient when it's applicable.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Sun, 10 Aug 2003 17:34:01 +0000 (UTC) Raw View
On Sat, 9 Aug 2003 21:31:06 +0000 (UTC), gp1@paradise.net.nz (Graeme
Prentice) wrote:
>
>It would be possible for the called function to allocate space on the
>stack for the returned object after first removing the return address
>and any passed parameters and placing them higher (or lower, depending
>on the machine) on the stack, then returning the address of that object
>to the caller - however this would be inefficient and affect all return
>values and a good enough reason not to allow what the OP wants. The
>standard method for C and C++ compilers is for the caller to allocate
>the space for the return value.
>
>Maybe ADA is not as efficient as C++.
ok, I know, I posted without thinking for long enough here. The calling
code could query the object (as Hyman suggests) and allocate an
appropriate amount of suitably aligned space on the stack and would only
have to do this for virtual functions where the base class declared the
return type to be of type "base". This complicates life for the
compiler writer though for something not needed much. It would also
penalise code that wanted to return a base object from the virtual
function (to allow for this the compiler would have to query the
"function" for its return type size - or introduce a new keyword) -
this could well be more likely than the "covariant" case for which there
are other alternatives such as a custom allocator if dynamic memory is
too slow or static memory can't be used. Another possibility is for the
virtual function to create an object of its own type on its own stack
and make a callback.
Graeme
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Sun, 10 Aug 2003 18:02:22 +0000 (UTC) Raw View
d.frey@gmx.de (Daniel Frey) wrote in message news:<3f34d30d$0$25226$9b622d9e@news.freenet.de>...
> >> You said:
> >>
> >> <quote>The type of the result is the return type of the function being
> >> called which is known at compile tome. It is copy-initialized with the
> >> return from the overrider at run-time.</quote>
[snip]
> objected to is, that the OPs example is not legal, thus in the context
> that I was thinking about, you sentence is wrong. IIUC, you thought about
> a different code fragment and that given, you are of course right.
I just tried to state general facts regardless of any particular code
sample.
> >> or we need a different
> >> implementation model where the result is not stored in a memory area
> >> provided by the caller.
> >
> > No! Implementation has nothing to do with this. Slicing will be
> > *unavoidable*. At the point of return from A::fun() we are left with a
> > value of type A, and that is all we got. It does not make any difference
> > if the implementation retains the original return from the overrider.
> > The caller has no way to access it anyway.
>
> Given some overhead, it would be possible to do this without slicing.
> Just think of a Java-like model. Of course, this is not C++ and this is
> all I tried to say. You can fix this one point to make the OPs example
> legal and it could work without slicing - but there are lots of
> consequences for the rest of the language.
AFAIK Java objects are not allocated on the stack.
My point was that I did not see how the language could allow the
returned object to be delivered to the caller intact (even assuming
that it is not required to be converted to the return type of the
statically chosen function).
Now I can think of a (somewhat twisted) way to do it - bind the return
value to a const reference and then cast away const:
B b;
A& a = b;
const A& cra = a.fun();
A& ra = const_cast<A&>(cra);
B& rb = dynamic_cast<B&>(ra);
> > And the implementation reasons you mentioned in you original post are
> > IMHO irrelevant and misleading.
>
> I don't think so, but as it doesn't affect the result I won't argue about
> that any more.
Well, now I tend to agree that your way of looking at that might make
sense.
I don't know about the OP, but I needed some elaboration on it.
So at least for me the discussion was usefull. :)
> And given our discussion, the OP probably got more to think
> about than he wanted to :o)
I think he ran away in terror long ago. :)))
Eugene
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Hyman Rosen <hyrosen@mail.com>
Date: 11 Aug 2003 02:05:11 GMT Raw View
Graeme Prentice wrote:
> for something not needed much
You only think it's not needed much because you haven't programmed
in a language that supports it. The ability to return variable sized
arrays and objects means that in many cases, you do not need to
dynamically allocate an object, and therefore you do not need to deal
with freeing that memory, which avoids using samrt pointers, and so on.
Here's an example. Suppose I want to read in a line of text from
standard input. If I don't want to limit the length arbitrarily,
C++ offers me 'istream &getline(istream &, string&)', which will
require dynamic memory allocation. In Ada, I can do
function Get_Line return String is -- 1
Line : String (1 .. 2000); -- 2
Last : Natural;
begin
Text_IO.Get_Line (Line, Last); -- 3
if Last < Line'Last then
return Line (Line'First .. Last); -- 4
else
return Line & Get_Line; -- 5
end if;
end Get_Line;
String is an unconstrained array of characters type - that is, the
limits of the array are not specified in the code, but come from
the initialization. In line 1, we declare that Get_Line returns
such an unconstrained array, meaning that each call can return
an array of a different size. In line 2, we have a fixed size
buffer, which we declare by providing constraints for that use of
the String type. At line 3, we use Ada's built-in Get_Line, which
reads into a fixed-size buffer and also reports the number of
characters read. At line 4, we have read less than a full buffer,
so we return an array of only the characters read. At line 5, we
know that the line was longer than the buffer, so we call our
Get_Line recursively, and return an array which consists of our
full buffer concatenated with the results of the recursive call.
All of this array manipulation is done on the stack, not the heap.
In most cases, lines will be short and no recursive call will happen,
but arbitrarily long lines will be handled transparently, as long as
you have stack space available. To use this function, you just do
declare
line : String := Get_Line;
begin
-- process from line'First to line'Last
end;
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: vsimionescu@softwin.ro (Vlad Simionescu)
Date: Tue, 12 Aug 2003 17:17:56 +0000 (UTC) Raw View
philippe_mori@hotmail.com ("Philippe Mori") wrote in message news:<TrZYa.7839$pq5.1125668@news20.bellglobal.com>...
>
> > (Vlad Simionescu wrote in a previous message)
> >
> > So it seems that it could be done; the question remains whether it
> > would also be useful enough. IMHO it would be probably worth doing.
> >
I'm going to try not to argue very extensively because I'm not sure
what the real implications would be, not being very familiar with
compiling C++ code. But basically it seems like a simple idea that
should be possible to implement in a simple way, giving up some
functionality if necessary in order to keep things simple, but
retaining the basic idea.
> If this is allowed then someone will want to be able to override both
> functions instead
Of course, and every overrider must have a return type that can be
copied in that of every overridden function, as I already said.
> Also, if we add another level to the hierarchy, (a class F with a function
> returning
> an E), then maybe there would be 1 user conversion from E to C and 1 from
> C to A but 2 (user conversions) would be required from E to A (should we
> allows
> it; if so then we are not consistent with the 1 user-conversion rule and if
> not
> then the feature is partly "broken" IMO...
I'm not sure I understand. It could either be done by direct
conversion from E to A (the B::fun stub of the F object calls F::fun
directly and then converts the result) or by calling only the
immediate overrider, i.e. B::fun calls D::fun which calls F::fun. The
first way would be quicker, whereas the second one would be more
permissive, an overrider must then be compatible only with the
directly overridden methods (max. 1 for every direct base class). I
cannot say for sure but both ways should work. The only difference to
how things are now is that in the "new way" all overridden methods
must be in the virtual table of the object. Which could maybe cause
some compatibility problems at the binary level, but otherwise it
seems it should work, at least to me. And, of course, objects would
tend to be bigger.
Which in fact makes us think twice if the change really would be worth
doing. Because, of course, I cannot remember any case where it would
have made a real difference. And the workaround is simple - have a new
method D::newFun which returns C, redefine D::fun to call D::newFun
and return the returned C as an A, and call explicitly D::fun or
D::newFun as desired. Which works in most cases, but not in all, for
instance writing templates that use both fun and newFun the same way
would be much more complicated. So - maybe it would be worth it, maybe
not. If it's not a big complication I would tend to say it would be,
even if the objects grew a little. Note that if an overrider returns
the same type of value then there's no need to keep also the
overridden method in the virtual table, so the programmer would have
the choice.
> Also what will happen in multiple inheritance cases... It's easy to create
> cases that would causes ambigities if the same base appears more than once
> and each derived classes has its own return types...
I don't think there would be particular problems with multiple
inheritance if things were done consistently as above. If you know of
one, I'd like to see an example.
> And what would we do for simple type (int, double,...) Allowing that would
> IMO put a hole in the safety of the language and would prevent the compiler to
> detect many type mismatch....
Again I don't see why. Please give an example.
> And finally, if we do it, the we could apply the same arguments to supports
> it for function parameters... so it would be big language change.... with too
> many implications...
I'm going to sound boring but I'm not sure I follow. AFAIK, actual
arguments can already be passed for formal ones if they can be copied
in them. This actually is an argument for making the change - if it
works for function arguments then why not also for their return values
?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Tue, 12 Aug 2003 18:41:36 +0000 (UTC) Raw View
gp1@paradise.net.nz (Graeme Prentice) writes:
[snip]
ok, I know, I posted without thinking for long enough here. The calling
> code could query the object (as Hyman suggests) and allocate an
> appropriate amount of suitably aligned space on the stack and would only
> have to do this for virtual functions where the base class declared the
> return type to be of type "base". This complicates life for the
> compiler writer though for something not needed much.
'not needed much'?
Here's what it does:
(a) The returned object has automatic lifetime, and is therefor an
exception-safe resource.
(b) The returned object may have a size and / or type dependent on
runtime info.
Now ask yourself what returning an auto_ptr<> does. It does (a) and
(b). Is returning an auto_ptr<> a feature 'not needed much'? (Note
that I do not believe the implied assertion that returning a
variable sized object on the stack need have anything to do with
virtual functions.)
Further, the ability to return variable sized objects on the stack has
several advantages over auto_ptr<>:
(a) It doesn't requre dynamic allocation. This is crucial for
real-time, and important for embedded systems and performance
hungry systems.
(b) It works for types incomplete at the point of the function's
call. (auto_ptr<> doesn't - it has hideous undefined
behavoir.)
(c) It is dramaticly more efficient.
(d) No surpising transfer of ownership semantics.
If returning a variable sized object on the stack is 'not needed
much', IMO auto_ptr<> should never have been added to C++.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Tue, 12 Aug 2003 18:44:23 +0000 (UTC) Raw View
gp1@paradise.net.nz (Graeme Prentice) wrote in message news:<ufebjvgg15bhfpejslptkgb7iavjmiot0u@4ax.com>...
> On Sat, 9 Aug 2003 21:31:06 +0000 (UTC), gp1@paradise.net.nz (Graeme
> Prentice) wrote:
>
> >
> >It would be possible for the called function to allocate space on the
> >stack for the returned object after first removing the return address
> >and any passed parameters and placing them higher (or lower, depending
> >on the machine) on the stack, then returning the address of that object
> >to the caller - however this would be inefficient and affect all return
> >values and a good enough reason not to allow what the OP wants. The
> >standard method for C and C++ compilers is for the caller to allocate
> >the space for the return value.
> >
> >Maybe ADA is not as efficient as C++.
>
> ok, I know, I posted without thinking for long enough here. The calling
> code could query the object (as Hyman suggests) and allocate an
> appropriate amount of suitably aligned space on the stack and would only
> have to do this for virtual functions where the base class declared the
> return type to be of type "base". This complicates life for the
> compiler writer though for something not needed much. It would also
> penalise code that wanted to return a base object from the virtual
> function (to allow for this the compiler would have to query the
> "function" for its return type size - or introduce a new keyword) -
> this could well be more likely than the "covariant" case for which there
> are other alternatives such as a custom allocator if dynamic memory is
> too slow or static memory can't be used. Another possibility is for the
> virtual function to create an object of its own type on its own stack
> and make a callback.
BTW, how do you know what the OP wanted? Did he tell you in private
about that? :)
I am actually starting to like the idea. :)
As I've already mentioned, the main reason for my skepticism was that
I believed that the language does not provide means for the caller to
receive a return value of unknown type. But after some thinking I
realized that it could be done by binding the return value to a const
reference.
I think it might be implemented quite efficiently with little overhead
for the fixed-size return types, and a keyword may be introduced to
eliminate any overhead.
The caller passes a return slot for the statically chosen function
return type along with its size.
The function implementation examines the return slot size and if it is
less than the size of its return type it reallocates the return slot,
readjusts the stack frame and updates the return slot size value. If
the return type size of the function is the same as the return type
size of any function it overrides the compiler does not need to emit
the code above avoiding any overhead for regular cases.
And finally the caller examines the return slot size and obtains its
address.
Eugene
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Wed, 13 Aug 2003 16:32:18 +0000 (UTC) Raw View
On Tue, 12 Aug 2003 18:41:36 +0000 (UTC), llewelly.at@xmission.dot.com
(llewelly) wrote:
>
>If returning a variable sized object on the stack is 'not needed
> much', IMO auto_ptr<> should never have been added to C++.
>
"not needed much" is relative. There is an endless clamour for more
language level features to be added to C++. As soon as a new feature is
thought of, people say "yeah we need this". How often has this feature
been asked for in comparison to many others. I don't recall ever seeing
it mentioned in the two years I've been reading C++ newsgroups although
I don't spend as much time as yourself. There is a big difference
between adding a library feature like auto_ptr and a language level
feature. Adding language level features adds an exponential complexity
and can be done by only a few select people - 3 in the case of EDG, last
I heard. Library features like auto_ptr are implemented, tested,
debated and reviewed by the masses. They become universally available
long before they're standardised.
Actually I have no idea at all how this feature rates in comparison to
the zillion other things that get suggested. I'm an embedded programmer
myself and the idea has never occurred to me in the three years I've
been using C++, although I don't use C++ in embedded work yet but might
be soon.
Graeme
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Wed, 13 Aug 2003 16:33:29 +0000 (UTC) Raw View
On Tue, 12 Aug 2003 18:44:23 +0000 (UTC), eugalt@access4less.net (Eugene
Alterman) wrote:
>
>As I've already mentioned, the main reason for my skepticism was that
>I believed that the language does not provide means for the caller to
>receive a return value of unknown type. But after some thinking I
>realized that it could be done by binding the return value to a const
>reference.
Or the language defines the return value to be a special case lvalue as
if it were created locally on the stack and allow it to bind to a non
const reference which would be more useful. That makes me think we need
another new feature - allow non const references to bind to
temporaries, perhaps with a new keyword or symbol :)
Graeme
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Thu, 14 Aug 2003 02:21:35 +0000 (UTC) Raw View
[ I got mail system/ posting errors for this message. My apologies if
it turns up more than once.]
On Tue, 12 Aug 2003 18:41:36 +0000 (UTC), llewelly.at@xmission.dot.com
(llewelly) wrote:
[snip]
>Now ask yourself what returning an auto_ptr<> does. It does (a) and
> (b). Is returning an auto_ptr<> a feature 'not needed much'? (Note
> that I do not believe the implied assertion that returning a
> variable sized object on the stack need have anything to do with
> virtual functions.)
Why not? The whole point of returning a variable sized object rather
than always a base object or slicing is so that the derived parts can be
used. The derived part can be used locally if dynamic_cast is used
(requires a virtual function) but if this is about efficiency (as you
say), then dynamic_cast is likely undesirable which leaves manual type
decoding and static_cast (ugly - except that I have recently invented a
manual type decode that I think is "relatively" nice), or a call to a
virtual function (much better than manual type decode).
What other variable length objects are there in C++? Arrays? G++ and
C99 already allow variable length arrays and most likely standard C++
will too. This thread was about a covariant object return type in a
virtual function call, not about the return of a variable length array
from a function.
If the covariant object return is easy to implement and doesn't "ripple"
through the rest of the language then of course I'm in favour of it.
>
>Further, the ability to return variable sized objects on the stack has
> several advantages over auto_ptr<>:
>
> (a) It doesn't requre dynamic allocation. This is crucial for
> real-time, and important for embedded systems and performance
> hungry systems.
Which can use a custom allocator with preallocated memory the available
amount of which is preassigned just the same as the available stack
space has to be preassigned for the stack objects. True it's not quite
as easy but neither is estimating stack space requirement and stack
space has nowhere to go when it runs out and can't be shared between
threads.
>
> (b) It works for types incomplete at the point of the function's
> call. (auto_ptr<> doesn't - it has hideous undefined
> behavoir.)
This is not true, so to speak. The auto_ptr would be of type
auto_ptr<base>. The function call would be to a virtual function member
of base with a return type of base. You can't call a member of an
incomplete type so the base type has to be complete in both cases.
Equally, the destructor needs a complete base type in both cases.
>
> (c) It is dramaticly more efficient.
This is the same as (a)
>
> (d) No surpising transfer of ownership semantics.
Nor to someone who learns how to use auto_ptr properly. If you don't
want to lose ownership, make it const or use a non ownership
transferring version of auto_ptr ...
Which is not to say that I don't think a variable length object return
would be useful but who knows how *much* it's needed or what
complications it causes.
Graeme
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Thu, 14 Aug 2003 16:16:30 +0000 (UTC) Raw View
On Wed, 13 Aug 2003 16:33:29 +0000 (UTC), gp1@paradise.net.nz (Graeme
Prentice) wrote:
>
>Or the language defines the return value to be a special case lvalue as
>if it were created locally on the stack and allow it to bind to a non
>const reference which would be more useful. That makes me think we need
>another new feature - allow non const references to bind to
>temporaries, perhaps with a new keyword or symbol :)
>
Why can't local non const references with automatic storage duration
bind to temporaries? Bjarne Stroustrup says it's because it's highly
error prone since the modifiable object is soon to go out of scope but
as far as I can see its no different to any other local automatic
object. i.e.
void f1()
{
atype object1;
atype & ref1 = atype(); // illegal
atype & ref2 = function_that_returns_an_atype(); // illegal
// ...
}
why is using ref1 or ref2 any more error prone than using object1?
Graeme
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Thu, 14 Aug 2003 23:58:39 +0000 (UTC) Raw View
gp1@paradise.net.nz (Graeme Prentice) wrote in message news:<1rnmjvc02p73390g3m19t4pg7pfjf4hcuu@4ax.com>...
> On Wed, 13 Aug 2003 16:33:29 +0000 (UTC), gp1@paradise.net.nz (Graeme
> Prentice) wrote:
>
> >
> >Or the language defines the return value to be a special case lvalue as
> >if it were created locally on the stack and allow it to bind to a non
> >const reference which would be more useful. That makes me think we need
> >another new feature - allow non const references to bind to
> >temporaries, perhaps with a new keyword or symbol :)
> >
>
> Why can't local non const references with automatic storage duration
> bind to temporaries? Bjarne Stroustrup says it's because it's highly
> error prone since the modifiable object is soon to go out of scope but
> as far as I can see its no different to any other local automatic
> object. i.e.
>
> void f1()
> {
> atype object1;
> atype & ref1 = atype(); // illegal
> atype & ref2 = function_that_returns_an_atype(); // illegal
> // ...
> }
>
> why is using ref1 or ref2 any more error prone than using object1?
You might want to read this:
http://std.dkuug.dk/JTC1/SC22/WG21/docs/papers/2002/n1377.htm
Eugene
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Sun, 17 Aug 2003 05:29:14 +0000 (UTC) Raw View
gp1@paradise.net.nz (Graeme Prentice) writes:
> [ I got mail system/ posting errors for this message. My apologies if
> it turns up more than once.]
>
>
> On Tue, 12 Aug 2003 18:41:36 +0000 (UTC), llewelly.at@xmission.dot.com
> (llewelly) wrote:
>
>
> [snip]
>
>>Now ask yourself what returning an auto_ptr<> does. It does (a) and
>> (b). Is returning an auto_ptr<> a feature 'not needed much'? (Note
>> that I do not believe the implied assertion that returning a
>> variable sized object on the stack need have anything to do with
>> virtual functions.)
>
> Why not? The whole point of returning a variable sized object rather
> than always a base object or slicing is so that the derived parts can be
> used.
What I meant is that function returning the runtime-sized object (I'm
saying runtime-sized now because the object's size is dependent on
runtime info, but the size doesn't vary after its creation. ) need
not be virtual. The object itself would need to support rtti -
which in current c++ is synonomous with having at least one
virtual function. I see now this was not at all clear in my post,
I appologize for the confusion.
> The derived part can be used locally if dynamic_cast is used
> (requires a virtual function) but if this is about efficiency (as you
> say),
Efficiency is the least important of its advantages. Dynamic
allocation is error-prone. auto_ptr<> is error-prone (in the hands
of most people I've worked with, anyway). Returning a runtime
sized object eliminates a source of error. Predictability is also
more important than efficiency; new typically has unpredictable
execution time.
> then dynamic_cast is likely undesirable which leaves manual type
> decoding and static_cast (ugly - except that I have recently invented a
> manual type decode that I think is "relatively" nice), or a call to a
> virtual function (much better than manual type decode).
>
> What other variable length objects are there in C++? Arrays? G++ and
> C99 already allow variable length arrays and most likely standard C++
> will too. This thread was about a covariant object return type in a
> virtual function call, not about the return of a variable length array
> from a function.
I didn't consider variable length arrays, because, like you, I view
them as likely to become part of C++ some day.
>
> If the covariant object return is easy to implement and doesn't "ripple"
> through the rest of the language then of course I'm in favour of it.
Good point. If it is found to have a ripple effect, (and it may - I
can't tell) I may change my mind about supporting it.
Since Ada95 provides this feature already, the feature's effect on
Ada95's definition should be examined.
>>
>>Further, the ability to return variable sized objects on the stack has
>> several advantages over auto_ptr<>:
>>
>> (a) It doesn't requre dynamic allocation. This is crucial for
>> real-time, and important for embedded systems and performance
>> hungry systems.
>
> Which can use a custom allocator with preallocated memory the available
> amount of which is preassigned just the same as the available stack
> space has to be preassigned for the stack objects. True it's not quite
> as easy but neither is estimating stack space requirement and stack
> space has nowhere to go when it runs out and can't be shared between
> threads.
Agreed.
>
>>
>> (b) It works for types incomplete at the point of the function's
>> call. (auto_ptr<> doesn't - it has hideous undefined
>> behavoir.)
>
> This is not true, so to speak.
I think the first statement is true. However on further consideration,
I agree the parenthetical statement is not; as you say,
auto_ptr<base> is the proper equivalent, and while base must be
complete, the derived types needn't be - they do not even need to
be declared or defined in the same module. So (b) isn't an
advantage over auto_ptr<base>. My error.
> The auto_ptr would be of type
> auto_ptr<base>. The function call would be to a virtual function member
> of base with a return type of base. You can't call a member of an
> incomplete type so the base type has to be complete in both cases.
>
> Equally, the destructor needs a complete base type in both cases.
>>
>> (c) It is dramaticly more efficient.
>
> This is the same as (a)
No. Dynamic allocation has several other costs besides
efficiency. It is error-prone, and it has unpredictable (or
difficult to predict) execution time. (c) does overlap with (a),
but it is not the same.
>>
>> (d) No surpising transfer of ownership semantics.
>
> Nor to someone who learns how to use auto_ptr properly. If you don't
> want to lose ownership, make it const or use a non ownership
> transferring version of auto_ptr ...
Of course. But I must say I do not see either of these strategies used
by many of the auto_ptr-using co-workers I have had.
>
> Which is not to say that I don't think a variable length object return
> would be useful but who knows how *much* it's needed or what
> complications it causes.
I think it replaces all uses of scoped_ptr and most uses of
auto_ptr. It's also useful in areas where neither of those could
be used, and where they would have to be used with special-purpose
new.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Wed, 6 Aug 2003 15:03:31 +0000 (UTC) Raw View
Eugene Alterman wrote:
>=20
> Well, let us generalize the concept of covariance and call it weak
> covariance:
> If a function D::f overrides a function B::f, the return types of the
> functions are weakly covariant if a return value from B::f can be
> initialized with a return value from D::f.
> It is easy to see that covariance implies weak covariance.=20
> Replace "covariant" in 10.3.5 with "weakly covariant"
> You can see then that if A doesn't have a copy-ctor than return types
> of B::fun and A::fun are not weakly covariant and B is ill-formed.
Eugene,
please allow me to recap the thread so far, correct me if I'm wrong:
The OP asked why his example is "not allowed". This clearly addresses=20
the C++ programming language as it currently is as it was posted to=20
comp.std.c++.
I answered that (AFAIK) the root of the trouble is, that the function=20
should be able to store its result in a memory area provided by the=20
caller, which won't work for the OPs example. The language needn't=20
prescribe it, but I guess the language's authors don't want to render it=20
impossible as it is a very common and fast technique. Maybe you just=20
misread this as that I was saying that it's technically impossible, but=20
that wasn't my intend.
You said:
<quote>The type of the result is the return type of the function being=20
called which is known at compile tome. It is copy-initialized with the
return from the overrider at run-time.</quote>
IMHO, both sentences are wrong. I showed an example (p->fun()) where the=20
compiler doesn't know the return type at compile time and the second=20
sentence is not true for the current C++ language. This (especially the=20
last sentence) suggests to me that you think that the OPs example is=20
legal. If you are talking about a hypothetical language extension,=20
please say so, otherwise I'll always assume you are talking about=20
ISO/IEC 14882-1998, which, btw, does not have 10.3.5 - it's 10.3/5 ;)
During the ongoing discussion, we came to the conclusion that *if* the=20
above example would be legal, slicing would occur or we need a different=20
implementation model where the result is not stored in a memory area=20
provided by the caller. Slicing is a bad thing as it results in=20
supprising behaviour for the user and it's also inefficient (yes, I am=20
serious about the run-time overhead!). As a bonus, you need an=20
accessible copy-ctor for A, which is not needed for the current code.
Using another implementation leads to even more run-time costs which I=20
would be deeply concerned about. All these are consequences of trying to=20
make the OPs example legal despite what I described in my first answer.=20
So, once again: It's not technically impossible, but it's a very bad idea.
I hope I expressed myself clearly now. :)
Regards, Daniel
--=20
Daniel Frey
aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Wed, 6 Aug 2003 16:07:45 +0000 (UTC) Raw View
dan.r.mcleran@seagate.com (Dan McLeran) wrote in message news:<19b0e504.0308051407.19d7e593@posting.google.com>...
> > What about a copy-ctor that the developer explicitly declares and does
> > not define? Say,
> >
> > class A
> > {
> > A(const A &); // declaration only, no definition anywhere
> > };
> >
> > This class does not have a copy-ctor.
> >
> > Randy.
>
> I don't believe that this is valid code. I believe that if you provide
> a copy ctr method declaration, you must provide implementation as
> well. I put together a small file and got a linker error, with gcc &
> MSVCSP5 anyways:
>
> #include <iostream>
> #include <stdlib.h>
>
> using namespace std;
>
> class A
> {
> public:
> A()
> {
> cout<<"Ctr"<<endl;
> }
> A(A const& copy);
> };
>
> int main(int argc, char *argv[])
> {
> A a;
> A b(a); //comment this line out and you're ok
> //the compiler generates a default copy ctr
>
> system("PAUSE");
> return 0;
> }
>
> gcc gave a linker error:
>
> main.o(.text+0x3f):main.cpp: undefined reference to `A::A(A const&)'
>
> MSVCSP5 gave this linker error:
>
> main.obj : error LNK2001: unresolved external symbol "public:
> __thiscall A::A(class A const &)" (??0A@@QAE@ABV0@@Z)
> Debug/NoCopyCtr.exe : fatal error LNK1120: 1 unresolved externals
>
> ---
It is indeed valid code, and the linker error you see is exactly the
desired effect. The class A deliberately did not provide a copy ctor,
so you cannot copy objects of class A, which was rather the point.
This is a useful idiom for classes that correspond to things that
cannot be copied. Say a mutex or some other system resource, or a
singleton object, or whatever. When the situation is such that
copying makes no sense, this is the idiom used to prevent it.
Randy.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andys@despammed.com (Andy Sawyer)
Date: Thu, 7 Aug 2003 02:50:16 +0000 (UTC) Raw View
In article <bgq9u0$gqh$1@swifty.westend.com>,
on Wed, 6 Aug 2003 15:03:31 +0000 (UTC),
daniel.frey@aixigo.de (Daniel Frey) wrote:
> If you are talking about a hypothetical language extension, please say
> so, otherwise I'll always assume you are talking about ISO/IEC
> 14882-1998, which, btw, does not have 10.3.5 - it's 10.3/5 ;)
I can't speak for Eugene, but some of us are talking about the language
as defined by ISO/IEC 14882:2003(E)....
Regards,
Andy S
--
"Light thinks it travels faster than anything but it is wrong. No matter
how fast light travels it finds the darkness has always got there first,
and is waiting for it." -- Terry Pratchett, Reaper Man
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dan.r.mcleran@seagate.com (Dan McLeran)
Date: Fri, 8 Aug 2003 03:22:57 +0000 (UTC) Raw View
> > class A {
> > public:
> > A() {
> > std::cout << "Ctr" << std::endl;
> > }
>
> > A(A const& copy);
> > };
> >
> > int main(int argc, char *argv[]) {
> > A a;
> > A b(a); //comment this line out and you're ok
> > //the compiler generates a default copy ctr
>
> The difference here is that you are using the copy constructor. If you're not
> using it, the compiler won't require it and the linker won't go looking for it
> either. The comment "the compiler generates a default copy ctr" is incorrect. In
> your example, no copy constructor is generated by the compiler.
>
Oops! You're quite right, I fat-fingered my example. It should have been:
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
public:
A()
{
cout<<"Ctr"<<endl;
}
A(A const& copy);//comment this line out and you're ok
//the compiler generates a default copy ctr
};
int main(int argc, char *argv[])
{
A a;
A b(a);
system("PAUSE");
return 0;
}
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dan.r.mcleran@seagate.com (Dan McLeran)
Date: Fri, 8 Aug 2003 05:00:59 +0000 (UTC) Raw View
You guys are correct. I misspoke when I said that this was not valid
code. I should have said that given the original posters desire to
return by value, hiding the copy ctor is not a valid option.
Thanks,
Dan McLeran
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Fri, 8 Aug 2003 18:27:26 +0000 (UTC) Raw View
daniel.frey@aixigo.de (Daniel Frey) wrote in message news:<bgq9u0$gqh$1@swifty.westend.com>...
> You said:
>
> <quote>The type of the result is the return type of the function being
> called which is known at compile tome. It is copy-initialized with the
> return from the overrider at run-time.</quote>
I am sorry if my poor choice of terms led to confusion.
By "function being called" I meant the statically chosen function
rather then the function that is actually called (the final
overrider).
Let me put more precisely what I tried to say in the above quote:
According to ISO/IEC 14882 5.2.2/4
"The value of a function call is the value returned by the called
function except in a virtual function call if the return type of the
final overrider is different from the return type of the statically
chosen function, the value returned from the final overrider is
converted to the return type of the statically chosen function."
So in any case the type of the return value that the caller receives
is known at compile time.
Eugene
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: hyrosen@mail.com (Hyman Rosen)
Date: Fri, 8 Aug 2003 20:12:03 +0000 (UTC) Raw View
Daniel Frey wrote:
> The caller of fun() needs to provide a memory block that can hold the
> result. As it cannot know which of the above implementations is called,
> it cannot know whether it needs to allocate space for an A or a B. This
> is why the standard only allows you to return A* and B* in the above
> example as a pointer has always the same size.
As is often the case, Ada has been there and done that.
In Ada, functions may return classwide types or variable
sized arrays, and yet space for these is allocated on the
stack. (The OP's case would be written in Ada as returning
an object of type A'Class, and could then return a B.)
Think of these functions as generalizations of alloca.
Just as alloca(n) allocates an n-sized object on the stack,
so could a call to fun(). Naturally, the Ada langugae provides
support for this construct, with the 'Class and then ability to
query an array for its bounds.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Fri, 8 Aug 2003 23:28:54 +0000 (UTC) Raw View
daniel.frey@aixigo.de (Daniel Frey) wrote in message news:<bgq9u0$gqh$1@swifty.westend.com>...
> please allow me to recap the thread so far, correct me if I'm wrong:
Now it turns out there has been a major communication problem all
along.
All right. Let us try to set the whole thing straight.
> The OP asked why his example is "not allowed". This clearly addresses
> the C++ programming language as it currently is as it was posted to
> comp.std.c++.
Of course.
> I answered that (AFAIK) the root of the trouble is, that the function
> should be able to store its result in a memory area provided by the
> caller, which won't work for the OPs example.
And here I disagree. It still can work the same way for that example!
See below.
> You said:
>
> <quote>The type of the result is the return type of the function being
> called which is known at compile tome. It is copy-initialized with the
> return from the overrider at run-time.</quote>
>
> IMHO, both sentences are wrong. I showed an example (p->fun()) where the
> compiler doesn't know the return type at compile time
The first sentence simply states that the return type of a function
*THAT IS BEING CALLED* is known at compile time. The type of a
function call result is the (static) return type from the function
being called - not the (dynamic) return type from the overrider!
> and the second
> sentence is not true for the current C++ language.
Huh???... Wait a minute...
Oh, I think I've got it! <g>
Excuse me if I am wrong, but I suspect that you are confusing
copy-initialization and initialization using a copy constructor.
Copy-initialization is just an initialization of type "T x = a;" that
occurs in various contexts, in particular in function return. It does
not imply use of a copy constructor.
See ISO/IEC 14882 8.5/12: ( did I get that slash right this time? :)
<quote>
The initialization that occurs in argument passing, function return,
throwing an exception (15.1), handling an exception (15.3), and
brace-enclosed initializer lists (8.5.1) is called copy-initialization
and is equivalent to the form
T x = a;
<\quote>
> This (especially the
> last sentence) suggests to me that you think that the OPs example is
> legal.
Wow! We've been talking in different languages without an interpreter.
:)
> During the ongoing discussion, we came to the conclusion that *if* the
> above example would be legal, slicing would occur
Right.
> or we need a different
> implementation model where the result is not stored in a memory area
> provided by the caller.
No! Implementation has nothing to do with this. Slicing will be
*unavoidable*. At the point of return from A::fun() we are left with a
value of type A, and that is all we got. It does not make any
difference if the implementation retains the original return from the
overrider. The caller has no way to access it anyway.
> Slicing is a bad thing as it results in
> supprising behaviour for the user and it's also inefficient (yes, I am
> serious about the run-time overhead!).
If you mean a wrapper for transition from the overrider return type to
the original return type then observe that with multiple inheritance
you might need a similar wrapper for covariant return types because
base class pointer value may be different from derived class pointer
value for the same object.
> So, once again: It's not technically impossible, but it's a very bad idea.
I could not agree more.
Let me reiterate my point once again.
To address the original question we need to ask ourselves:
1. Can the language be extended in a way that would make the code
valid?
2. If yes what do we get?
And we answer:
1. Yes, it can.
2. Nothing valuable.
We get those answers reasoning strictly within the language framework.
That is all we need.
And the implementation reasons you mentioned in you original post are
IMHO irrelevant and misleading.
I hope I expressed myself clearly too. :))
Eugene.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: vsimionescu@softwin.ro (Vlad Simionescu)
Date: Fri, 8 Aug 2003 23:29:06 +0000 (UTC) Raw View
daniel.frey@aixigo.de (Daniel Frey) wrote in message news:<bgq9u0$gqh$1@swifty.westend.com>...
> Eugene Alterman wrote:
> >
> > Well, let us generalize the concept of covariance and call it weak
> > covariance:
> > ...
> Eugene,
>
> ...
>
> You said:
>
> <quote>The type of the result is the return type of the function being
> called which is known at compile tome. It is copy-initialized with the
> return from the overrider at run-time.</quote>
>
> IMHO, both sentences are wrong. I showed an example (p->fun()) where the
> compiler doesn't know the return type at compile time and the second
> sentence is not true for the current C++ language.
I think I agree with Eugene, in that allowing an overrider function to
return an object type that can be copied into the one of the
overridden function could be stated by the standard (which is not the
case with the current standard, of course). I also think it could be
also implemented without significant time overhead or slicing any
objects, and of course by returning the final result to the caller in
its own supplied memory area, which is on the stack.
The idea, as he put it, is:
class B
{
public:
...
virtual A fun (void);
...
};
class D: public B
{
public:
...
virtual C fun (void);
...
};
where an object of type C can be copied legally into one of type A, by
a copy constructor. The assignment of C to A must be legal and known
by the compiler only when compiling the class D, not in the context of
the caller of B::fun or D::fun.
Now, if I have an object d of class D and I access it as a B&, that is
I call B::fun on it, what happens is that B::fun calls D::fun, then
copies the result into an A object and returns it. Of course, the
virtual table of D must retain both functions. When d is accessed as a
D object, D::fun is called directly and returns a C object, so
everything is OK.
It should be noted that this must be possible for any method replaced
by D::fun, that is if D derives from one or more other classes,
posibly by multiple inheritance, any virtual fun (void) method in any
base class must return something into which an object of type C can be
copied, in the context of class D, otherwise the declaration of D::fun
is illegal.
I guess there wouldn't be any backwards compatibility problems,
because any legal code would continue to work.
So it seems that it could be done; the question remains whether it
would also be useful enough. IMHO it would be probably worth doing.
Regards
Vlad Simionescu
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: philippe_mori@hotmail.com ("Philippe Mori")
Date: Sat, 9 Aug 2003 07:11:54 +0000 (UTC) Raw View
> The idea, as he put it, is:
>
> class B
> {
> public:
> ...
> virtual A fun (void);
> ...
> };
>
> class D: public B
> {
> public:
> ...
> virtual C fun (void);
> ...
> };
>
> where an object of type C can be copied legally into one of type A, by
> a copy constructor. The assignment of C to A must be legal and known
> by the compiler only when compiling the class D, not in the context of
> the caller of B::fun or D::fun.
>
>
> I guess there wouldn't be any backwards compatibility problems,
> because any legal code would continue to work.
>
> So it seems that it could be done; the question remains whether it
> would also be useful enough. IMHO it would be probably worth doing.
>
If this is allowed then someone will want to be able to override both
functions
instead (maybe in a derived classe) maybe because he can create the object
more efficiently. i.e. someone would then like to have 2 overloads, one
returning
a A object and another a C object.
Also, if we add another level to the hierarchy, (a class F with a function
returning
an E), then maybe there would be 1 user conversion from E to C and 1 from
C to A but 2 (user conversions) would be required from E to A (should we
allows
it; if so then we are not consistent with the 1 user-conversion rule and if
not
then the feature is partly "broken" IMO...
Also, what should be done if a derived class wants to override the original
function... Someone would have to know that return type was changed in
between... since I think we will only look up to the closer parent where the
function
is defined.
Also what will happen in multiple inheritance cases... It's easy to create
cases that
would causes ambigities if the same base appears more than once and each
derived
classes has its own return types...
And what would we do for simple type (int, double,...) Allowing that would
IMO
put a hole in the safety of the language and would prevent the compiler to
detect
many type mismatch....
And finally, if we do it, the we could apply the same arguments to supports
it for
function parameters... so it would be big language change.... with too many
implications...
> Regards
>
> Vlad Simionescu
>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: d.frey@gmx.de (Daniel Frey)
Date: Sat, 9 Aug 2003 21:31:03 +0000 (UTC) Raw View
On Sat, 09 Aug 2003 01:28:54 +0200, Eugene Alterman wrote:
> daniel.frey@aixigo.de (Daniel Frey) wrote in message
> news:<bgq9u0$gqh$1@swifty.westend.com>...
>> please allow me to recap the thread so far, correct me if I'm wrong:
>
> Now it turns out there has been a major communication problem all along.
> All right. Let us try to set the whole thing straight.
Actually I think that we agree on the technical aspects, it's really just
a language problem :)
>> You said:
>>
>> <quote>The type of the result is the return type of the function being
>> called which is known at compile tome. It is copy-initialized with the
>> return from the overrider at run-time.</quote>
>>
>> IMHO, both sentences are wrong. I showed an example (p->fun()) where
>> the compiler doesn't know the return type at compile time
>
> The first sentence simply states that the return type of a function
> *THAT IS BEING CALLED* is known at compile time. The type of a function
> call result is the (static) return type from the function being called -
> not the (dynamic) return type from the overrider!
To me, the term "that is being called" always refers to the overrider, as
the is, well, the function that is actually called. But I now understand
what you mean when you used this term.
>> and the second
>> sentence is not true for the current C++ language.
>
> Huh???... Wait a minute...
> Oh, I think I've got it! <g>
Again, I think I should clarify what I understood. I thought that you
were suggesting that in the OPs example, "it [the result] is
copy-initialized with the return from the overrider at run-time". What I
objected to is, that the OPs example is not legal, thus in the context
that I was thinking about, you sentence is wrong. IIUC, you thought about
a different code fragment and that given, you are of course right.
>> This (especially the
>> last sentence) suggests to me that you think that the OPs example is
>> legal.
>
> Wow! We've been talking in different languages without an interpreter.
> :)
>
>> During the ongoing discussion, we came to the conclusion that *if* the
>> above example would be legal, slicing would occur
>
> Right.
>
>> or we need a different
>> implementation model where the result is not stored in a memory area
>> provided by the caller.
>
> No! Implementation has nothing to do with this. Slicing will be
> *unavoidable*. At the point of return from A::fun() we are left with a
> value of type A, and that is all we got. It does not make any difference
> if the implementation retains the original return from the overrider.
> The caller has no way to access it anyway.
Given some overhead, it would be possible to do this without slicing.
Just think of a Java-like model. Of course, this is not C++ and this is
all I tried to say. You can fix this one point to make the OPs example
legal and it could work without slicing - but there are lots of
consequences for the rest of the language.
>> So, once again: It's not technically impossible, but it's a very bad
>> idea.
>
> I could not agree more.
>
> Let me reiterate my point once again.
>
> To address the original question we need to ask ourselves: 1. Can the
> language be extended in a way that would make the code valid? 2. If yes
> what do we get?
>
> And we answer:
> 1. Yes, it can.
> 2. Nothing valuable.
100% agreed.
> We get those answers reasoning strictly within the language framework.
> That is all we need.
>
> And the implementation reasons you mentioned in you original post are
> IMHO irrelevant and misleading.
I don't think so, but as it doesn't affect the result I won't argue about
that any more.
> I hope I expressed myself clearly too. :))
I think so. And given our discussion, the OP probably got more to think
about than he wanted to :o)
Regards, Daniel
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: vvenkatagr@yahoo.com (venkat)
Date: Fri, 1 Aug 2003 06:31:21 +0000 (UTC) Raw View
Why is this not allowed as against using reference types for return?
class A{
public:
virtual A fun(){
}
};
class B :public A{
public:
B fun(){
}
};
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Fri, 1 Aug 2003 15:21:14 +0000 (UTC) Raw View
venkat wrote:
> Why is this not allowed as against using reference types for return?
>=20
> class A{
> public:
> virtual A fun(){
> }
> =20
> };
>=20
> class B :public A{=20
> public:
> B fun(){
> }
> };
The caller of fun() needs to provide a memory block that can hold the=20
result. As it cannot know which of the above implementations is called,=20
it cannot know whether it needs to allocate space for an A or a B. This=20
is why the standard only allows you to return A* and B* in the above=20
example as a pointer has always the same size.
Regards, Daniel
--=20
Daniel Frey
aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dan.r.mcleran@seagate.com (Dan McLeran)
Date: Fri, 1 Aug 2003 15:21:27 +0000 (UTC) Raw View
vvenkatagr@yahoo.com (venkat) wrote in message news:<fe69c8ea.0307312225.567922ec@posting.google.com>...
> Why is this not allowed as against using reference types for return?
>
> class A{
> public:
> virtual A fun(){
> }
>
> };
>
> class B :public A{
> public:
> B fun(){
> }
> };
See the standard 10.3.5:
5 The return type of an overriding function shall be either identical to
the return type of the overridden function or covariant with the
classes of the functions.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Sat, 2 Aug 2003 18:01:11 +0000 (UTC) Raw View
dan.r.mcleran@seagate.com (Dan McLeran) wrote in message news:<19b0e504.0308010608.62f44796@posting.google.com>...
> vvenkatagr@yahoo.com (venkat) wrote in message news:<fe69c8ea.0307312225.567922ec@posting.google.com>...
> > Why is this not allowed as against using reference types for return?
> >
> > class A{
> > public:
> > virtual A fun(){
> > }
> >
> > };
> >
> > class B :public A{
> > public:
> > B fun(){
> > }
> > };
>
> See the standard 10.3.5:
>
> 5 The return type of an overriding function shall be either identical to
> the return type of the overridden function or covariant with the
> classes of the functions.
The question was why the standard says this; the original poster was
clearly already aware of the fact that the code is illegal.
In particular, the key question is, why does the standard restrict
covariance to pointers and references; why can't it apply to actual
objects of class type? The other responder has already answered that
question, so I won't bother.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Mon, 4 Aug 2003 01:04:12 +0000 (UTC) Raw View
kuyper@wizard.net (James Kuyper) wrote in message news:<8b42afac.0308020918.7445f0a1@posting.google.com>...
> dan.r.mcleran@seagate.com (Dan McLeran) wrote in message news:<19b0e504.0308010608.62f44796@posting.google.com>...
> > vvenkatagr@yahoo.com (venkat) wrote in message news:<fe69c8ea.0307312225.567922ec@posting.google.com>...
> > > Why is this not allowed as against using reference types for return?
> > >
> > > class A{
> > > public:
> > > virtual A fun(){
> > > }
> > >
> > > };
> > >
> > > class B :public A{
> > > public:
> > > B fun(){
> > > }
> > > };
> >
> > See the standard 10.3.5:
> >
> > 5 The return type of an overriding function shall be either identical to
> > the return type of the overridden function or covariant with the
> > classes of the functions.
>
> The question was why the standard says this; the original poster was
> clearly already aware of the fact that the code is illegal.
>
> In particular, the key question is, why does the standard restrict
> covariance to pointers and references; why can't it apply to actual
> objects of class type? The other responder has already answered that
> question, so I won't bother.
I would not consider that answer particularly accurate though.
The type of the result is the return type of the function being called
which is known at compile tome. It is copy-initialized with the
return from the overrider at run-time.
A pointer or a reference to a base class can be downcasted to a
pointer/reference to the run-time type of the object it refers to. But
initializing an object with an object of the derived class does not
make sense since the latter would be sliced and irreversibly lost.
Eugene.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Mon, 4 Aug 2003 17:02:21 +0000 (UTC) Raw View
Eugene Alterman wrote:
> kuyper@wizard.net (James Kuyper) wrote in message news:<8b42afac.030802=
0918.7445f0a1@posting.google.com>...
>=20
>>The other responder has already answered that
>>question, so I won't bother.
>=20
> I would not consider that answer particularly accurate though.
> The type of the result is the return type of the function being called
> which is known at compile tome. It is copy-initialized with the
> return from the overrider at run-time.
What if A doesn't have a copy-ctor?
> A pointer or a reference to a base class can be downcasted to a
> pointer/reference to the run-time type of the object it refers to. But
> initializing an object with an object of the derived class does not
> make sense since the latter would be sliced and irreversibly lost.
What about the context of the call? Was it called from an A or from an=20
B? If it's a B
B b;
b.fun();
it should return a B without slicing. If the calling context is A,=20
slicing occurs. Slicing is bad, yes, but you'd also create an overhead=20
as the function called from A's vtable needs to be a different function=20
as the one in B's vtable. Probably just a small stub but anyway.
There are problems other than the one I mentioned in my first answer,=20
but in my eyes these problems are just a consequence of the basic=20
assumption that the caller provides the memory for the return value (the=20
return slot) and what would happen if we try to make the OP's code legal.
Regards, Daniel
--=20
Daniel Frey
aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sebmol@yahoo.com ("Sebastian Moleski")
Date: Tue, 5 Aug 2003 01:00:35 +0000 (UTC) Raw View
>"Daniel Frey" <daniel.frey@aixigo.de> wrote in message
news:bgl8bj$sor$1@swifty.westend.com...
>Eugene Alterman wrote:
>> kuyper@wizard.net (James Kuyper) wrote in message
news:<8b42afac.0308020918.7445f0a1@posting.google.com>...
>>
>>>The other responder has already answered that
>>>question, so I won't bother.
>>
>> I would not consider that answer particularly accurate though.
>> The type of the result is the return type of the function being called
>> which is known at compile tome. It is copy-initialized with the
>> return from the overrider at run-time.
> What if A doesn't have a copy-ctor?
That's impossible. Every object has a copy-constructor whether it is implictly
defined by the compiler or explicitly by the class developer. That copy
constructor might not be accessible though.
sm
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Tue, 5 Aug 2003 02:22:59 +0000 (UTC) Raw View
daniel.frey@aixigo.de (Daniel Frey) wrote in message news:<bgl8bj$sor$1@swifty.westend.com>...
> Eugene Alterman wrote:
> > kuyper@wizard.net (James Kuyper) wrote in message news:<8b42afac.030802
> 0918.7445f0a1@posting.google.com>...
> >
> >>The other responder has already answered that
> >>question, so I won't bother.
> >
> > I would not consider that answer particularly accurate though.
> > The type of the result is the return type of the function being called
> > which is known at compile tome. It is copy-initialized with the
> > return from the overrider at run-time.
>
> What if A doesn't have a copy-ctor?
Then it may not be used as a pass-by-value parameter or return type.
> > A pointer or a reference to a base class can be downcasted to a
> > pointer/reference to the run-time type of the object it refers to. But
> > initializing an object with an object of the derived class does not
> > make sense since the latter would be sliced and irreversibly lost.
>
> What about the context of the call? Was it called from an A or from an
> B? If it's a B
>
> B b;
> b.fun();
>
> it should return a B without slicing. If the calling context is A,
> slicing occurs.
It does not matter whether it is called "from A" or "from B" (whatever
that means). In your example the virtual function mechanism does not
need to be employed at all since the most derived object type (and the
final overrider) is known at compile time. And if you call a virtual
function via a pointer or a reference there is no way to tell at
compile time what the final overrider would be.
> Slicing is bad, yes, but you'd also create an overhead
> as the function called from A's vtable needs to be a different function
> as the one in B's vtable.
What do you mean?
> Probably just a small stub but anyway.
No vtable thunk is necessary if there is no multiple inheritance.
OK, I don't know what you are talking about.
> There are problems other than the one I mentioned in my first answer,
What are they?
> but in my eyes these problems are just a consequence of the basic
> assumption that the caller provides the memory for the return value (the
> return slot)
You don't need to make any assumptions other than those explicitely
stated by the standard.
> and what would happen if we try to make the OP's code legal.
Nothing terrible will happen. It just would be totally useless.
Eugene
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: google@dalvander.com (Anders Dalvander)
Date: Tue, 5 Aug 2003 14:37:23 +0000 (UTC) Raw View
sebmol@yahoo.com ("Sebastian Moleski") wrote in message news:<vitvnbs20nqb28@corp.supernews.com>...
> > What if A doesn't have a copy-ctor?
>
> That's impossible. Every object has a copy-constructor whether it is implictly
> defined by the compiler or explicitly by the class developer. That copy
> constructor might not be accessible though.
What if the class has member variable of another class that has a non
accessible cctor, then the compiler can't define it implictly nor can
the developer define it explicitly. Is that cctor also non accessible
or non existent?
class foo
{
foo(const foo&); // private cctor
};
class bar
{
foo _foo;
// Does bar have a cctor or not?
};
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Tue, 5 Aug 2003 14:37:54 +0000 (UTC) Raw View
Eugene Alterman wrote:
> daniel.frey@aixigo.de (Daniel Frey) wrote in message news:<bgl8bj$sor$1=
@swifty.westend.com>...
>=20
>>What if A doesn't have a copy-ctor?
>=20
> Then it may not be used as a pass-by-value parameter or return type.
And what does it mean for the example?
>>What about the context of the call? Was it called from an A or from an=20
>>B? If it's a B
>>
>>B b;
>>b.fun();
>>
>>it should return a B without slicing. If the calling context is A,=20
>>slicing occurs.
>=20
> It does not matter whether it is called "from A" or "from B" (whatever
> that means). In your example the virtual function mechanism does not
It means:
A a;
B b;
A a2 =3D a.fun();
B b2 =3D b.fun(); // No slicing here, no copy-ctor of A required
A a3 =3D b.fun(); // B returned, copy-ctor required, slicing
A* p =3D &b;
A a4 =3D p->fun(); // Huh??
The last call is the problem: p is of type A*, so the return type of=20
p->fun() is A. But B::fun() is called, which return a B. Without a stub,=20
how do you think this works? Compare it to 'b2' and 'a3'...
> need to be employed at all since the most derived object type (and the
> final overrider) is known at compile time. And if you call a virtual
> function via a pointer or a reference there is no way to tell at
> compile time what the final overrider would be.
Should the language have separate rules for different cases? Should it=20
describle in detail how smart a compiler must be to find out the final=20
overriders?
>>and what would happen if we try to make the OP's code legal.
>=20
> Nothing terrible will happen. It just would be totally useless.
The standard doesn't allow this dangerous code (althought it might not=20
be useless depending on the context). It's just a trap that is avoided.=20
So what's your point? Are you arguing that the code should be legal=20
because "nothing terrible will happen"? Also, instead of complaining=20
about my inaccurate answer, why don't you provide a better and accurate=20
answer? :)
Regards, Daniel
--=20
Daniel Frey
aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Tue, 5 Aug 2003 14:38:44 +0000 (UTC) Raw View
sebmol@yahoo.com ("Sebastian Moleski") wrote in message news:<vitvnbs20nqb28@corp.supernews.com>...
> >"Daniel Frey" <daniel.frey@aixigo.de> wrote in message
> news:bgl8bj$sor$1@swifty.westend.com...
> >Eugene Alterman wrote:
> >> kuyper@wizard.net (James Kuyper) wrote in message
> news:<8b42afac.0308020918.7445f0a1@posting.google.com>...
> >>
> >>>The other responder has already answered that
> >>>question, so I won't bother.
> >>
> >> I would not consider that answer particularly accurate though.
> >> The type of the result is the return type of the function being called
> >> which is known at compile tome. It is copy-initialized with the
> >> return from the overrider at run-time.
>
> > What if A doesn't have a copy-ctor?
>
> That's impossible. Every object has a copy-constructor whether it is implictly
> defined by the compiler or explicitly by the class developer. That copy
> constructor might not be accessible though.
>
> sm
>
What about a copy-ctor that the developer explicitly declares and does
not define? Say,
class A
{
A(const A &); // declaration only, no definition anywhere
};
This class does not have a copy-ctor.
Randy.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sebmol@yahoo.com ("Sebastian Moleski")
Date: Tue, 5 Aug 2003 23:38:47 +0000 (UTC) Raw View
"Randy Maddox" <rmaddox@isicns.com> wrote in message
news:8c8b368d.0308050510.657ba3cd@posting.google.com...
> sebmol@yahoo.com ("Sebastian Moleski") wrote in message
news:<vitvnbs20nqb28@corp.supernews.com>...
> > That's impossible. Every object has a copy-constructor whether it is
implictly
> > defined by the compiler or explicitly by the class developer. That copy
> > constructor might not be accessible though.
>
> What about a copy-ctor that the developer explicitly declares and does
> not define? Say,
>
> class A
> {
> A(const A &); // declaration only, no definition anywhere
> };
>
> This class does not have a copy-ctor.
That's a question of what "has" means <g>
To be exact, every object has a declared (although not necessarily accessible or
defined) copy constructor.
sm
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eugalt@access4less.net (Eugene Alterman)
Date: Tue, 5 Aug 2003 23:38:59 +0000 (UTC) Raw View
daniel.frey@aixigo.de (Daniel Frey) wrote in message news:<bgnrc1$98k$1@swifty.westend.com>...
> Eugene Alterman wrote:
> > daniel.frey@aixigo.de (Daniel Frey) wrote in message news:<bgl8bj$sor$1
> @swifty.westend.com>...
> >
> >>What if A doesn't have a copy-ctor?
> >
> > Then it may not be used as a pass-by-value parameter or return type.
>
> And what does it mean for the example?
Well, let us generalize the concept of covariance and call it weak
covariance:
If a function D::f overrides a function B::f, the return types of the
functions are weakly covariant if a return value from B::f can be
initialized with a return value from D::f.
It is easy to see that covariance implies weak covariance.
Replace "covariant" in 10.3.5 with "weakly covariant"
You can see then that if A doesn't have a copy-ctor than return types
of B::fun and A::fun are not weakly covariant and B is ill-formed.
> A a;
> B b;
> A a2 = a.fun();
> B b2 = b.fun(); // No slicing here, no copy-ctor of A required
> A a3 = b.fun(); // B returned, copy-ctor required, slicing
>
> A* p = &b;
> A a4 = p->fun(); // Huh??
>
> The last call is the problem: p is of type A*, so the return type of
> p->fun() is A. But B::fun() is called, which return a B. Without a stub,
> how do you think this works? Compare it to 'b2' and 'a3'...
Oh... I see. You are right.
OK, we encountered a minor challange here, which we both know how to
address, don't we? :)
> > need to be employed at all since the most derived object type (and the
> > final overrider) is known at compile time. And if you call a virtual
> > function via a pointer or a reference there is no way to tell at
> > compile time what the final overrider would be.
>
> Should the language have separate rules for different cases? Should it
> describle in detail how smart a compiler must be to find out the final
> overriders?
God forbid! I've never said anything of the sort.
> >>and what would happen if we try to make the OP's code legal.
> >
> > Nothing terrible will happen. It just would be totally useless.
>
> The standard doesn't allow this dangerous code (althought it might not
> be useless depending on the context). It's just a trap that is avoided.
Could you please provide an example illustrating why it might be
dangerous or useful.
> So what's your point? Are you arguing that the code should be legal
> because "nothing terrible will happen"?
No, I am saying that "nothing terrible will happen" does not justify
introducing the feature.
> Also, instead of complaining
> about my inaccurate answer, why don't you provide a better and accurate
> answer? :)
Hmm... I thought I did. :)
In your original reply you seamed to suggest that the feature was not
allowed because it was technically impossible to implement.
And IMO that was the wrong answer.
So far you have not pointed out any reason why it could not be
implemented. Overhead? You are not serious about it, are you?
What I am saying is that there must be a good reason for a feature to
be introduced into a language. There was a good reason for introducing
covariant return types.
I don't see any problems that would result from allowing the code from
the original post. But all it would be good for is implementing a
perfect object slicer.
Eugene
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dan.r.mcleran@seagate.com (Dan McLeran)
Date: Wed, 6 Aug 2003 01:52:36 +0000 (UTC) Raw View
> What about a copy-ctor that the developer explicitly declares and does
> not define? Say,
>
> class A
> {
> A(const A &); // declaration only, no definition anywhere
> };
>
> This class does not have a copy-ctor.
>
> Randy.
I don't believe that this is valid code. I believe that if you provide
a copy ctr method declaration, you must provide implementation as
well. I put together a small file and got a linker error, with gcc &
MSVCSP5 anyways:
#include <iostream>
#include <stdlib.h>
using namespace std;
class A
{
public:
A()
{
cout<<"Ctr"<<endl;
}
A(A const& copy);
};
int main(int argc, char *argv[])
{
A a;
A b(a); //comment this line out and you're ok
//the compiler generates a default copy ctr
system("PAUSE");
return 0;
}
gcc gave a linker error:
main.o(.text+0x3f):main.cpp: undefined reference to `A::A(A const&)'
MSVCSP5 gave this linker error:
main.obj : error LNK2001: unresolved external symbol "public:
__thiscall A::A(class A const &)" (??0A@@QAE@ABV0@@Z)
Debug/NoCopyCtr.exe : fatal error LNK1120: 1 unresolved externals
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sebmol@yahoo.com ("Sebastian Moleski")
Date: Wed, 6 Aug 2003 02:19:29 +0000 (UTC) Raw View
"Dan McLeran" <dan.r.mcleran@seagate.com> wrote in message
news:19b0e504.0308051407.19d7e593@posting.google.com...
> > What about a copy-ctor that the developer explicitly declares and does
> > not define? Say,
> >
> > class A
> > {
> > A(const A &); // declaration only, no definition anywhere
> > };
> >
> > This class does not have a copy-ctor.
> >
> > Randy.
>
> I don't believe that this is valid code. I believe that if you provide
> a copy ctr method declaration, you must provide implementation as
> well.
Actually, that's not quite true. There's actually an idiom out there that takes
advantage of the fact that functions that aren't actually used don't have to be
defined either: if you want to specifically prevent copying and assignment
(which is sometimes necessary), you can declare the copy constructor and copy
assignment operator private and don't define it either.
> class A {
> public:
> A() {
> std::cout << "Ctr" << std::endl;
> }
> A(A const& copy);
> };
>
> int main(int argc, char *argv[]) {
> A a;
> A b(a); //comment this line out and you're ok
> //the compiler generates a default copy ctr
The difference here is that you are using the copy constructor. If you're not
using it, the compiler won't require it and the linker won't go looking for it
either. The comment "the compiler generates a default copy ctr" is incorrect. In
your example, no copy constructor is generated by the compiler.
sm
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]