inherit from std::vector

Guys, i am confused.

On some pages i find people saying that i MUST NOT inherit from std::vector, but after writing some lines of code for a class i realised that this is actually just a std::vector with a variable...

I'll just dump some code...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
template <typename T>
class Tree
{
private:
	class Node : public Tree<T>
	{
	public:
		Node() {}
		Node(T val) : mValue(val) {}

		void SetValue(T val) { mValue = val; }
		T GetValue() const { return mValue; }

	private:
		T mValue;
	};

public:
	Tree() {}
	Tree(T value) { mNodes.push_back(Node(value)); }

	const Node& operator[](unsigned int pos) const { return mNodes[pos]; }
	unsigned int size() const { return mNodes.size(); }

	void insert(T NewTree, unsigned int pos) { mNodes.insert(pos, Node(NewTree)); }
	void push_back(T NewTree) { mNodes.push_back(NewTree); }
	void erase(unsigned int pos) { mNodes.erase(pos); }

private:

	std::vector<Node> mNodes;
};


this is basically just a std::vector of nodes, and nodes are a std::vector of nodes with a value, right?

I'd just like to do something like that now:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
class Node : public std::vector<Node<T>>
{
public:
    Node() {}
    Node(T val) : mValue(val) {}

    void SetValue(T val) { mValue = val; }
    T GetValue() const { return mValue; }

private:
    T mValue;
};
template <typename T>
using Tree = std::vector<Node<T>>;
edit: found the correct syntaxes

Is it allowed to inherit from std::vector?
If no, what is the right way to do it?

edit 2: Is it possible to hide the implementation of Node? i tried a few different things but compiler says no
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <typename T>
class Tree : public Tree::Node<T>
{
	class Node : public std::vector<Node<T>>
	{
	public:
		Node() {}
		Node(T val) : mValue(val) {}

		void SetValue(T val) { mValue = val; }
		T GetValue() const { return mValue; }

	private:
		T mValue;
	};
};
if it is not possible, how can i safely hide the Implementation?
Last edited on
If you don't want the other classes to know that Node is inheriting from std::vector you can use private instead of public inheritance.

 
	class Node : private std::vector<Node<T>>

Nah, that's not the problem, i just don't want to pollute the global namespace.

So, does that mean that it is allowed to inherit from std::vector?
Yes you are allowed to inherit from std::vector, but if you use public inheritence, you should be aware that deleting a Node (or Tree) object through a std::vector pointer is not allowed because std::vector doesn't have a virtual destructor.

1
2
3
4
5
6
7
8
9
10
template <typename T>
void deleteVector(std::vector<T>* p)
{
	delete p;
}

int main()
{
	deleteVector(new Tree<int>); // undefined behaviour
}


Also some vector functions will not make much sense on the Tree (e.g. the size() function will not return the number of nodes in the whole tree.).

It is ok to inherit publicly from std::vector<> as long as:

a. We remember that every operation provided by std::vector<> must be a semantically valid operation on an object of the derived class

b. We avoid creating derived class objects with dynamic storage duration.
(std::vector<> does not have a virtual destructor).

The standard library vector does not guarantee range checking. For example:
1
2
vector<Entry> phone_book(1000);
int i = phone_book[2001].number; // 2001 is out of range 

That initialization is likely to place some random value in i rather than giving an error.
This is undesirable and out-of-range errors are a common problem.
Consequently, I often use a simple range-checking adaptation of vector:
1
2
3
4
5
6
7
8
9
10
template<typename T>
class Vec : public std::vector<T> {
public:
    using vector<T>::vector; // use the constructors from vector

    T& operator[](int i) { return vector<T>::at(i); } // range-checked

    const T& operator[](int i) const { return vector<T>::at(i); } // range-checked
    // for const objects; 
};

Vec inherits everything from vector except for the subscript operations that it redefines to do range checking. The at() operation is a vector subscript operation that throws an exception of type out_of_range if its argument is out of the vector’s range.

An out-of-range access will throw an exception that the user can catch.

Stroustrup in A Tour of C++ (draft): http://isocpp.org/files/papers/4-Tour-Algo-draft.pdf
Last edited on
Very nice, thank you JLBorges!
That's a nice answer and it answers the question in the Thread Name.

That leaves me with one unanswered question:
Is there a way to not pollute the global namespace with the Node Class?

At the moment it looks like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <typename T>
class Node : public std::vector<Node<T>>
{
public:
	Node() {}
	Node(T val) : mValue(val) {}

	T operator=(T val) { return mValue = val; }
	T value() { return mValue; }

private:
	T mValue;
};

template <typename T>
using Tree = std::vector<Node<T>>;


I'd like to have something like this:
1
2
3
4
5
6
7
class Tree : std::vector<Tree::Node<T>>
{
    class Node : public std::vector<Node<T>>
    {
        // stuff 
    }
}


but this seems like it is just not possible because the Nested class gets "created" after the Tree class, right?
Last edited on
I'll just put it in a namespace, that way it won't pollute the global namespace


Thanks for all your helps!
Topic archived. No new replies allowed.