473,405 Members | 2,415 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

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

Why down-casting is done here?

The code is from a Meyers' book...

class BankAccount { ... }; // as above

// new class representing accounts that bear interest
class InterestBearingAccount: public BankAccount {
public:
virtual void creditInterest() = 0;

...

};

class SavingsAccount: public InterestBearingAccount {

... // as above

};

class CheckingAccount: public InterestBearingAccount {

... // as above

};

// better, but still not perfect
for (list<BankAccount*>::iterator p = allAccounts.begin();
p != allAccounts.end();
++p) {

static_cast<InterestBearingAccount*>(*p)->creditInterest();

}

Why did he use downcasting here to convert BankAccount* to
InterestBearingAccount*? Seems to this isn't necessary since
creditInterest() is a virtual function and creditInterest() in
InterestBearingAccount will be virtual and also in SavingsAccount and
CheckingAccount. So, (*p)->creditInterest(); will invoke creditInterest() in
SavingAccount or CheckingAccount as what virtual function supposes to work
like. Do I miss something? Thanks!

Jul 22 '05 #1
7 3013
On Sun, 02 May 2004 03:58:22 GMT, "mead" <ph******@light.com> wrote:
The code is from a Meyers' book...

class BankAccount { ... }; // as above
Note that, in BankAccount (Item 39 in Effective C++), there's no
creditInterest() member function.

[snip]

// better, but still not perfect
for (list<BankAccount*>::iterator p = allAccounts.begin();
p != allAccounts.end();
++p) {

static_cast<InterestBearingAccount*>(*p)->creditInterest();

}

Why did he use downcasting here to convert BankAccount* to
InterestBearingAccount*? Seems to this isn't necessary since
creditInterest() is a virtual function and creditInterest() in
InterestBearingAccount will be virtual and also in SavingsAccount and
CheckingAccount.
Yes, but the iterator refers to a BankAccount *, and as mentioned above,
those have no awareness of anything by the name of "creditInterest".
So, (*p)->creditInterest(); will invoke creditInterest() in
SavingAccount or CheckingAccount as what virtual function supposes to work
like.
At compile time, calls to member functions through pointers are checked for
legality according to the /static/ type of the pointer. IOW, at compile
time, the compiler can't know what is being pointed to. So it only goes by
what the class (BankAccount, in this case) provides.

Dynamic binding happens at run-time, but C++ requires the static check at
compile-time before the code can get to run-time...
Do I miss something? Thanks!
HTH,
-leor


--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Jul 22 '05 #2
"Leor Zolman" <le**@bdsoft.com> wrote in message
On Sun, 02 May 2004 03:58:22 GMT, "mead" <ph******@light.com> wrote:
for (list<BankAccount*>::iterator p = allAccounts.begin();
p != allAccounts.end();
++p) {

static_cast<InterestBearingAccount*>(*p)->creditInterest();

}

Yes, but the iterator refers to a BankAccount *, and as mentioned above,
those have no awareness of anything by the name of "creditInterest".


True, and a very good response, but the use of static_cast does ring bells.
Sure it is OK if you've enforced that every object in allAccounts is an
InterestBearingAccount, but in that case we should probably have used
list<InterestBearingAccount*>. I think it's safer to use dynamic_cast. You
have to compare the result of dynamic_cast to NULL, and only if it is not
NULL call the creditInterest virtual function. We could also add a virtual
function creditInterest to the base class with the default behavior to do
nothing. Not sure which is the better solution though.

Jul 22 '05 #3
Siemel Naran wrote:

"Leor Zolman" <le**@bdsoft.com> wrote in message
On Sun, 02 May 2004 03:58:22 GMT, "mead" <ph******@light.com> wrote:

for (list<BankAccount*>::iterator p = allAccounts.begin();
p != allAccounts.end();
++p) {

static_cast<InterestBearingAccount*>(*p)->creditInterest();

}

