-
October 16th, 2003, 04:59 AM
#16
I actually tried to take almost the same approach after all the comments to my other post saying that I couldn't derive from std::list but I found myself having to rewrite all the functions that come free with std::list!! So that was the reason that made me go back to the idea of derivation as it would make my instructor happy and would save me a lotta headache.
Can anybody give me a link to where I can find how the std::list is written so that I might just include all of it inside of my new class without having to derive.
Thanks.
Cheers,
Sofia.
-
October 16th, 2003, 05:02 AM
#17
Originally posted by sbrothy
Ofcourse this would so much simpler if you were allowed to derive from std::list. :-)
And how would we go about it in case we were!!
Thanks for taking time to explain all that by the way .
Sofia.
-
October 16th, 2003, 05:59 AM
#18
If this is an assignment it is conceivable that your instructor hides from you the fact that you shouldn't derive from std::list. The easy way, as you have already discovered, is doing it anyway and mentioning this when turning in your assignment. Never do it in real life! (And if you do it anyway at least inherit privately!)
Code:
/*
WARNING: This code derives from std::list which is something you should never do in real life because
it has a non-virtual destructor!
*/
#include <list>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
template<class T>
class OrderedList: public list<T> {
public:
OrderedList() {}
~OrderedList() {} // <-- Non-virtual destuctor! Same as std::list! This is one reason why you shouldn't derive from std::list
void pop_first(T t)
{
OrderedList<T>::iterator itr = find_if(begin(), end(), CompareType(t));
if (itr != end())
erase(itr);
}
private:
struct CompareType : public unary_function<T, bool>
{
CompareType(const T& t) : m_t(t) {}
bool operator()(const T& t) const { return (m_t == t); }
private:
T m_t;
};
};
class Employee
{
public:
Employee(const string name = "")
: m_name(name)
{
}
Employee(const Employee &emp)
: m_name(emp.getName())
{
}
bool operator==(const Employee &emp) const
{
return (m_name == emp.getName());
}
void setName(const string &name) { m_name = name; }
string getName() const { return m_name; }
friend ostream &operator<<(ostream &os, const Employee &emp)
{
return os << emp.m_name << endl;
}
private:
string m_name;
};
int main()
{
OrderedList<Employee> employees;
Employee e("Ford");
employees.push_back(e);
e.setName("Arthur");
employees.push_back(e);
e.setName("Zaphod");
employees.push_back(e);
for(OrderedList<Employee>::const_iterator it = employees.begin(); it != employees.end(); it++)
cout << *it;
// remove first employee named 'Arthur' from the list
e.setName("Arthur");
employees.pop_first(e);
for(OrderedList<Employee>::const_iterator it = employees.begin(); it != employees.end(); it++)
cout << *it;
return 0;
}
Note that the Employee class has an overloaded == operator for the comparison in CompareType. and a copy constructor for push_back.
-
October 16th, 2003, 09:53 AM
#19
Originally posted by megabyte
I actually tried to take almost the same approach after all the comments to my other post saying that I couldn't derive from std::list but I found myself having to rewrite all the functions that come free with std::list!!
Why are you trying to implement all the functions?
a) You implement the functions that you need to perform in terms of the std::list member.
b) You now have a chance to give your new functions names that can be understood by others using your class. For example, instead of erase(), you can now call your function EraseElementFromList() and you call your std::list erase function internally.
c) Who says that the class will always use a list? What if in the future, your class internals now want to use a std::map, a std::vector, or a std:eque instead of a std::list? You now have to force the user of the class to change their code, all because you've changed your base class from, say std::list to a std::map. If you did steps a) and b), the users of your new class will not have to change any code, since the underlying structure used is hidden from them.
Can anybody give me a link to where I can find how the std::list is written so that I might just include all of it inside of my new class without having to derive.
See steps a) and b). You create member functions that fit your needs for your class. If std::list::splice() is not necessary for your class, you don't need to include it. Your object has to make sense, and if splicing an ordered list (I believe this is what you wanted to do) doesn't make sense, why provide a member function for it?
Regards,
Paul McKenzie
-
October 18th, 2003, 03:24 AM
#20
Thanks a million for that nice explaination sbrothy.
I have a bit of a problem still though and I will really appreciate any help as this has been driving me nuts.
I have another function that is almost the same as the void pop_first(T t) above. The only difference is that this one erases the member and pushes it to the back of my list. Something like:
Code:
void pop_first_push_back(T t)
{
typename OrderedList<T>::iterator itr = find_if(begin(), end(), CompareType(t));
typename OrderedList<T>::iterator itr;
if (itr != end())
{
itrr=itr
erase(itr);
//push itrr to the back of my list
}
I don't know how to push back the member I'm erasing as I haven't declared any lists inside the scope(hence I can't do something like MyList.push_back(itrr); )
Thanks for any help.
Cheers,
Sofia.
-
October 18th, 2003, 05:45 AM
#21
Originally posted by megabyte
I don't know how to push back the member I'm erasing as I haven't declared any lists inside the scope(hence I can't do something like MyList.push_back(itrr);
You have a list<T>, therefore your list holds T, not iterators. You should be placing a T in the list.
Code:
void pop_first_push_back(T t)
{
typename OrderedList<T>::iterator itr = find_if(begin(), end(), CompareType(t));
T temp;
if (itr != end())
{
temp = *itr;
erase(itr);
push_back( temp );
}
}
Regards,
Paul McKenzie
-
October 18th, 2003, 05:49 AM
#22
Originally posted by sbrothy
Note that the Employee class has an overloaded == operator for the comparison in CompareType. and a copy constructor for push_back.
The Employee class does not need a user-defined copy constructor. The only member, a std::string is copyable, therefore there is no need for a user-defined copy constructor.
Also, if you are to provide a copy constructor, an assignment operator (which is also not necessary) should be provided, along with a destructor (the "rule of three" in C++).
Regards,
Paul McKenzie
-
October 20th, 2003, 11:55 PM
#23
Thank you very much for the explanation Paul.
Regards,
Sofia.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|