471,585 Members | 1,594 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,585 software developers and data experts.

Polymorphic behavior without virtual functions


What is the expected output of this program and why???

#include <iostream>

using namespace std;

class base
{
public:
~base() {cout << "base" << endl;}
};

class derived: public base
{
public:
~derived() {cout << "derived" << endl;}
};

int main()
{
const base &r = derived();
(void) r; // Suppress compiler warning about unused var.
}
Jul 22 '05 #1
9 1371
"Dave" <be***********@yahoo.com> wrote...

What is the expected output of this program and why???

#include <iostream>

using namespace std;

class base
{
public:
~base() {cout << "base" << endl;}
};

class derived: public base
{
public:
~derived() {cout << "derived" << endl;}
};

int main()
{
const base &r = derived();
(void) r; // Suppress compiler warning about unused var.
}


The output should be

derived
base

After 'main' function finishes and 'r' goes out of scope.

Regarding the subject of your post: there is no polymorphic
behaviour here. A temporary of type 'derived' is created and
later destroyed when a constant reference (bound to its base
class subobject) ceases to exist (see 12.2/5).

Victor
Jul 22 '05 #2

"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:VLmGb.470930$275.1368307@attbi_s53...
"Dave" <be***********@yahoo.com> wrote...

What is the expected output of this program and why???

#include <iostream>

using namespace std;

class base
{
public:
~base() {cout << "base" << endl;}
};

class derived: public base
{
public:
~derived() {cout << "derived" << endl;}
};

int main()
{
const base &r = derived();
(void) r; // Suppress compiler warning about unused var.
}


The output should be

derived
base

After 'main' function finishes and 'r' goes out of scope.

Regarding the subject of your post: there is no polymorphic
behaviour here. A temporary of type 'derived' is created and
later destroyed when a constant reference (bound to its base
class subobject) ceases to exist (see 12.2/5).

Victor


This program would have undefined behavior if I had used a pointer rather
than a reference. I'm trying to understand the underlying language
mechanism that makes this case different, but I'm not sure that there is a
really satisfying answer; the answer may be "it just is"...
Jul 22 '05 #3
"Dave" <be***********@yahoo.com> wrote...

"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:VLmGb.470930$275.1368307@attbi_s53...
"Dave" <be***********@yahoo.com> wrote...

What is the expected output of this program and why???

#include <iostream>

using namespace std;

class base
{
public:
~base() {cout << "base" << endl;}
};

class derived: public base
{
public:
~derived() {cout << "derived" << endl;}
};

int main()
{
const base &r = derived();
(void) r; // Suppress compiler warning about unused var.
}
The output should be

derived
base

After 'main' function finishes and 'r' goes out of scope.

Regarding the subject of your post: there is no polymorphic
behaviour here. A temporary of type 'derived' is created and
later destroyed when a constant reference (bound to its base
class subobject) ceases to exist (see 12.2/5).

Victor


This program would have undefined behavior if I had used a pointer rather
than a reference.


It would be a different program.
I'm trying to understand the underlying language
mechanism that makes this case different, but I'm not sure that there is a
really satisfying answer; the answer may be "it just is"...


If a reference (a const one) is bound to a temporary, the lifetime of
the temporary extends to match the lifetime of the reference. It is
mandated by the Standard, and I've given you the subclause/paragraph
number. What else mechanism you're talking about, I am not sure.

Victor
Jul 22 '05 #4

"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:v2oGb.449122$Dw6.1358306@attbi_s02...
"Dave" <be***********@yahoo.com> wrote...

"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:VLmGb.470930$275.1368307@attbi_s53...
"Dave" <be***********@yahoo.com> wrote...
>
> What is the expected output of this program and why???
>
>
>
> #include <iostream>
>
> using namespace std;
>
> class base
> {
> public:
> ~base() {cout << "base" << endl;}
> };
>
> class derived: public base
> {
> public:
> ~derived() {cout << "derived" << endl;}
> };
>
> int main()
> {
> const base &r = derived();
> (void) r; // Suppress compiler warning about unused var.
> }

The output should be

derived
base

After 'main' function finishes and 'r' goes out of scope.

Regarding the subject of your post: there is no polymorphic
behaviour here. A temporary of type 'derived' is created and
later destroyed when a constant reference (bound to its base
class subobject) ceases to exist (see 12.2/5).