Yes, but the iterator refers to a BankAccount *, and as mentioned above,
those have no awareness of anything by the name of "creditInterest".


True, and a very good response, but the use of static_cast does ring bells.
Sure it is OK if you've enforced that every object in allAccounts is an
InterestBearingAccount, but in that case we should probably have used
list<InterestBearingAccount*>. I think it's safer to use dynamic_cast. You
have to compare the result of dynamic_cast to NULL, and only if it is not
NULL call the creditInterest virtual function. We could also add a virtual
function creditInterest to the base class with the default behavior to do
nothing. Not sure which is the better solution though.


To me, a dynamic_cast rings other bells (as it very often does). It might be
a sign we are putting more logic into this particular loop than we should.
If creditInterest() doesn't belong to the base class then I would prefer

for_each(allInterestBearingAccounts.begin(),
allInterestBearingAccounts.end(),
mem_fun(&InterestBearingAccoun::creditInterest));

where allInterestBearingAccounts might be, as you said, a
list<InterestBearingAccount*>.
It might as well be a result of a query (in /whatever/ form) for interest
bearing accounts based on allAccounts.

Denis
Jul 22 '05 #4
"Denis Remezov" <RE*********************@yahoo.removethis.ca> wrote in
message
Siemel Naran wrote:
True, and a very good response, but the use of static_cast does ring bells. Sure it is OK if you've enforced that every object in allAccounts is an
InterestBearingAccount, but in that case we should probably have used
list<InterestBearingAccount*>. I think it's safer to use dynamic_cast. You have to compare the result of dynamic_cast to NULL, and only if it is not NULL call the creditInterest virtual function. We could also add a virtual function creditInterest to the base class with the default behavior to do nothing. Not sure which is the better solution though.


To me, a dynamic_cast rings other bells (as it very often does). It might

be a sign we are putting more logic into this particular loop than we should.
If creditInterest() doesn't belong to the base class then I would prefer

for_each(allInterestBearingAccounts.begin(),
allInterestBearingAccounts.end(),
mem_fun(&InterestBearingAccoun::creditInterest));

where allInterestBearingAccounts might be, as you said, a
list<InterestBearingAccount*>.
It might as well be a result of a query (in /whatever/ form) for interest
bearing accounts based on allAccounts.


I think dynamic_cast has its place in good programming, although we should
take care to limit its use. Suppose you had a list of allAccounts where the
accounts may be interest or non-interest
bearing accounts. Now you want to construct a list of interest-bearing
accounts, for use in your code snippet above. You still have to use
dynamic_cast.

copy_if(allAccounts.begin(),
allAccounts.end(),
std::back_inserter(allInterestBearingAccounts),
isA<InterestBearingAccount>());

where

template <class T>
struct isA {
template <class U>
bool operator()(const U * u) const {
return dynamic_cast<const T *>(u);
}
};

BTW, the copy_if function above copies elements from the first container to
the new that meet a certain condition. But I don't think there is such a
function in the standard. Does anyone know of a similar function in the
standard? I think there's got to be one.

Jul 22 '05 #5
Siemel Naran wrote:
[snip]
I think dynamic_cast has its place in good programming, although we should
take care to limit its use. Suppose you had a list of allAccounts where the
accounts may be interest or non-interest
bearing accounts. Now you want to construct a list of interest-bearing
accounts, for use in your code snippet above. You still have to use
dynamic_cast.

I certainly agree in general, but I feel that by redesigning the base
BankAccount you could find a very sensible alternative or two in this specific
case.

[snip]
BTW, the copy_if function above copies elements from the first container to
the new that meet a certain condition. But I don't think there is such a
function in the standard. Does anyone know of a similar function in the
standard? I think there's got to be one.


Would be nice to have it, but I guess we cannot have everything.

Denis
Jul 22 '05 #6
"Denis Remezov" <RE*********************@yahoo.removethis.ca> wrote in
message
BTW, the copy_if function above copies elements from the first container to the new that meet a certain condition. But I don't think there is such a function in the standard. Does anyone know of a similar function in the
standard? I think there's got to be one.


