Polymorphism and virtual Destructors

When operating on classes in inheritance hierarchies, we often maintain containers of base class pointers that hold addresses of derived objects.

Example 23.3 defines a Bank class that has a container of various kinds of Account.

Example 23.3. src/derivation/assigcopy/bank.h

#ifndef BANK_H #define BANK_H #include class Account; class Bank { public: Bank& operator<< (Account* acct); <-- 1 ~Bank(); private: QList<Account*> m_Accounts; }; #endif

(1)This is how we add object ptrs into m_Accounts.

Bank is able to perform uniform operations on its collected Accounts by calling virtual methods on each one.

Example 23.4. src/derivation/assigcopy/bank.cpp

[ . . . . ] #include "bank.h" #include "account.h" Bank::~Bank() { foreach (Account* acct, m_Accounts) { delete acct; } m_Accounts.clear(); }

In Example 23.4, delete acct causes an indirect call to the destructor of Account, as well as the subsequent release of allocated memory. However, while every address in the list is an Account, some (perhaps all) might point to derived-class objects and therefore require derived-class destructor calls.

If the destructor is virtual, the compiler allows run-time binding on the destructor call, instead of simply calling Account::~Account() on each one.

Example 23.5. src/derivation/assigcopy/bank.cpp

[ . . . . ] Bank& Bank::operator<< (Account* acct) { m_Accounts << acct; return *this; } int main(int argc, char* argv[]) { Bank b; Account* a1 = new Account(1, 423, "Gene Kelly"); JointAccount *a2 = new JointAccount(2, 1541, "Fred Astaire", "Ginger Rodgers"); b << a1; b << a2; } <-- 1

(1)At this point, the bank and all the accounts are destroyed.

Without declaring ~Account() to be virtual in the base class, we would get an incorrect result from running Example 23.5.[1]

[1] Compilers report a missing virtual in the destructor as a warning, and the behavior is undefined, so you may not see the same thing on your system.

Closing Acct - sending e-mail to primary acctholder:Gene Kelly Closing Acct - sending e-mail to primary acctholder:Fred Astaire

By making the destructor virtual, both types of Account will get destroyed properly and, in this example, both account holders of a joint account will get proper e-mail notifications when the Bank is destroyed.

Closing Acct - sending e-mail to primary acctholder:Gene Kelly Closing Joint Acct - sending e-mail to joint acctholder:Ginger Rodgers Closing Acct - sending e-mail to primary acctholder:Fred Astaire

If you declare one or more virtual methods in a class, you should define a virtual destructor for that class, even if it has an empty body.

Категории

© amp.flylib.com,