The STL containers are largely used. Sometimes, they could be badly used. Let’s see an example for the std::queue.
#Design a class reusing methods from a STL Container
#A bad class design example: a class inheriting from a STL container
When thinking to this problem, it is easier to think of designing a class that directly inherits from the std::queue all of its functions. In the derived class, then all the additional methods can be implemented.
For easy of understanding, let’s assume we need to implement our own MyQueue class. This class is expected to provide the same functionalities of the std::queue<> with some additional methods (for the goal of this article, we can ignore these methods).
template<typename T>
class MyQueue : public std::queue<T>
{
public:
MyQueue();
virtual ~MyQueue();
void SomeAdditionalMethod(int x);
};
template<typename T>
MyQueue<T>::MyQueue()
{
std::cout << "Constructor called" << std::endl;
}
template<typename T>
MyQueue<T>::~MyQueue()
{
std::cout << "Destructor called" << std::endl;
}
template<typename T>
void MyQueue<T>::SomeAdditionalMethod(int x)
{
// ...
}
int main()
{
std::queue<int>* ptr = new MyQueue<int>();
ptr->push(5);
std::cout << ptr->size() << std::endl;
delete ptr; // DANGER!
return 0;
}
Constructor called
1
Press any key to continue . . .
The answer is that the STL containers are not designed to be inheritable. No virtual methods, all data members are private, no protected getters or setters functions… and – above all – no virtual class destructors …
#The correct class design: when the class has a STL container
template<typename T>
class MyGoodQueue
{
public:
MyGoodQueue();
virtual ~MyGoodQueue();
void SomeAdditionalMethod(const int x);
void push(const T& x);
size_t size() const;
private:
std::queue<T> q;
};
template<typename T>
MyGoodQueue<T>::MyGoodQueue()
{
std::cout << "Constructor called" << std::endl;
}
template<typename T>
MyGoodQueue<T>::~MyGoodQueue()
{
std::cout << "Destructor called" << std::endl;
}
template<typename T>
void MyGoodQueue<T>::SomeAdditionalMethod(int x)
{
// ...
}
template<typename T>
void MyGoodQueue<T>::push(const T& x)
{
q.push(x);
}
template<typename T>
size_t MyGoodQueue<T>::size() const
{
return q.size();
}
Constructor called
1
Destructor called
Press any key to continue . . .
