 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Daniel Guest
|
Posted: Mon Feb 27, 2006 2:06 am Post subject: Virtual Methods Question |
|
|
I have the following three classes
class A
{
public:
virtual void f() = 0;
};
class B: public A
{
public:
virtual void f();
};
void B::f()
{
cout << "B::f()";
}
class C: public B
{
public:
void f();
};
void C::f()
{
cout << "C::f()";
}
main()
{
A* x = new C();
x->f();
}
The above program prints the following:
B::f()
But, I wanted the program to print
C::f()
Why is the program doing this? Is there any way for me to have C's f()
method invoked instead of B's f() method? I am using the GNU compiler
for VxWorks 5.5. Thanks in advance for any help.
-Daniel |
|
| Back to top |
|
 |
Guest
|
Posted: Mon Feb 27, 2006 2:06 am Post subject: Re: Virtual Methods Question |
|
|
Daniel wrote:
| Quote: | The above program prints the following:
B::f()
But, I wanted the program to print
C::f()
|
prints "C::f()" over here. That is what it should do. |
|
| Back to top |
|
 |
Frank Schmidt Guest
|
Posted: Mon Feb 27, 2006 4:06 am Post subject: Re: Virtual Methods Question |
|
|
"Daniel" <dantheman0316 (AT) gmail (DOT) com> schrieb im Newsbeitrag
news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
| Quote: | class C: public B
{
public:
void f();
};
|
you miss a virtual there.
f~ |
|
| Back to top |
|
 |
Peter_Julian Guest
|
Posted: Mon Feb 27, 2006 5:06 am Post subject: Re: Virtual Methods Question |
|
|
"Daniel" <dantheman0316 (AT) gmail (DOT) com> wrote in message
news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
| I have the following three classes
|
| class A
| {
| public:
| virtual void f() = 0;
| };
undefined behaviour.
1) you failed to invoke delete x
2) In main() you are using a base pointer to a derived object and yet you
have not declared a virtual destructor in class A.
#include <iostream>
#include <ostream>
class A
{
public:
virtual ~A() { std::cout << "~A()\n"; }
virtual void f() = 0;
};
<snip>
|
| main()
int main()
| {
| A* x = new C();
A* x = new C;
|
| x->f();
delete x;
| }
|
| The above program prints the following:
|
| B::f()
|
| But, I wanted the program to print
|
| C::f()
|
| Why is the program doing this? Is there any way for me to have C's f()
| method invoked instead of B's f() method? I am using the GNU compiler
| for VxWorks 5.5. Thanks in advance for any help.
|
Your compiler is invoking the C() ctor correctly(which requires that both
A() and B() get allocated first) and then drops the allocation of the
derived C as if it were a temporary (which is not appropriate but otherwise
not strictly enforced). The remnant is a valid B-type object.
That should be fixed with the correct statement:
A* x = new C; // correctly invokes the default ctor to completion
Note that your problem, other than not using delete x at all (shame), has a
much more critical issue than the one you raise. If you don't provide a
virtual d~tor in class A then ~B() or ~C() will never be invoked. Thats a
guarenteed memory leak.
Test it:
int main()
{
A* x = new C;
x->f();
delete x;
return 0;
}
/* correct output
C::f()
~C()
~B()
~A()
*/
but what you are getting with the compiler generated d~tor(s) is:
C::f()
~A()
which is a partial destruction and a memory leak. bad news.
Moral of the story:
a) never, ever new if you don't delete
b) never, ever new[] if you don't [] delete
c)if you derive and destroy via a pointer to base:
***always provide a virtual d~tor***
or suffer the consequences. |
|
| Back to top |
|
 |
Guest
|
Posted: Mon Feb 27, 2006 5:06 am Post subject: Re: Virtual Methods Question |
|
|
Peter_Julian wrote:
| Quote: | "Frank Schmidt" <fs (AT) example (DOT) com> wrote in message
news:dttrvp$ndp$1 (AT) online (DOT) de...
|
| "Daniel" <dantheman0316 (AT) gmail (DOT) com> schrieb im Newsbeitrag
| news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
|
| > class C: public B
| > {
| > public:
| > void f();
| > };
|
| you miss a virtual there.
|
| f~
|
Nope, if the pure-abstract or base class specifies that void f() is virtual
then its virtual in the entire hierarchy. Regardless whether the derived
classes have that function as virtual or not.
|
I thought it stopped at C meaning that any subclass of C would not be
able to polymorphically override f(). |
|
| Back to top |
|
 |
