Hi all,
I have a simple question. If I have a ClassA as base class, and ClassB
derive from it. There is a virtual function foo() in ClassA, and in Class B,
I defined a function called foo() as well (w/ or w/o declaring it as virtual
doesn't matter since the virtual is inhered, right?). Both of them have a
virtual destructor.
Now, here is the part of the code:
ClassA::foo()
{
cout << "In class A"
}
ClassB::foo()
{
cout << "In class B"
}
ClassA::~ClassA ()
{
cout << "destroying A"
}
ClassB::~ClassB ()
{
cout << "destroying A"
}
When deleting objectB (from ClassB), both destructors are called. However,
when calling objectB's foo, only the classB's foo is called. Why is that?
Thanks for all your help. 7 1615
"Calvin Lai" <ca********@i01 0.com> wrote in message
news:PA******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Hi all,
I have a simple question. If I have a ClassA as base class, and ClassB derive from it. There is a virtual function foo() in ClassA, and in Class
B, I defined a function called foo() as well (w/ or w/o declaring it as
virtual doesn't matter since the virtual is inhered, right?).
Correct.
Both of them have a virtual destructor.
Now, here is the part of the code:
ClassA::foo() { cout << "In class A" }
ClassB::foo() { cout << "In class B" }
ClassA::~ClassA () { cout << "destroying A" }
ClassB::~ClassB () { cout << "destroying A" }
When deleting objectB (from ClassB), both destructors are called. However, when calling objectB's foo, only the classB's foo is called. Why is that?
Because an object of type ClassB is actually composed of parts of both
ClassA and ClassB. Let's say in ClassA there were a file, and in ClassB
there was also a file. In an object of type ClassA, there will be 1 file.
In an object of type ClassB, there will be 2 files. When you delete an
object of ClassB, don't you want to make sure that both files are closed?
The closing of the file in ClassA should logically be closed in the
destructor for ClassA. On the other hand, functions aren't the same as
storage. Functions have to do with behavior, and if you want the behavior
of ClassB to be different from that of ClassA, then there's no reason to
call ClassA's function. You could though. In ClassB::foo(), you could make
a call to ClassA::foo(). Then it would work the same way as the destructor
calls.
Thanks Jeff. However, is this a logical reasoning of why this is happening
by design, or there is other behind the door arguments for it?
Calvin
"jeffc" <no****@nowhere .com> wrote in message
news:3f******** @news1.prserv.n et... "Calvin Lai" <ca********@i01 0.com> wrote in message news:PA******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Hi all,
I have a simple question. If I have a ClassA as base class, and ClassB derive from it. There is a virtual function foo() in ClassA, and in
Class B, I defined a function called foo() as well (w/ or w/o declaring it as virtual doesn't matter since the virtual is inhered, right?).
Correct.
Both of them have a virtual destructor.
Now, here is the part of the code:
ClassA::foo() { cout << "In class A" }
ClassB::foo() { cout << "In class B" }
ClassA::~ClassA () { cout << "destroying A" }
ClassB::~ClassB () { cout << "destroying A" }
When deleting objectB (from ClassB), both destructors are called.
However, when calling objectB's foo, only the classB's foo is called. Why is
that? Because an object of type ClassB is actually composed of parts of both ClassA and ClassB. Let's say in ClassA there were a file, and in ClassB there was also a file. In an object of type ClassA, there will be 1 file. In an object of type ClassB, there will be 2 files. When you delete an object of ClassB, don't you want to make sure that both files are closed? The closing of the file in ClassA should logically be closed in the destructor for ClassA. On the other hand, functions aren't the same as storage. Functions have to do with behavior, and if you want the behavior of ClassB to be different from that of ClassA, then there's no reason to call ClassA's function. You could though. In ClassB::foo(), you could
make a call to ClassA::foo(). Then it would work the same way as the
destructor calls.
"Calvin Lai" <ca********@i01 0.com> wrote in message
news:99******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Thanks Jeff. However, is this a logical reasoning of why this is happening by design, or there is other behind the door arguments for it?
I'm not sure what you mean. A destructor isn't a normal function. It is
there to do necessary cleanup, so a derived class has no business preventing
its base class's destructor executing. Therefore, it executes automatically.
An ordinary member function, OTOH, is a different matter. A derived class is
there to alter or extend the behaviour of its base class, so it sometimes
is, and sometimes isn't, appropriate for a virtual function override to call
its base class version. For example, a virtual Clone function returns a new
copy of an object. Obviously, only one copy should be made and it should be
of the most derived class, so it would make no sense at all for any virtual
Clone function in a class hierarchy to call its base-class version.
Futhermore, even when a virtual function does call its base class version,
in some cases it should be called first, in others last, and in still others
somewhere in the middle of the derived class override. It all depends on
just how the derived class wants to modify/extend the base class's
behaviour.
For all these reasons, calling the base class version of an ordinary virtual
function from an override is left up to the programmer.
DW
"Calvin Lai" <ca********@i01 0.com> wrote in message
news:99******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Thanks Jeff. However, is this a logical reasoning of why this is happening by design, or there is other behind the door arguments for it?
I don't understand your question. If you mean why was the language
originally designed this way, Bjarne Stroustrup wrote a book about that.
From an object-oriented design perspective though (which is unrelated to the
C++ language per se), it makes good sense to me.
"Calvin Lai" <ca********@i01 0.com> wrote in message
news:99******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Thanks Jeff. However, is this a logical reasoning of why this is happening by design, or there is other behind the door arguments for it?
Calvin
It's by design. Perhaps the following (succint, yet dumb) code example will
help.
/////
#include <iostream>
#include <ostream>
class Base
{
public:
Base()
{
std::cout << "Base: " << foo() << std::endl;
}
virtual int foo() {return 3;}
virtual ~Base()
{
std::cout << "~Base: " << foo() << std::endl;
}
};
class Derived
{
int *x_;
public:
Derived() : x_ (new int (5))
{
std::cout << "Derived: " << foo() << std::endl;
}
int foo() {return *x_;}
~Derived()
{
std::cout << "~Derived: " << foo() << std::endl;
delete x_;
}
};
int main()
{
Derived d;
}
/////
creates output:
Base: 3
Derived: 5
~Derived: 5
~Base: 3
If Base could reach Derived::foo in its destructor, it would try to access
invalid memory. From a design point of view we get much better class
invariants* if we can assume a function will only be called on a constructed
object. Otherwise here we might need to (somehow) check in Derived::foo if
an actual Derived object exists or not - which seems kind of silly.
*: (Invariants are conditions that are always true for an object. An
invariant in Derived above is that x_ always points to a valid int, so we
never need to do the check x_ against NULL. Maintaining good invariants is
key to OO programming, and a motivating reason for data encapsulation.)
HTH
--
KCS
"Kevin Saff" <go********@kev in.saff.net> wrote in message
news:Hq******** @news.boeing.co m... "Calvin Lai" <ca********@i01 0.com> wrote in message news:99******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Thanks Jeff. However, is this a logical reasoning of why this is
happening by design, or there is other behind the door arguments for it? [SNIP]
If Base could reach Derived::foo in its destructor, it would try to access invalid memory. From a design point of view we get much better class
I totally misunderstood the question. How embarrassing! Guess I'm done for
the day.
--
KCS
Thanks all for your comments. They are very helpful. I got it now.
"Calvin Lai" <ca********@i01 0.com> wrote in message
news:99******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Thanks Jeff. However, is this a logical reasoning of why this is happening by design, or there is other behind the door arguments for it?
Calvin
"jeffc" <no****@nowhere .com> wrote in message news:3f******** @news1.prserv.n et... "Calvin Lai" <ca********@i01 0.com> wrote in message news:PA******** ************@ne ws04.bloor.is.n et.cable.rogers .com... Hi all,
I have a simple question. If I have a ClassA as base class, and ClassB derive from it. There is a virtual function foo() in ClassA, and in Class B, I defined a function called foo() as well (w/ or w/o declaring it as virtual doesn't matter since the virtual is inhered, right?).
Correct.
Both of them have a virtual destructor.
Now, here is the part of the code:
ClassA::foo() { cout << "In class A" }
ClassB::foo() { cout << "In class B" }
ClassA::~ClassA () { cout << "destroying A" }
ClassB::~ClassB () { cout << "destroying A" }
When deleting objectB (from ClassB), both destructors are called. However, when calling objectB's foo, only the classB's foo is called. Why is that? Because an object of type ClassB is actually composed of parts of both ClassA and ClassB. Let's say in ClassA there were a file, and in ClassB there was also a file. In an object of type ClassA, there will be 1
file. In an object of type ClassB, there will be 2 files. When you delete an object of ClassB, don't you want to make sure that both files are
closed? The closing of the file in ClassA should logically be closed in the destructor for ClassA. On the other hand, functions aren't the same as storage. Functions have to do with behavior, and if you want the
behavior of ClassB to be different from that of ClassA, then there's no reason to call ClassA's function. You could though. In ClassB::foo(), you could
make a call to ClassA::foo(). Then it would work the same way as the destructor calls.
This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: Ele |
last post by:
Is it correct to say that Whenever a class has a virtual member function,
define its destructor as "virtual"?
Can a destructor as "pure virtual"? When is it needed to do so?
For an interface, Interf:
class Interf
{
public:
|
by: ctick |
last post by:
A reason for declaring a "virtual destructor" for a Base class is to make
sure the destructor of Derived class will be invoked when a pointer of Base
type is used to delete an object of Derived.
Is this the only reason to define "virtual destructor" for a Base class?
Since it's always possible that users of any Base class will delete a...
|
by: Giancarlo Niccolai |
last post by:
Hello all.
I have peeked through the FAQ and all relevant links, and also through
Stroustrup book, but I have not been able to find an answer, so I have to
post here as a last resort.
It makes sense that if you have virtual destructors, they are eventually
used in the explicit destructor call when using the placement new semantic:
...
|
by: santosh |
last post by:
Hello,
I was going through the Marshal Cline's C++ FAQ-Lite.
I have a doubt regarding section 33.10.
Here he is declaring a pure virtual destructor in the base class.
And again defining it inline. Like this.
|
by: WittyGuy |
last post by:
Hi,
I wonder the necessity of constructor and destructor in a Abstract
Class? Is it really needed?
?
Wg
http://www.gotw.ca/resources/clcm.htm for info about ]
| |
by: pmizzi |
last post by:
When i compile my program with the -ansi -Wall -pedantic
flags,
i get this warning: `class vechile' has virtual functions
but non-virtual destructor, and the same with my
sub-classes. But when i add a virtual destructor like this :
" virtual ~vechile". I get this error:
Undefined first referenced
symbol ...
|
by: eric |
last post by:
hello
i'm confused by an example in the book "Effective C++ Third Edition"
and would be grateful for some help. here's the code:
class Person {
public:
Person();
virtual ~Person(); // see item 7 for why this is virtual
...
|
by: Jess |
last post by:
Hello,
If I have a class that has virtual but non-pure declarations, like
class A{
virtual void f();
};
Then is A still an abstract class? Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
|
by: Shraddha |
last post by:
What is the use of "PURE vitual distructors"?
And why we can not have vitual constructors?
|
by: GAURAV AGRAWAL |
last post by:
Hi Guys,
Can someone please explain me why this is happening
#include<iostream>
using namespace std;
class a {
public:
int a1; // If I remove this it'll work fine
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
| |
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it.
First, let's disable language...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols.
I succeeded, with both firewalls in...
|
by: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
|
by: bsmnconsultancy |
last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...
| |