"Alden Pierre" <apierre@tellurian.com> wrote in message
news:crGdnT4Rt_r0dK7ZnZ2dnUVZ_u-dnZ2d@garden.net...[color=blue]
> Howard wrote:[color=green]
>> "Alden Pierre" <apierre@tellurian.com> wrote in message
>> news:BdudnZtZxct6RK7ZnZ2dnUVZ_tCdnZ2d@garden.net.. .[color=darkred]
>>> Hello,
>>>
>>>
http://www.parashift.com/c++-faq-lit....html#faq-20.7
>>>
>>> As per the link above it's wise to have a virtual deconstructor when
>>> creating an abstract class. Here is when I'm little confused. Am I
>>> deleting the right object when I call the virtual deconstructor?[/color]
>>
>> You don't call the destructor. It is called for you when an object is
>> destroyed (either by calling delete on a pointer to the object, or when
>> an object goes out of scope).
>>[color=darkred]
>>> I was under impression when creating a class if I'm not specifically
>>> allocating memory, do not implement deconstructor and let the default
>>> take care of it for you. I have the following code:
>>>[/color]
>>
>> Generally, that's true. But, if you intend to inherit from the class
>> (which you'd have to do if it's abstract and you ever want to use it),
>> AND if you intend to delete an object of the inherited class via a
>> pointer to the base class, THEN your destructor needs to be virtual.
>>
>> The question is, do you really need an abstract class here? And, will
>> you later be deleting an instance of an inherited class via a pointer to
>> the base class? By that I mean something like:
>>
>> Person* person = new SpecialPerson(); // where SpecialPerson inherites
>> from Person
>> ...
>> delete person;
>>
>>[color=darkred]
>>> -------------------------------------------------------------------------
>>> File: person.h
>>> -------------------------------------------------------------------------
>>> #ifndef _PERSON_H
>>> #define _PERSON_H
>>>
>>> #include <iostream>
>>> using std::string;
>>>
>>> class Person
>>> {
>>> public:
>>> Person( string, string );
>>>
>>> void setName( string );
>>> void setSSN( string );
>>>
>>> const string getName( void ) const {return name;}
>>> const string getSSN( void ) const {return ssn;}
>>>
>>> virtual void print( void ) = 0;
>>> virtual ~Person();
>>>
>>> private:
>>> string name;
>>> string ssn;
>>> };
>>> #endif
>>>
>>> -----------------------------------------------------------------------------------------
>>> File: person.cpp
>>> -----------------------------------------------------------------------------------------
>>> #include "person.h"
>>>
>>> using std::cout;
>>> using std::endl;
>>>
>>> Person::Person( string in_name, string in_ssn )
>>> {
>>> setName( in_name );
>>> setSSN( in_ssn );
>>> }
>>>
>>> Person::~Person()
>>> {
>>> delete this; // would this delete any derived class? return;[/color]
>>
>> Don't do this. The destructor (this one) is called FOR YOU when the
>> object is deleted, so calling delete here would be redundant (and BAD).
>>
>> And the return statement is also unneeded, (unless you're trying to
>> return before executing some action below it in the function, or if
>> you're returning a value). Just drop out of the function to exit.
>>[color=darkred]
>>> }
>>>
>>> void Person::setName( string in_name )
>>> {
>>> name =in_name;
>>> }
>>>
>>> void Person::setSSN( string in_ssn )
>>> {
>>> ssn =in_ssn;
>>> }
>>>
>>> void Person::print( void )
>>> {
>>> cout << "Name: " << name << endl;
>>> cout << "SSN: " << ssn << endl;
>>> }[/color]
>>
>> Any reason you have a body for the print function here, when you've
>> declared it as pure virtual (by adding the "= 0" to the declaration in
>> the class definition above)?
>>
>> -Howard[/color]
>
> Yes, this is by request through my prof. The classes which derive from
> person is the following: student, faculty, and admin. They all implement
> there on print function as well. Student will print name, ssn, and major.
> Faculty will print name, ssn, and dept. Last, but not least, admin will
> print name, ssn, title, and boss. I guess the reason behind this request
> is not to type too much. So within the derived class implementation file,
> I would have something like this as my print function: Person::print() and
> then cout << data-member.
>
> Regards,
> Alden[/color]
Honestly, this is a terrible design. In partitioning software functions you
should frequently ask yourself, "what does X have to do with Y?" In this
case, what does personal data such as name and ssn have to do with printing
anything? Absolutely nothing.
Stroustrop talks about abstract data types such as:
class Printable
{
public:
virtual void print() = 0; // nothing but pure virtual functions and...
~Printable() {} // a do-nothing virtual destructor
};
and concrete data types such as
class Person
{
private:
std::string m_name;
std::string m_ssn;
public:
// no virtual functions
Person(std::string const &i_name, std::string const &i_ssn) :
m_name(i_name), m_ssn(i_ssn) {}
std::string const &name() const {return m_name;}
std::string const &ssn() const {return m_ssn;}
};
Then you can print any way you want without using Printable in any way:
std::ostream &
print_my_way(std::ostream &os, Person const &p)
{
os << p.name() << ' ' << p.ssn() << '\n';
return os;
}
std::ostream &
print_your_way(std::ostream &os, Person const &p) {...}
This gives just as much flexibility as virtual functions without breaking
encapsulation in Person. (All code is unchecked and typed quickly over lunch
hour.)
I generally only use abstract data types if I want to create a collection of
smart pointers to a common base class -- in other words a collection of
things that have a common interface but different actual types.
Cy