Victor


This program would have undefined behavior if I had used a pointer rather than a reference.


It would be a different program.
I'm trying to understand the underlying language
mechanism that makes this case different, but I'm not sure that there is a really satisfying answer; the answer may be "it just is"...


If a reference (a const one) is bound to a temporary, the lifetime of
the temporary extends to match the lifetime of the reference. It is
mandated by the Standard, and I've given you the subclause/paragraph
number. What else mechanism you're talking about, I am not sure.

Victor


But how is the proper destructor execution sequence occurring given that we
have a const reference to *base*? What causes the *derived* destructor to
be executed? Why would it be executed given that nothing polymorphic is
going on?

Also, the output I actually see is:

derived
base
derived
base

This I don't understand. I would have expected exactly the output you
predicted!

Another interesting point: Suppose I change the definition of r to the
following:

const base &r(derived());

In this case, I get no output at all!

Not sure what's going on with all of this...
Jul 22 '05 #5
Not sure why you are getting the repeats. I don't get them here.
I am using g++. Maybe it is a compiler issue.

On Wed, 24 Dec 2003 15:45:47 -0700, Dave wrote:

"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:v2oGb.449122$Dw6.1358306@attbi_s02...
"Dave" <be***********@yahoo.com> wrote...
>
> "Victor Bazarov" <v.********@comAcast.net> wrote in message
> news:VLmGb.470930$275.1368307@attbi_s53...
> > "Dave" <be***********@yahoo.com> wrote...
> > >
> > > What is the expected output of this program and why???
> > >
> > >
> > >
> > > #include <iostream>
> > >
> > > using namespace std;
> > >
> > > class base
> > > {
> > > public:
> > > ~base() {cout << "base" << endl;}
> > > };
> > >
> > > class derived: public base
> > > {
> > > public:
> > > ~derived() {cout << "derived" << endl;}
> > > };
> > >
> > > int main()
> > > {
> > > const base &r = derived();
> > > (void) r; // Suppress compiler warning about unused var.
> > > }
> >
> > The output should be
> >
> > derived
> > base
> >
> > After 'main' function finishes and 'r' goes out of scope.
> >
> > Regarding the subject of your post: there is no polymorphic
> > behaviour here. A temporary of type 'derived' is created and
> > later destroyed when a constant reference (bound to its base
> > class subobject) ceases to exist (see 12.2/5).
> >
> > Victor
> >
> >
>
> This program would have undefined behavior if I had used a pointer rather > than a reference.


It would be a different program.
> I'm trying to understand the underlying language
> mechanism that makes this case different, but I'm not sure that there is a > really satisfying answer; the answer may be "it just is"...


If a reference (a const one) is bound to a temporary, the lifetime of
the temporary extends to match the lifetime of the reference. It is
mandated by the Standard, and I've given you the subclause/paragraph
number. What else mechanism you're talking about, I am not sure.

Victor


But how is the proper destructor execution sequence occurring given that we
have a const reference to *base*? What causes the *derived* destructor to
be executed? Why would it be executed given that nothing polymorphic is
going on?

Also, the output I actually see is:

derived
base
derived
base

This I don't understand. I would have expected exactly the output you
predicted!

Another interesting point: Suppose I change the definition of r to the
following:

const base &r(derived());

In this case, I get no output at all!

Not sure what's going on with all of this...


Jul 22 '05 #6
"Dave" <be***********@yahoo.com> wrote in message
news:vu***********@news.supernews.com

But how is the proper destructor execution sequence occurring given
that we have a const reference to *base*? What causes the *derived*
destructor to be executed? Why would it be executed given that
nothing polymorphic is going on?

I don't know the answer, but this is my guess. Suppose that you simply
entered

Derived();

Then the destructor for the derived class will be called, courtesy of the
mechanism for handling temporaries. I suspect that it is this same mechanism
that is being used when you assign the temporary to a const reference to a
base object. The only effect of the const reference is to defer the
destruction of the temporary; the basic mechanism of destruction is the same
as if no assignment had been made.
Also, the output I actually see is:

derived
base
derived
base

This I don't understand. I would have expected exactly the output you
predicted!


I suspect a bug. With VC++2002, I get the same repeated output as you do.
If, however, I add a constructor, then the output is as expected.