Would be nice to have it, but I guess we cannot have everything.


replace_copy_if seems pretty close, but not exactly what I'm looking for,
because the destination container will always have the same size as the
source container.
Jul 22 '05 #7
On Sun, 02 May 2004 20:22:50 GMT, "Siemel Naran"
<Si*********@REMOVE.att.net> wrote:

copy_if(allAccounts.begin(),
allAccounts.end(),
std::back_inserter(allInterestBearingAccounts),
isA<InterestBearingAccount>());

where

template <class T>
struct isA {
template <class U>
bool operator()(const U * u) const {
return dynamic_cast<const T *>(u);
}
};

BTW, the copy_if function above copies elements from the first container to
the new that meet a certain condition. But I don't think there is such a
function in the standard. Does anyone know of a similar function in the
standard? I think there's got to be one.
This one would seem to have fallen through the cracks as far as the present
standard is concerned. Here's a work-around: use remove_copy_if with a
logically reversed predicate. Example:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

bool b20and30(int n) // predicate: true if n is between 20 and 30 (incl.)
{
return n >= 20 && n <= 30;
}

void showvec(const vector<int> &v)
{
for (int i = 0; i < v.size(); ++i)
cout << v[i] << " ";
cout << endl << endl;
}
int main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);

cout << "Original:" << endl;
showvec(v);

vector<int> result;
remove_copy_if(v.begin(), v.end(),
back_inserter(result),
not1(ptr_fun(b20and30)));

cout << "Result:" << endl;
showvec(result);

return 0;
}

Output, showing "b20and30" applied to a vector "as if" it were a copy_if
type of function:

Original:
10 20 30 40

Result:
20 30
-leor


--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Jul 22 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
by: PT | last post by:
I got a form with many text boxes, checkboxes and 3 drop downs. From that 3, 2 are dependant. I can choose one drop down, and the next drop down should display the dependant values of the first...
2
by: ehm | last post by:
I am working on creating an editable grid (for use in adding, deleting, and editing rows back to an Oracle database). I have a JSP that posts back to a servlet, which in turns posts to a WebLogic...
18
by: jrhoads23 | last post by:
Hello, I am trying to find a way to tell if an .NET windows forms Button (System.Windows.Forms.Button) is "depressed" (pushed down). For my application, I can not use a check box control set to...
3
by: Don Wash | last post by:
Hi There! I have a Server-side Drop-down box in ASP.NET (VB) page. What do I do to widen the Drop down box's Pull-Down list's width? I'm not talking about the Drop-down box's width but the box...
2
by: Yoshitha | last post by:
hi I have 2 drop down lists in my application.1st list ontains itmes like java,jsp,swings,vb.net etc.2nd list contains percentage i.e it conatains the items like 50,60,70,80,90,100. i will...
1
by: pmelanso | last post by:
Hello, I have a drop down list which is dynatically loaded from a database and I have a second drop down list that is also dynatically loaded depending on what is selected in the first drop down...
7
by: callawayglfr | last post by:
I am building a database in access where I have a drop down box that relates to a text box, that part I have working but when someone selects information from the first drop down I need it to limit...
8
by: Ed Dror | last post by:
Hi there ASP.NET 2.0 VB & SQL Express Lest take Northwind Categories Products as example I create a table that hold these two together and I create a stored procedure like select ProductID,...
3
by: penny111 | last post by:
Hi there, For my application, i need to have 3 drop down lists 1. drop down list of folder names 2. drop down list of documents in the folder selected 3. drop down list of instances of the...
6
by: zacks | last post by:
I have an application I am developing that has a Combo Box that is intended to show a list of available tables in the selected DSN. I have put code in the control's DropDown event handler to clear...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
marktang
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,...
0
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...
0
jinu1996
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...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
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,...

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.