Topic: Virtual function call for an object under construction
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 3 Nov 2009 17:08:50 CST Raw View
C++03 - 12.7/3: "When a virtual function is called directly or
indirectly from a constructor (including from the mem-initializer for
a data member) or from a destructor, and the object to which the call
applies is the object under construction or destruction, the function
called is the one defined in the constructor or destructor s own class
or in one of its bases, but not a function overriding it in a class
derived from the constructor or destructor s class, or overriding it
in one of the other base classes of the most derived object (1.8)."
There are two possible interpretations of this:
1) the function called is the final overrider (according to 5.2.2/1)
where the object under construction or destruction is considered to be
a most derived object that has the type of the constructor or
destructor s class (similarly to dynamic_cast);
2) an implementation is free to call any version of the virtual
function defined in the constructor or destructor s own class or in
one of its bases.
Consider the following example:
#include <iostream>
struct B
{
virtual void f() { std::cout << "B::f" << std::endl; }
};
struct D
{
D() { f(); }
virtual void f() { std::cout << "D::f" << std::endl; }
};
int main()
{
D d;
}
According to the first interpretation, an implementation shall choose
D::f for the call.
According to the second interpretation, it is unspecified whether D::f
or B::f is actually called.
Which one interpretation is intended?
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Tue, 3 Nov 2009 17:10:21 CST Raw View
[Note for the moderator: This is edited version (I have fixed erratum
in the example: D shall derive from B)]
C++03 - 12.7/3: "When a virtual function is called directly or
indirectly from a constructor (including from the mem-initializer for
a data member) or from a destructor, and the object to which the call
applies is the object under construction or destruction, the function
called is the one defined in the constructor or destructor s own class
or in one of its bases, but not a function overriding it in a class
derived from the constructor or destructor s class, or overriding it
in one of the other base classes of the most derived object (1.8)."
There are two possible interpretations:
1) the function called is the final overrider (according to 5.2.2/1)
where the object under construction or destruction is considered to be
a most derived object that has the type of the constructor or
destructor s class (similarly to dynamic_cast);
2) an implementation is free to call any version of the virtual
function defined in the constructor or destructor s own class or in
one of its bases.
Consider the following example:
#include <iostream>
struct B
{
virtual void f() { std::cout << "B::f" << std::endl; }
};
struct D : B
{
D() { f(); }
virtual void f() { std::cout << "D::f" << std::endl; }
};
int main()
{
D d;
}
According to the first interpretation, an implementation shall choose
D::f for the call.
According to the second interpretation, it is unspecified whether D::f
or B::f is actually called.
Which one interpretation is intended?
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Wed, 4 Nov 2009 21:39:03 CST Raw View
Nikolay Ivchenkov wrote:
> [Note for the moderator: This is edited version (I have fixed erratum
> in the example: D shall derive from B)]
>
> C++03 - 12.7/3: "When a virtual function is called directly or
> indirectly from a constructor (including from the mem-initializer for
> a data member) or from a destructor, and the object to which the call
> applies is the object under construction or destruction, the function
> called is the one defined in the constructor or destructor s own class
> or in one of its bases, but not a function overriding it in a class
> derived from the constructor or destructor s class, or overriding it
> in one of the other base classes of the most derived object (1.8)."
>
> There are two possible interpretations:
>
> 1) the function called is the final overrider (according to 5.2.2/1)
> where the object under construction or destruction is considered to be
> a most derived object that has the type of the constructor or
> destructor s class (similarly to dynamic_cast);
>
> 2) an implementation is free to call any version of the virtual
> function defined in the constructor or destructor s own class or in
> one of its bases.
>
Just found a third interpretation:
3) an implementation always calls the statically chosen function:
struct B
{
virtual void f() { std::cout << "B::f" << std::endl; }
void g() { f(); }
};
struct D : B
{
D() { g(); }
virtual void f() { std::cout << "D::f" << std::endl; }
};
int main()
{
D d;
}
According to the third interpretation, it will print "B::f".
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Alf P. Steinbach" <alfps@start.no>
Date: Wed, 4 Nov 2009 21:38:11 CST Raw View
* Nikolay Ivchenkov:
>
> C++03 - 12.7/3: "When a virtual function is called directly or
> indirectly from a constructor (including from the mem-initializer for
> a data member) or from a destructor, and the object to which the call
> applies is the object under construction or destruction, the function
> called is the one defined in the constructor or destructor s own class
> or in one of its bases, but not a function overriding it in a class
> derived from the constructor or destructor s class, or overriding it
> in one of the other base classes of the most derived object (1.8)."
>
> There are two possible interpretations of this:
>
> 1) the function called is the final overrider (according to 5.2.2/1)
> where the object under construction or destruction is considered to be
> a most derived object that has the type of the constructor or
> destructor s class (similarly to dynamic_cast);
>
> 2) an implementation is free to call any version of the virtual
> function defined in the constructor or destructor s own class or in
> one of its bases.
>
[snip]
>
> Which one interpretation is intended?
The first.
The intention is/was that in a T constructor, the object under
construction is effectively of most derived type T.
I can talk with very high degree of confidence about the intention
because this is a matter of very simple logic and practicality and
what it could at all be /for/, -- not because I was present in those
discussions, I wasn't.
Cheers & hth.,
- Alf
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: James Dennett <james.dennett@gmail.com>
Date: Wed, 4 Nov 2009 22:41:33 CST Raw View
On Nov 3, 3:10 pm, Nikolay Ivchenkov <ts...@mail.ru> wrote:
> [Note for the moderator: This is edited version (I have fixed erratum
> in the example: D shall derive from B)]
>
> C++03 - 12.7/3: "When a virtual function is called directly or
> indirectly from a constructor (including from the mem-initializer for
> a data member) or from a destructor, and the object to which the call
> applies is the object under construction or destruction, the function
> called is the one defined in the constructor or destructor s own class
> or in one of its bases, but not a function overriding it in a class
> derived from the constructor or destructor s class, or overriding it
> in one of the other base classes of the most derived object (1.8)."
>
> There are two possible interpretations:
>
> 1) the function called is the final overrider (according to 5.2.2/1)
> where the object under construction or destruction is considered to be
> a most derived object that has the type of the constructor or
> destructor s class (similarly to dynamic_cast);
>
> 2) an implementation is free to call any version of the virtual
> function defined in the constructor or destructor s own class or in
> one of its bases.
>
> Consider the following example:
>
> #include <iostream>
>
> struct B
> {
> virtual void f() { std::cout << "B::f" << std::endl; }
>
> };
>
> struct D : B
> {
> D() { f(); }
> virtual void f() { std::cout << "D::f" << std::endl; }
>
> };
>
> int main()
> {
> D d;
>
> }
>
> According to the first interpretation, an implementation shall choose
> D::f for the call.
> According to the second interpretation, it is unspecified whether D::f
> or B::f is actually called.
>
> Which one interpretation is intended?
The first. Virtual dispatch goes to the most-derived function. It
happens that during construction or destruction, that is the most-
derived that exists in the object at that time. Implementations do
not have flexibility in which function they call.
-- James
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Bart van Ingen Schenau <bart@ingen.ddns.info>
Date: Wed, 4 Nov 2009 22:41:12 CST Raw View
Nikolay Ivchenkov wrote:
> C++03 - 12.7/3: "When a virtual function is called directly or
> indirectly from a constructor (including from the mem-initializer for
> a data member) or from a destructor, and the object to which the call
> applies is the object under construction or destruction, the function
> called is the one defined in the constructor or destructor?s own class
> or in one of its bases, but not a function overriding it in a class
> derived from the constructor or destructor?s class, or overriding it
> in one of the other base classes of the most derived object (1.8)."
>
> There are two possible interpretations of this:
>
> 1) the function called is the final overrider (according to 5.2.2/1)
> where the object under construction or destruction is considered to be
> a most derived object that has the type of the constructor or
> destructor?s class (similarly to dynamic_cast);
>
> 2) an implementation is free to call any version of the virtual
> function defined in the constructor or destructor?s own class or in
> one of its bases.
>
> Consider the following example:
>
> #include <iostream>
>
> struct B
> {
> virtual void f() { std::cout << "B::f" << std::endl; }
> };
>
> struct D
> {
> D() { f(); }
> virtual void f() { std::cout << "D::f" << std::endl; }
> };
>
> int main()
> {
> D d;
> }
>
> According to the first interpretation, an implementation shall choose
> D::f for the call.
> According to the second interpretation, it is unspecified whether D::f
> or B::f is actually called.
>
> Which one interpretation is intended?
To my knowledge, the intended interpretation is #1 and that is (to my
knowledge) also the one that is implemented in all current compilers.
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Hyman Rosen <hyrosen@mail.com>
Date: Wed, 4 Nov 2009 22:40:25 CST Raw View
Nikolay Ivchenkov wrote:
> There are two possible interpretations of this:
> ...
> 1) the function called is the final overrider (according to 5.2.2/1)
> where the object under construction or destruction is considered to be
> a most derived object that has the type of the constructor or
> destructor s class (similarly to dynamic_cast);
> ...
> Which one interpretation is intended?
This.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Bo Persson" <bop@gmb.dk>
Date: Wed, 4 Nov 2009 22:40:53 CST Raw View
Nikolay Ivchenkov wrote:
> [Note for the moderator: This is edited version (I have fixed
> erratum in the example: D shall derive from B)]
>
> C++03 - 12.7/3: "When a virtual function is called directly or
> indirectly from a constructor (including from the mem-initializer
> for a data member) or from a destructor, and the object to which
> the call applies is the object under construction or destruction,
> the function called is the one defined in the constructor or
> destructor s own class or in one of its bases, but not a function
> overriding it in a class derived from the constructor or
> destructor s class, or overriding it in one of the other base
> classes of the most derived object (1.8)."
>
> There are two possible interpretations:
>
> 1) the function called is the final overrider (according to 5.2.2/1)
> where the object under construction or destruction is considered to
> be a most derived object that has the type of the constructor or
> destructor s class (similarly to dynamic_cast);
>
> 2) an implementation is free to call any version of the virtual
> function defined in the constructor or destructor s own class or in
> one of its bases.
>
When inside the constructor, or in something called from the
constructor, the object's dynamic type is the same as the static type
of the class containing the constructor. Option 1 is closest to that.
Bo Persson
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Kaz Kylheku <kkylheku@gmail.com>
Date: Thu, 5 Nov 2009 01:11:58 CST Raw View
On 2009-11-03, Nikolay Ivchenkov <tsoae@mail.ru> wrote:
> C++03 - 12.7/3: "When a virtual function is called directly or
> indirectly from a constructor (including from the mem-initializer for
> a data member) or from a destructor, and the object to which the call
> applies is the object under construction or destruction, the function
> called is the one defined in the constructor or destructor?s own class
^
Uh oh! ``dumbquote'' apostrophe mangling. :)
> or in one of its bases, but not a function overriding it in a class
This ``or'' doesn't mean that there is a lottery to be held between
the constructor's class and bases regarding whose virtual gets
called.
It simply means that the virtual function might not actualy be defined in
the
constructor or destructor's class; the call could go to a virtual which is
inherited from a base.
Sometimes ``or'' means there is a sequenced choice (like the || operator).
Call the one defined in its own class || call one defined in a base.
:)
> 2) an implementation is free to call any version of the virtual
> function defined in the constructor or destructor?s own class or in
> one of its bases.
That's insane. It would be like, say, allowing function arguments
to be evaluated in any order. Errr, wait a minute ... :)
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Thu, 5 Nov 2009 16:27:18 CST Raw View
Seems, I missed something important. Second try:
* When a virtual function specified by unqualified-id is called for an
object under construction _or destruction_ and the call occurs during
execution of:
-- body of the object's constructor
-- initialization of the object's non-static data member
-- body of the object's destructor
-- destructor of the object's non-static data member
the function called is the final overrider in the object's class, but
not a function overriding it in a class derived from the object's
class, or overriding it in one of the other base classes of the most
derived object (1.8).
Note: this also covers the case when the destructor for a non-static
data member is called from the object's constructor due to throwing an
exception.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nikolay Ivchenkov <tsoae@mail.ru>
Date: Thu, 5 Nov 2009 16:28:46 CST Raw View
On 5 Nov, 06:38, "Alf P. Steinbach" <al...@start.no> wrote:
>
> The intention is/was that in a T constructor, the object under
> construction is effectively of most derived type T.
I think, the presence of two interpretations of "most derived type"
and two interpretations of "most derived object" makes the rules
inconsistent. For example,
"the function called is the one defined in the constructor or
destructor's own class or in one of its bases, but not a function
overriding it in a class derived from the constructor or destructor's
class, or overriding it in one of the other base classes of the most
derived object (1.8)." (see 12.7/3)
Here "most derived object" means the most enclosing object which is
not subobject of any other object.
"if the operand of the dynamic_cast refers to the object under
construction or destruction, this object is considered to be a most
derived object that has the type of the constructor or destructor's
class" (see 12.7/5)
Here "most derived object" actually means the most base object under
construction (if the base class subobject is under construction then
any derived object (which contains that subobject) is apparently under
construction too).
"When a virtual function is called directly or indirectly from a
constructor (including from the mem-initializer for a data member) or
from a destructor, and the object to which the call applies is the
object under construction or destruction [...]". (see 12.7/3)
The constructor's execution may include initialization of base class
subobjects and non-static data members (regardless of whether the
corresponding mem-initializer is specified or the initialization
performs implicitly). The hint "including from the mem-initializer for
a data member" does not explicitly exclude initialization of base
class subobjects and initialization of data members which occurs
outside of mem-initializer. Similarly, the destructor's execution may
include calls of destructors for base class subobjects and non-static
data members.
#include <iostream>
struct D *d;
struct A
{
A();
~A();
};
struct B
{
B(D *d) { ::d = d; }
virtual void f() { std::cout << "B::f" << std::endl; }
};
struct D : B
{
D() : B(this) {}
virtual void f() { std::cout << "D::f" << std::endl; }
A a;
};
// most derived
struct M : D
{
virtual void f() { std::cout << "M::f" << std::endl; }
};
A::A() { d->f(); } // #1
A::~A() { d->f(); } // #2
int main() { M(); }
It's not clear enough which f can be called at #1 and #2 in the
example above.
I think, the rules shall be reformulated, and I hope, my wording below
is not so bad:
When a virtual function specified by unqualified-id is called for an
object under construction and the call occurs during execution of:
-- body of the object's constructor
-- initialization of the object's non-static data member
-- body of the object's destructor
-- destructor of the object's non-static data member
the function called is the final overrider in the object's class, but
not a function overriding it in a class derived from the object's
class, or overriding it in one of the other base classes of the most
derived object (1.8).
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]