Peter_Julian Guest
|
Posted: Mon Feb 27, 2006 5:06 am Post subject: Re: Virtual Methods Question |
|
|
"Frank Schmidt" <fs (AT) example (DOT) com> wrote in message
news:dttrvp$ndp$1 (AT) online (DOT) de...
|
| "Daniel" <dantheman0316 (AT) gmail (DOT) com> schrieb im Newsbeitrag
| news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
|
| > class C: public B
| > {
| > public:
| > void f();
| > };
|
| you miss a virtual there.
|
| f~
|
Nope, if the pure-abstract or base class specifies that void f() is virtual
then its virtual in the entire hierarchy. Regardless whether the derived
classes have that function as virtual or not. |
|
| Back to top |
|
 |
Peter_Julian Guest
|
Posted: Mon Feb 27, 2006 7:06 am Post subject: Re: Virtual Methods Question |
|
|
<roberts.noah (AT) gmail (DOT) com> wrote in message
news:1141013860.390579.103060 (AT) z34g2000cwc (DOT) googlegroups.com...
|
| Peter_Julian wrote:
| > "Frank Schmidt" <fs (AT) example (DOT) com> wrote in message
| > news:dttrvp$ndp$1 (AT) online (DOT) de...
| > |
| > | "Daniel" <dantheman0316 (AT) gmail (DOT) com> schrieb im Newsbeitrag
| > | news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
| > |
| > | > class C: public B
| > | > {
| > | > public:
| > | > void f();
| > | > };
| > |
| > | you miss a virtual there.
| > |
| > | f~
| > |
| >
| > Nope, if the pure-abstract or base class specifies that void f() is
virtual
| > then its virtual in the entire hierarchy. Regardless whether the derived
| > classes have that function as virtual or not.
|
| I thought it stopped at C meaning that any subclass of C would not be
| able to polymorphically override f().
|
That doesn't make sense, and with good reason. The is_a relationship is
critical here. If you publicly derive from C and declare D, then its implied
that the D-type is_a C-type as well. You can perfectly well derive like
so...
class D : public C
{
};
and never declare void f() since a call like so...
A* p_a = new D;
p_a->f(); // will call C::f(), no problem - its expected
delete p_a; // invokes 4 d~tors - ~D, ~C, ~B and ~A
If there was a way to prevent the inheritance of a pure-virtual member
function, polymorphism would be broken. And there is...
___
The answer to your quest is simple: composition or private inheritance.
Sometimes its more important to understand when not_to_use polymorphic
inheritance.
Neither of these represent an "is_a" inheritance scheme.
class D
{
C c;
public:
void f() { } // not virtual
};
or D in_terms_of C, where D is_not C or B or A. This is also a form of
composition, not polymorphic inheritance...
class D : private C
{
void f() { std::cout << "D::f()\n"; } // not virtual
};
int main()
{
D d;
d.f();
}
/*
D::f() // not virtual
~D()
~C()
~B()
~A()
*/ |
|
| Back to top |
|
 |
Dietmar Kuehl Guest
|
Posted: Mon Feb 27, 2006 9:06 am Post subject: Re: Virtual Methods Question |
|
|
Daniel wrote:
| Quote: | The above program prints the following:
B::f()
|
You must have made a copying error: the program does not compile
for me. There are missing include statements, namespace qualification,
and a missing return type of 'main()'. Once I fixed these problems,
the program prints "C::f()", as it should.
--
<mailto:dietmar_kuehl (AT) yahoo (DOT) com> <http://www.dietmar-kuehl.de/>
<http://www.eai-systems.com> - Efficient Artificial Intelligence |
|
| Back to top |
|
 |
Frank Schmidt Guest
|
Posted: Mon Feb 27, 2006 1:06 pm Post subject: Re: Virtual Methods Question |
|
|
"Peter_Julian" <pj (AT) antispam (DOT) codigo.ca> schrieb im Newsbeitrag
news:fNuMf.1551$RM2.104149 (AT) news20 (DOT) bellglobal.com...
| Quote: |
"Frank Schmidt" <fs (AT) example (DOT) com> wrote in message
news:dttrvp$ndp$1 (AT) online (DOT) de...
|
| "Daniel" <dantheman0316 (AT) gmail (DOT) com> schrieb im Newsbeitrag
| news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
|
| > class C: public B
| > {
| > public:
| > void f();
| > };
|
| you miss a virtual there.
|
| f~
|
Nope, if the pure-abstract or base class specifies that void f() is
virtual
then its virtual in the entire hierarchy. Regardless whether the derived
classes have that function as virtual or not.
|
say that to a compiler, which calls B::f() with the given the source |
|
| Back to top |
|
 |
