extending an STL container class Question
I have a class, "event_list", derived from the template class "vector." I extended it with a method, "write" for this new class. Here's its definition:
class event_list : public vector<Event>
{
public:
void write (ofstream &filename, format_type format, int start, int end);
};
For what it`s worth, the class "Event" is defined thus:
class Event
{
public:
int date;
string name;
string poc;
string type;
Event();
~Event();
void write(ofstream &filename, int start, int end);
};
In the "write" method for "event_list" (derived from vector), I want to go through every element and write it out. My problem is how to reference vector methods and operators within this method for the derived class. I currently have the following code, which will not compile:
void write (ofstream &filename, format_type format, int start, int end)
{
// write out vector contents
for (int indx = 0; indx < *this.size(); indx++)
{
current_date = *this[indx].date;
if (current_date != last_date)
{
last_date = current_date;
}
*this[indx].write(filename, start, end);
. . .
};
However, the compiler is telling me that this is and invalid use of "this" in non-member function (all 3 uses of "this"). I thought this was the way to do it.
Could anyone point out what I am doing wrong? Thanks, Alan
Re: extending an STL container class Question
There is no need to use *this to call vector member functions. Since you're using public inheritance, you can just use the method name itself. For overloaded operators, it's a bit more tricky, you have to write out the operator function's full name (e.g. operator[]).
Here's a version of you code that would work. Note the bolded areas:
Code:
void write (ofstream &filename, format_type format, int start, int end)
{
// write out vector contents
for (int indx = 0; indx < size(); indx++)
{
current_date = operator[](index).date;
if (current_date != last_date)
{
last_date = current_date;
}
operator[](indx).write(filename, start, end);
. . .
};
P.S: Your approach (using "this") would work, too, but you need to put brackets around "*this", because the membership operator has a higher precedence than the pointer dereferencing operator:
Code:
void write (ofstream &filename, format_type format, int start, int end)
{
// write out vector contents
for (int indx = 0; indx < (*this).size(); indx++)
{
current_date = (*this)[indx].date;
if (current_date != last_date)
{
last_date = current_date;
}
(*this)[indx].write(filename, start, end);
. . .
};
However, I think that using *this makes the code less clear (especially because you have to put the brackets around it), so I would stick with the first method.
Re: extending an STL container class Question
When I make those changes, the compiler complains that "size" is undeclared. It also complains that "operator[]" is not defined. Do I need to include some header file for the latter to work?
Thanks
Re: extending an STL container class Question
The following code compiles correctly on Dev-Cpp:
Code:
#include <vector>
#include <string>
using namespace std;
class Event
{
public:
int date;
string name;
string poc;
string type;
Event();
~Event();
void write(ofstream &filename, int start, int end);
};
class event_list : public vector<Event>
{
public:
void write (ofstream &filename, int start, int end)
{
// write out vector contents
for (int indx = 0; indx < size(); indx++)
{
int last_date;
int current_date = operator[](indx).date;
if (current_date != last_date)
{
last_date = current_date;
}
operator[](indx).write(filename, start, end);
}
}
};
Re: extending an STL container class Question
You're gonna get in trouble for deriving publicly from std::vector. ;)
Is there a reason you didn't just make write() a standalone function that took a vector<Event> reference as an argument? Heck, you could make it take iterators and that way your write function would work if you stored your Event objects in a vector, list, set, array, or any of a bunch of other containers.
If there is more to your event_list class, including extra state information, then you might also consider using containment instead of public derivation.
Re: extending an STL container class Question
jlou has hit th nail on the head. vector is not designed for public inheritance. It is, however, designed to be extended via separate algorithm functions.
Re: extending an STL container class Question
Do you need to publically inherit from vector. You are saying event_list is a vector. Personally I would have prefferred private inheritance or even better composition. These mean "is implemented in terms of" rather than "is a".I see this as a job for composition really but if you want to save a fair bit of coding at the expense of a quick hack then private inheritance would do. At least then you wouldn't be able to polymorphically delete event_list accidentally. Also do you need all those lovely vector functions in your public interface. Surely they would be better for you if they were private and for event_lists own internal use.
Re: extending an STL container class Question
Thank you for helping me sort out the syntax.
I use some standard vector member functions elsewhere in the code. I am still learning (obviously), but that is why I used public inheritance with vector. I evidently am still not clear on when to use composition versus inheritance.
I take it from some other stuff I read that the "list" container does not present the same concerns as "vector." Is that right? If so, why? Also, could you explain to me why "vector" is different?
Thanks, Alan
Re: extending an STL container class Question
Well in general public inheritance means "is a" or "is fully substitutable for".
Composition means "has a" or "is implemented in terms of".
Private inheritance means virtually the same as composition. You should favour composition over inheritance unless:-
you need to access protected members.
you need to override a virtual function.
There are a few other reasons too. This article helps explain the situation.
Re: extending an STL container class Question
Quote:
Originally Posted by jlou
You're gonna get in trouble for deriving publicly from std::vector. ;)
Is there a reason you didn't just make write() a standalone function that took a vector<Event> reference as an argument? Heck, you could make it take iterators and that way your write function would work if you stored your Event objects in a vector, list, set, array, or any of a bunch of other containers.
If there is more to your event_list class, including extra state information, then you might also consider using containment instead of public derivation.
The only time you could get in trouble in this case is if you had a vector<Event>* pointer that pointed to an event_list object alocated on the heap and tried to delete the object using the pointer. I mean, come on, what are the chances of that?
Re: extending an STL container class Question
Quote:
Originally Posted by HighCommander4
The only time you could get in trouble in this case is if you had a vector<Event>* pointer that pointed to an event_list object alocated on the heap and tried to delete the object using the pointer. I mean, come on, what are the chances of that?
You keep on riding this, don't you? ;) The point is that the chance is there... Someone might do it. And when they do, it's a very bad thing.
It's fair enough that you know that you can't delete through base class pointers for the classes you write, but other people using your code might not be aware of that. We shouldn't have to check if a class we use has a virtual destructor before we use it like that. Public inheritance, and it's implied IMO.
Re: extending an STL container class Question
Quote:
Originally Posted by jlou
Is there a reason you didn't just make write() a standalone function that took a vector<Event> reference as an argument? Heck, you could make it take iterators and that way your write function would work if you stored your Event objects in a vector, list, set, array, or any of a bunch of other containers.
That's what I did in the end. In this particular application, the way I was designing it, I had to pass parameters down to more than one level of function calls. It made things much cleaner and less confusing in this case.
Thanks, Alan
Re: extending an STL container class Question
Quote:
Originally Posted by Inspired
That's what I did in the end. In this particular application, the way I was designing it, I had to pass parameters down to more than one level of function calls. It made things much cleaner and less confusing in this case.
Excellent. I think it will make things more flexible for the future as well.
Quote:
Originally Posted by HighCommander4
The only time you could get in trouble in this case is if you had a vector<Event>* pointer that pointed to an event_list object alocated on the heap and tried to delete the object using the pointer. I mean, come on, what are the chances of that?
I meant that Inspired was going to get in trouble from the members of this forum. :D
The bigger problem besides that potentially undefined behavior is that the alternatives are often better. Most of us learn public inheritance early in our C++ development, so it is often the first option considered, but there are better options out there like standalone functions that the OP ended up using.
Re: extending an STL container class Question
Quote:
Originally Posted by wien
You keep on riding this, don't you? ;) The point is that the chance is there... Someone might do it. And when they do, it's a very bad thing.
If the ISO Standards Committee would have believed that public inheritance without dynamic binding is risky to use, it would have made dynamic binding the default for public inheritance and left no other alternative. However, the use of dynamic binding has a conisderably high overhead and its overuse can affect a program's performance.
One thing I always liked about C++ as a language is that, unlike Java, you don't have to pay for what you don't need. This is one of those cases where using dynamic binding is not necessary because no one in their right mind would ever use a pointer to a container, never mind assign a derived class object to it and then try to delete the derived class object through the pointer.
Think about it from a conceptual viewpoint: polymorphism (which, in my view, is the only case you need to use dynamic binding, certainly not for all instances of public inheritance) is used when objects of different type share a common interface and we need to be able to use this interface without having to know what each implementation does for each particular derived class. Right? vector<Event> and event_list, however, are classes that do not need to use polymorphism. The interfaces are the same: the OP hasn't redefined a single vector member function. He simply has added functionality in what I believe is the proper way to do so. I mean, why use private inheritance or containment in this case? Then you would need to write code that exposes each public vector member functions that the users of event_list need... what if all of vector's funtionality is needed by the users of event_list?
Quote:
Originally Posted by wien
It's fair enough that you know that you can't delete through base class pointers for the classes you write, but other people using your code might not be aware of that. We shouldn't have to check if a class we use has a virtual destructor before we use it like that. Public inheritance, and it's implied IMO.
Anyone who would try to use a vector<Event>* to point to an event_list object would know that the base class is vector. And everyone should know that STL classes do not have virtual destructors. However, as I asserted above, no one would ever need to do such thing, so their knowing or not knowing whether vector has a virtual destructor is not a problem in the first place.
I think the central idea here is that there is a difference between public inheritance and polymoprhism. Public inheritance does not always mean polymoprhism. It simply means IS-A. And in the OP's case, he is using it correctly: an event_list IS a vector. Since when should you not use public inheritance without polymorphism? Polymorphism is used for very specific needs and, as I mentioned earlier, it has a high overhead, so there is no need to use it unless those specific needs aren't present.
The reason the STL writers did not make the STL containers have virtual destructors is because they saw the containers unfit for use is a polymorphic situation (not because they saw them unfit for public inheritance - there is a difference). Yet you try to question this, and manage to come up with these highly unlikely scenarios where people would go against the design intended by the STL writers and try to (wrongly) use STL containers in a polymorphic way. Well, bad design has its consequences. In this case, trying to use vector, a well-known class in the standard library, polymorphically even though it's clearly not meant to be used so, may lead to undefined behaviour. So why worry about the trouble people get into when they use a bad design?
Re: extending an STL container class Question
HighCommander, you have a point. However, when someone starts out with the STL, I think it's much safer not to recommend public derivation from containers. The risks are there, and if you don't know what you're doing exactly, you'll get into trouble. It's safer not to derive from them, so I think that it's entirely justified to warn against that.
The other thing to take into consideration is that if you want to derive from an STL container, you probably didn't understand the STL's philosophy correctly. Most cases of derivation are there to extend functionality and add new member functions. However the philosophy of the STL is that functions acting on the data should be decoupled from the containers. Take iterators and you'll have a much more powerful function than before. This is another point that I think is important to show to people who start out with the STL and which again speaks against public derivation.