Can We Inherit STL Containers?
Last Updated :
24 Jul, 2024
In C++, a common question that arises in our mind is: Can we inherit from Standard Template Library (STL) containers like std::vector, std::map, or std::list? The straightforward answer is no, we should not inherit from STL containers.
In this article, we will learn why inheriting from STL containers is not advisable and explore some practical alternatives for extending their functionality.
Problem with Inheriting STL Containers
1. STL Containers Are Not Designed for Inheritance
In C++ , STL containers are designed to be flexible and efficient for managing collections of elements. They are intended to be used through composition rather than inheritance. This means they should be components within other classes, not base classes to inherit from.
2. Lack of Protected Members and Virtual Destructors
Most STL containers do not have protected members, which means they do not expose internal implementation details that we might want to override or extend. Additionally, STL containers lack virtual destructors. Without a virtual destructor, even if we inherit from an STL container and create objects dynamically, deleting a derived class object through a base class pointer (e.g., std::vector*) will lead to undefined behavior.
3. Inheritance Can Lead to Unexpected Behavior
Inheriting from STL containers and overriding their member functions can result in unexpected and undefined behavior. The internal logic of STL containers assumes its own implementation and extending STL containers may cause compatibility issues with standard algorithms and other parts of the STL, which expect a standard-compliant container.
4. Breaking Encapsulation
Inheriting from an STL container can expose internal data structures and behaviors, thus losing the encapsulation provided by the container. This can even lead to maintenance problems because changes in the implementation of the STL container might break our derived class.
Alternatives to Extend the Functionality of STL Containers
The following are some of the alternatives that can be used to extend the functionality of STL containers in C++:
1. Composition
In composition what we do is, create a new class that contains an STL container as a member, which allows us to add new functionalities while maintaining encapsulation. This approach is often referred to as a “has-a” relationship.
Example:
The below example demonstrates the usage of composition, it includes an example of a library class that has a std::vector<Book> as a member because a library “has-a” collection of books.
C++
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// Book class
class Book {
public:
// Public member variables for book title and author
string title;
string author;
// Constructor to initialize a Book object with a title
// and author
Book(const string& t, const string& a)
: title(t)
, author(a)
{
}
};
// Library class that uses composition with vector
class Library {
private:
// Private member vector to hold books
vector<Book> books;
public:
// Method to add a book to the library
void addBook(const Book& book)
{
books.push_back(book);
}
// Method to print all books in the library
void printBooks() const
{
for (const auto& book : books) {
cout << "Title: " << book.title
<< ", Author: " << book.author << endl;
}
}
};
int main()
{
// Create a Library object
Library library;
// Add books to the library
library.addBook(Book("The C++ Programming Language",
"Bjarne Stroustrup"));
library.addBook(
Book("Effective Modern C++", "Scott Meyers"));
// Print all books in the library
library.printBooks();
return 0;
}
OutputTitle: The C++ Programming Language, Author: Bjarne Stroustrup
Title: Effective Modern C++, Author: Scott Meyers
2. Aggregation
Aggregation is similar to composition only but it has a key difference that the contained objects (STL containers) can exist independently of the parent class. This is useful when the lifecycle of the contained objects is not tied to the lifecycle of the parent class.
Example:
The below example demonstrates the usage of aggregation that includes an example of a Project class that have a std::vector<TeamMember> as a member, where TeamMember instances can exist independently of the Project.
C++
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// TeamMember class
class TeamMember {
public:
// Public member variable for team member name
string name;
// Constructor to initialize a TeamMember object with a
// name
TeamMember(const string& n)
: name(n)
{
}
};
// Project class that uses aggregation with vector
class Project {
private:
// Private member vector to hold team members
vector<TeamMember*> teamMembers;
public:
// Method to add a team member to the project
void addTeamMember(TeamMember* member)
{
teamMembers.push_back(member);
}
// Method to print all team members in the project
void printTeamMembers() const
{
for (const auto& member : teamMembers) {
cout << "Team Member: " << member->name << endl;
}
}
};
int main()
{
// Create team member objects
TeamMember alice("Alice");
TeamMember bob("Bob");
// Create a Project object
Project project;
// Add team members to the project
project.addTeamMember(&alice);
project.addTeamMember(&bob);
// Print all team members in the project
project.printTeamMembers();
return 0;
}
OutputTeam Member: Alice
Team Member: Bob
3. Wrapper Classes
Wrapper class is another alternative in which we create a new class that encapsulates an STL container and provides additional functionalities. This is another way to achieve composition with more control over the interface exposed to the user.
Example:
The below example demonstrates the usage of wrapper class, it includes an example of a Queue class that wraps a std::deque to provide queue-specific operations.
C++
#include <deque>
#include <iostream>
using namespace std;
// Queue class that wraps deque
class Queue {
private:
// Private member deque to hold elements
deque<int> elements;
public:
// Method to enqueue an element
void enqueue(int element)
{
elements.push_back(element);
}
// Method to dequeue an element
int dequeue()
{
if (elements.empty()) {
throw out_of_range("Queue is empty");
}
int front = elements.front();
elements.pop_front();
return front;
}
// Method to check if the queue is empty
bool isEmpty() const { return elements.empty(); }
};
int main()
{
// Create a Queue object
Queue queue;
// Enqueue elements 1, 2, and 3 into the queue
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
// Dequeue and print all elements in the queue
while (!queue.isEmpty()) {
cout << queue.dequeue() << " ";
}
cout << endl;
return 0;
}
Conclusion
While it might seem very convenient to inherit from STL containers, but it introduces several risks and complications that we must avoid. Using composition, aggregation, or wrapper classes can help us extend the functionality of STL containers in a safer and more maintainable way. Therefore, the answer to whether we should inherit from STL containers is a definitive no.
Similar Reads
Pointers in Containers in C++ STL
Prerequisites: Pointers in C++Container in STL There are different containers in C++ having their own features where if are adding extra functionality of pointer it will contribute in a different way. Although not all of the containers are useful in this context so let's see a few of the containers
5 min read
What's a Linux Container?
The Linux container includes one or more processes that are isolated from the rest of the system. All of the files required to run them are provided by a separate image, ensuring that Linux containers are portable and consistent as they go from development to testing and ultimately to production. Th
7 min read
What is a Container ?
One of the greatest challenges in software development is ensuring that an app works similarly in a variety of environments. In earlier times, this has been attended to by working through a virtual machine (VM), but it's quite a heavyweight solution. That's when containers came along, as a more ligh
8 min read
What Is Container Network Interface (CNI) ?
Controlling networks within Kubernetes clusters is mostly dependent on the Container Network Interface (CNI). CNI is an important component of the Kubernetes environment that allows easy networking and communication between containers and other networks. Let's briefly discuss the Container Network I
8 min read
Containership in C++
We can create an object of one class into another and that object will be a member of the class. This type of relationship between classes is known as containership or has_a relationship as one class contain the object of another class. And the class which contains the object and members of another
5 min read
Containers in C++ STL (Standard Template Library)
Standard Template Library (STL) provides the built-in implementation of commonly used data structures known as containers. A container is a holder object that stores a collection of other objects (its elements). They are implemented as class templates, which allows great flexibility in the data type
3 min read
Where to Use a Particular STL Container?
The Standard Template Library (STL) in C++ has a variety of containers designed to store collections of data. Each container has unique characteristics and is optimized for different operations. One common question that arises is which STL container to use in a specific scenario. In this article, we
3 min read
Docker - Containers & Hosts
A common containerization tool in DevOps is Docker. It is an application deployment platform as a service for Docker containers. It consumes the least amount of resources, can be deployed more rapidly, and can scale easily while running your application inside of a container. Containers - Containers
5 min read
How to Write Our Own STL Container?
The Standard Template Library (STL) in C++ provides us with various data structures and algorithms. We have STL containers like vector, list, map, and set that we commonly use to store and manipulate data efficiently. However, there are situations where the existing STL containers may not meet our s
7 min read
What Is Containerd?
Containerd in simple terms is a container runtime that is, Containerd is a software responsible for running and managing containers on a host system. It is a resource manager which manages the container processes, image, snapshots, container metadata and its dependencies. Going further, Containerd i
10 min read