Guest
|
Posted: Mon Feb 27, 2006 4:06 pm Post subject: Re: Virtual Methods Question |
|
|
Peter_Julian wrote:
| Quote: | roberts.noah (AT) gmail (DOT) com> wrote in message
news:1141013860.390579.103060 (AT) z34g2000cwc (DOT) googlegroups.com...
|
| Peter_Julian wrote:
| > "Frank Schmidt" <fs (AT) example (DOT) com> wrote in message
| > news:dttrvp$ndp$1 (AT) online (DOT) de...
| > |
| > | "Daniel" <dantheman0316 (AT) gmail (DOT) com> schrieb im Newsbeitrag
| > | news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
| > |
| > | > class C: public B
| > | > {
| > | > public:
| > | > void f();
| > | > };
| > |
| > | you miss a virtual there.
| > |
| > | f~
| > |
|
| > Nope, if the pure-abstract or base class specifies that void f() is
virtual
| > then its virtual in the entire hierarchy. Regardless whether the derived
| > classes have that function as virtual or not.
|
| I thought it stopped at C meaning that any subclass of C would not be
| able to polymorphically override f().
|
That doesn't make sense, and with good reason. The is_a relationship is
critical here. If you publicly derive from C and declare D, then its implied
that the D-type is_a C-type as well. You can perfectly well derive like
so...
class D : public C
{
};
and never declare void f() since a call like so...
|
You totally missed my point. Doesn't matter because I was wrong but
still, I said one thing and you went off in a totally different
direction. |
|
| Back to top |
|
 |
Peter_Julian Guest
|
Posted: Tue Feb 28, 2006 2:06 am Post subject: Re: Virtual Methods Question |
|
|
"Frank Schmidt" <fs (AT) example (DOT) com> wrote in message
news:dtutag$i83$1 (AT) online (DOT) de...
|
| "Peter_Julian" <pj (AT) antispam (DOT) codigo.ca> schrieb im Newsbeitrag
| news:fNuMf.1551$RM2.104149 (AT) news20 (DOT) bellglobal.com...
| >
| > "Frank Schmidt" <fs (AT) example (DOT) com> wrote in message
| > news:dttrvp$ndp$1 (AT) online (DOT) de...
| > |
| > | "Daniel" <dantheman0316 (AT) gmail (DOT) com> schrieb im Newsbeitrag
| > | news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
| > |
| > | > class C: public B
| > | > {
| > | > public:
| > | > void f();
| > | > };
| > |
| > | you miss a virtual there.
| > |
| > | f~
| > |
| >
| > Nope, if the pure-abstract or base class specifies that void f() is
| > virtual
| > then its virtual in the entire hierarchy. Regardless whether the derived
| > classes have that function as virtual or not.
|
| say that to a compiler, which calls B::f() with the given the source
|
Wrong solution. The only reason that B::f() is being called is because the
call to new C() never return a type C instance [undefined behaviour]. The
remnant type at the pointer is a B-type object with some compilers.
The correct statement is: A* p = new C; // no brackets
insofar as the virtual keyword, test it yourself...:
___
#include <iostream>
#include <ostream>
class A
{
virtual void f();
};
class B : public A
{
void f();
};
class C : public B
{
void f();
};
int main()
{
C c;
A* p = &c;
p->f();
return 0;
}
/*
C::f()
*/ |
|
| Back to top |
|
 |
Jay_Nabonne Guest
|
Posted: Tue Feb 28, 2006 3:06 am Post subject: Re: Virtual Methods Question |
|
|
On Sun, 26 Feb 2006 17:34:58 -0800, Daniel wrote:
| Quote: | I have the following three classes
|
<snip>
| Quote: |
The above program prints the following:
B::f()
But, I wanted the program to print
C::f()
Why is the program doing this? Is there any way for me to have C's f()
method invoked instead of B's f() method?
|
The way the code is set up above, it should work. Make sure the function
signatures are *identical* including parameters, return type, and
"const"ness.
- jay |
|
| Back to top |
|
 |