class base
{
public:
base() {cout << "base constructor" << endl;}
~base() {cout << "base destructor" << endl;}
};

class derived: public base
{
public:
derived() {cout << "derived constructor" << endl;}
~derived() {cout << "derived destructor" << endl;}
};
--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)

Jul 22 '05 #7
"Dave" <be***********@yahoo.com> wrote...
[...]

Another interesting point: Suppose I change the definition of r to the
following:

const base &r(derived());

In this case, I get no output at all!

Not sure what's going on with all of this...

const base& r(derived());

is a declaration of a function 'r' that takes one argument of type
'derived' and returns a reference to const base. Internal parens
do not matter.

Victor
Jul 22 '05 #8
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:U_DGb.39324$VB2.79533@attbi_s51
"Dave" <be***********@yahoo.com> wrote...
[...]

Another interesting point: Suppose I change the definition of r to
the following:

const base &r(derived());

In this case, I get no output at all!

Not sure what's going on with all of this...

const base& r(derived());

is a declaration of a function 'r' that takes one argument of type
'derived' and returns a reference to const base. Internal parens
do not matter.

Victor


VC++ 2002 doesn't interpret it that way (it treats it as an assignment to r)
but I presume that this is just a bug.

Comeau online, by contrast, does treat it as a function declaration, but
interprets the function's parameter as a pointer to a function that takes no
parameters and returns a derived object. Thus the following compiles:

derived foo()
{
derived d;
return d;
}

int main()
{
const base &r(derived());
r(foo);
}
whereas the following fails with the error message:

error: no suitable conversion function from "derived" to
"derived (*)()" exists
int main()
{
const base &r(derived());
derived dobject;
r(dobject);
}

I don't know if this is a bug or if there is some way in which a parameter
of type

derived()

can legitimately be intepreted as a parameter of type

derived(*)().

--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)

Jul 22 '05 #9
"John Carson" <do***********@datafast.net.au> wrote...
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:U_DGb.39324$VB2.79533@attbi_s51
"Dave" <be***********@yahoo.com> wrote...
[...]

Another interesting point: Suppose I change the definition of r to
the following:

const base &r(derived());

In this case, I get no output at all!

Not sure what's going on with all of this...

const base& r(derived());

is a declaration of a function 'r' that takes one argument of type
'derived' and returns a reference to const base. Internal parens
do not matter.

Victor


VC++ 2002 doesn't interpret it that way (it treats it as an assignment to

r) but I presume that this is just a bug.

Comeau online, by contrast, does treat it as a function declaration, but
interprets the function's parameter as a pointer to a function that takes no parameters and returns a derived object.
Yes, that's probably more correct, I've confused it with a situation

someothertype a;
const base& r(derived(a));

where the second 'a' is not an argument to a function-style cast, but
rather a [superfluous] name of an argument in a function declaration.
Thus the following compiles:

derived foo()
{
derived d;
return d;
}

int main()
{
const base &r(derived());
r(foo);
}
whereas the following fails with the error message:

error: no suitable conversion function from "derived" to
"derived (*)()" exists
int main()
{
const base &r(derived());
derived dobject;
r(dobject);
}

I don't know if this is a bug or if there is some way in which a parameter
of type

derived()

can legitimately be intepreted as a parameter of type

derived(*)().


I can't find any support for that in the Standard. It, apparently,
allows an argument to a function to be another function, and there
is no conversion necessary, AFAICT.

If 'T' is a function, an lvalue of type T can be converted to an rvalue
of type "a pointer to T", which will be "a pointer to a function ...".
However, there is nothing in the Standard that says that in a function
declaration a declaration of an argument in case of a function shall be
interpreted as a pointer to a function.

Victor
Jul 22 '05 #10

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by Dave Theese | last post: by
5 posts views Thread by S. Levent Yilmaz | last post: by
2 posts views Thread by Aryeh M. Friedman | last post: by
20 posts views Thread by verec | last post: by
9 posts views Thread by Karel Miklav | last post: by
7 posts views Thread by Peter Oliphant | last post: by
12 posts views Thread by Bob | last post: by
5 posts views Thread by Ben Pope | last post: by
7 posts views Thread by Arindam | last post: by
reply views Thread by leo001 | last post: by

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

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