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.
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.
Best regards,
S. Bro
"I would be happy to deal with my problems one at the time if they would only line up!"
-Paul Cilwa, "Borland C++ Insider".
Other useful fora some of which I ruthlessly clipboarded from other peoples footers.
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::deque 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?
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.
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.
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++).
Bookmarks