Jay_Nabonne Guest
|
Posted: Tue Feb 28, 2006 3:06 am Post subject: Re: Virtual Methods Question |
|
|
On Sun, 26 Feb 2006 23:50:54 -0500, Peter_Julian wrote:
I'll probably regret this...
| Quote: |
"Daniel" <dantheman0316 (AT) gmail (DOT) com> wrote in message
news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
| I have the following three classes
|
| class A
| {
| public:
| virtual void f() = 0;
| };
undefined behaviour.
1) you failed to invoke delete x
|
Failing to delete x is not undefined behavior. It's a memory leak.
| Quote: | 2) In main() you are using a base pointer to a derived object and yet you
have not declared a virtual destructor in class A.
|
*Using* a derived object through a base pointer (without a virtual
destructor) is not undefined behavior (see, for example, COM). *Deleting*
said pointer would be. Since the pointer was not deleted, there is no
undefined behavior. (But as soon as you add your delete, then you need to
add the virtual destructor.) I'm not saying it's good code (and you
provide an excellent analysis below), but there's no undefined behavior as
is.
| Quote: |
| {
| A* x = new C();
A* x = new C;
|
There is no difference in the above two lines for the C class, at least as
far as the stability of the resulting object goes.
| Quote: |
Your compiler is invoking the C() ctor correctly(which requires that both
A() and B() get allocated first) and then drops the allocation of the
derived C as if it were a temporary (which is not appropriate but otherwise
not strictly enforced). The remnant is a valid B-type object.
|
Have you been smoking the C++ standard again? Seriously, what are you
talking about? What in the world would cause the newly allocated "C"
object to decay to a "B"?
- Jay |
|
| Back to top |
|
 |
Peter_Julian Guest
|
Posted: Wed Mar 01, 2006 2:06 am Post subject: Re: Virtual Methods Question |
|
|
"Jay_Nabonne" <jnabonne (AT) pacbello (DOT) net> wrote in message
news:pan.2006.02.28.02.37.39.657000 (AT) pacbello (DOT) net...
| On Sun, 26 Feb 2006 17:34:58 -0800, Daniel wrote:
|
| > I have the following three classes
|
| <snip>
|
| >
| > The above program prints the following:
| >
| > B::f()
| >
| > But, I wanted the program to print
| >
| > C::f()
| >
| > Why is the program doing this? Is there any way for me to have C's f()
| > method invoked instead of B's f() method?
|
| The way the code is set up above, it should work. Make sure the function
| signatures are *identical* including parameters, return type, and
| "const"ness.
|
The return type is not part of the signature and is not taken in
consideration when deciding which function gets called. |
|
| Back to top |
|
 |
Peter_Julian Guest
|
Posted: Wed Mar 01, 2006 4:06 am Post subject: Re: Virtual Methods Question |
|
|
"Jay_Nabonne" <jnabonne (AT) pacbello (DOT) net> wrote in message
news:pan.2006.02.28.02.53.39.188000 (AT) pacbello (DOT) net...
| On Sun, 26 Feb 2006 23:50:54 -0500, Peter_Julian wrote:
|
| I'll probably regret this...
lol, no we won't, i welcome the feedback specially if it proves me wrong
|
| >
| > "Daniel" <dantheman0316 (AT) gmail (DOT) com> wrote in message
| > news:1141004098.574639.214840 (AT) v46g2000cwv (DOT) googlegroups.com...
| > | I have the following three classes
| > |
| > | class A
| > | {
| > | public:
| > | virtual void f() = 0;
| > | };
| >
| > undefined behaviour.
| > 1) you failed to invoke delete x
|
| Failing to delete x is not undefined behavior. It's a memory leak.
The mem leak wasn't what made the code UB.
|
| > 2) In main() you are using a base pointer to a derived object and yet
you
| > have not declared a virtual destructor in class A.
|
| *Using* a derived object through a base pointer (without a virtual
| destructor) is not undefined behavior (see, for example, COM). *Deleting*
| said pointer would be. Since the pointer was not deleted, there is no
| undefined behavior. (But as soon as you add your delete, then you need to
| add the virtual destructor.) I'm not saying it's good code (and you
| provide an excellent analysis below), but there's no undefined behavior as
| is.
Wrong, new used to allocate that base pointer, whether its explicitly
deleted or not, is UB. Consider: shared_ptr<T>, scoped_ptr<T>, etc.
|
| >
| >
| > | {
| > | A* x = new C();
| >
| > A* x = new C;
| >
|
| There is no difference in the above two lines for the C class, at least as
| far as the stability of the resulting object goes.
This, unfortunately, has been proven to be false. The OP's result is a case
in point.
|
| >
| > Your compiler is invoking the C() ctor correctly(which requires that
both
| > A() and B() get allocated first) and then drops the allocation of the
| > derived C as if it were a temporary (which is not appropriate but
otherwise
| > not strictly enforced). The remnant is a valid B-type object.
|
| Have you been smoking the C++ standard again? Seriously, what are you
| talking about? What in the world would cause the newly allocated "C"
| object to decay to a "B"?
|
Beats the hell out of me (placement new implementation?). Won't be the first
time i've seen that. It is, however, correct to write ...
int* p = new int;
.... to invoke the default ctor. Even the problem compilers handle that
correctly. I'ld be interested to know what that GNU compiler for VxWorks 5.5
does without the brackets (hint?).
[Hmm, now where the hell is that pint of beer()?] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|