How would you extend the functionality of a standard container?
sobes.tech AI
Answer from AI
There are several approaches:
-
Inheritance (public): Create a new class inheriting from the standard container. This allows direct use of parent class methods but may violate encapsulation and cause issues with polymorphism, especially when working with pointers or references to the base class.
#include <vector> template<typename T> class MyVector : public std::vector<T> { public: // Adding a new method void print_size() const { // Using base class method std::cout << "Size: " << this->size() << std::endl; } }; -
Composition (aggregation): Include an instance of the standard container as a data member in the new class. This is the preferred approach as it provides better encapsulation and more flexible management of functionality. Delegating method calls to the internal container is required.
#include <vector> template<typename T> class MyContainer { private: std::vector<T> data; public: // Delegating push_back method void push_back(const T& value) { data.push_back(value); } // Adding a new method void print_elements() const { for (const auto& elem : data) { std::cout << elem << " "; } std::cout << std::endl; } }; -
Using algorithms and functions: Add new functionality as free functions or algorithms that accept a standard container as an argument (possibly through iterators). This is the least invasive way, not modifying the container type itself.
#include <vector> #include <numeric> template<typename T> T sum_vector(const std::vector<T>& vec) { // Using a standard algorithm return std::accumulate(vec.begin(), vec.end(), T(0)); } -
Template wrappers (Wrapper classes): Create a template class that takes any container as a template parameter and adds new functionality to it. Similar to composition but more generalized.
#include <list> template<typename Container> class EnhancedContainer { private: Container data; public: // Methods delegating to the internal container auto begin() { return data.begin(); } auto end() { return data.end(); } // Adding a new method size_t get_approx_size() const { // Assuming this operation is expensive on some containers, // and we want to cache or process the size differently. // In this example, for simplicity, just return size(). return data.size(); } };
Comparison of approaches:
| Approach | Pros | Cons |
|---|---|---|
| Inheritance | Easy access to base class members | Violates encapsulation, potential issues with LSP |
| Composition | Good encapsulation, flexibility | Requires delegating method calls |
| Functions/Algorithms | Does not change container type, versatile | Not part of the container itself |
| Template Wrappers | Generality, applicable to various containers | Slightly more template code |
The choice of approach depends on the required functionality, the need to modify existing method behavior, and the level of encapsulation needed. Generally, composition is the most flexible and safe.