Topic: C++ Problem
Author: cs911089@ariel.cs.yorku.ca (JASON H KELTZ)
Date: Fri, 25 Feb 1994 01:06:00 GMT Raw View
I'm not sure if this is the appropriate newsgroup for my problem because
I rarely have time to read news. If it's not, please tell me this, and
I'll post it to the appropriate group.
Here is my problem.
I have an ABSTRACT base class called employee.
There are two derived classes, one called hourly_employee, and one called
salaried_employee.
There is also a class called "roster" that is a list holding salaried and
hourly employees.
Because "employee" is an abstract base class (ie. it has at least 1 pure
virtual function), I CANNOT declare:
employee x;
... What C++ allows me to do is to create a pointer to an employee. The
object being pointed to would be either an hourly_employee or a
salaried_employee.
Each node of the list in "roster" is a structure with two items - one
being a pointer to the next node, and the other being a pointer to an
employee.
My "add_to_roster" function accepts a pointer to an employee, and adds it
to the roster. It gets a new list node, and puts it into place.
Everything works fine, but this is where the problem lies. When I go to
store the "employee" in the list, I do it like this:
employee_ptr -> info = emp;
Where emp was in the header of the add function defined as employee *. The
problem is simple - if I call a function, and that function creates an
hourly_employee, and it passes that hourly employee to the add function
to store it, everything will remain fine until I leave the function.
Once I do, the pointer is, of course, destroyed, and the list is now
"broken". What I'd like to be able to do when assigning the info field
is:
employee_ptr -> info = new employee;
*(employee_ptr -> info) = *emp; (invokes the assignment operator f'n
for employee)
This is what would be normally done if the list was holding say, integers,
or characters, BUT, this can't be done because the compiler doesn't allow
"new employee" since "employee" is an ABSTRACT base class.
So, as long as I keep to main() I am fine, but no other function can modify
the list, or the link will be lost as soon as the function exits. This
is what I believe to be very very poor design, and limits very much what I
can do.
It's taken me half a day to figure out whats going on here, and why my
computer was going bonkers (in some cases locking up, and in some
cases, totally resetting!) and yet I can't solve the problem.
If anyone has any idea of how I might solve this problem (employee must
remain an abstract base class though), please, if at all possible, EMAIL
me. I'd really appreciate it. There must somehow be a simple fix that
I'm overlooking.
Take care,
Jason Keltz
cs911089@ariel.cs.yorku.ca
Author: jamshid@ses.com (Jamshid Afshar)
Date: Fri, 25 Feb 1994 21:45:12 GMT Raw View
Redirected to comp.lang.c++.
In article <CLr9q1.C8F@ariel.cs.yorku.ca>,
JASON H KELTZ <cs911089@ariel.cs.yorku.ca> wrote:
>I'm not sure if this is the appropriate newsgroup for my problem because
>I rarely have time to read news. If it's not, please tell me this, and
>I'll post it to the appropriate group.
Comp.std.c++ is intended for discussion of issues directly related to
the evolving ANSI/ISO C++ Standard. General discussion/questions
should go to comp.lang.c++.
>I have an ABSTRACT base class called employee.
>There are two derived classes, one called hourly_employee, and one called
>salaried_employee. [...]
>Where emp was in the header of the add function defined as employee *. The
>problem is simple - if I call a function, and that function creates an
>hourly_employee, and it passes that hourly employee to the add function
>to store it, everything will remain fine until I leave the function.
>Once I do, the pointer is, of course, destroyed, and the list is now
>"broken". [...]
See Marshall Cline's comp.lang.c++ FAQ for a solution to your problem
(ftp rtfm.mit.edu, look in pub/usenet/comp.lang.c++). Add a pure
virtual clone() member function to employee and make sure you document
that your employee_list class makes a copy of the object passed -- the
caller still "owns" the object whose address was passed to
employee_list::add() (modifications to that employee won't change the
list, and the caller must make sure it gets deleted). Btw, look into
templates so that you don't have to write a company_list,
department_list, etc.
------
Q76: What is a `virtual constructor'?
A: Technically speaking, there is no such thing. You can get the effect you
desire by a virtual `create_copy()' member fn (for copy constructing), or a
`create_similar()' member fn (also virtual) which constructs/creates a new
object of the same class but is `fresh' (like the `default' [zero parameter]
ctor would do).
The reason ctors can't be virtual is simple: a ctor turns raw bits into a
living object. Until there's a living object against which to invoke the
member function, you can't expect a member function invocation to be handled
`the right way'. You can think of ctors as `class' [static] functions, or as
`factories' which churn out objects. Thinking of ctors as `methods' attached
to an object is misleading.
Here is an example of how you could use `create_copy()' and `create_similar()'
methods:
class Set { //normally this would be a template
public:
virtual void insert(int); //Set of `int'
virtual int remove();
//...
virtual Set* create_copy() const = 0; //pure virtual; Set is an ABC
virtual Set* create_similar() const = 0;
virtual ~Set() { } //see on `virtual destructors' for more
};
class SetHT : public Set {
public:
//...
Set* create_copy() const { return new SetHT(*this); }
Set* create_similar() const { return new SetHT(); }
protected:
//a hash table in here
};
A SetHT is-a Set, so the return value is correct. The invocation of
`SetHT(*this)' is that of copy construction (`*this' has type `const SetHT&').
Although `create_copy()' returns a new SetHT, the caller of create_copy()
merely knows he has a Set, not a SetHT (which is desirable in the case of
wanting a `virtual ctor'). `create_similar()' is similar, but it constructs an
`empty' SetHT.
Clients can use this as if they were `virtual constructors':
void client_code(Set& s)
{
Set* s2 = s.create_copy();
Set* s3 = s.create_similar();
//...
delete s2; //relies on destructor being virtual!!
delete s3; // ditto
}
This fn will work correctly regardless of how the Set is implemented (hash
table based, AVL tree based, etc).
See above on `separation of interface from implementation' for more.