0

I am about to "create" my own vector class for a library I am writing. I won't really create a vector class from scratch, but just use std::vector as a parent class and add some stuff to my derived vector class.

Now, that said, I need a bit of advice. My questions are:

1) Is it a bad idea to call my derived class vector (inside of another namespace, of course)? What kind of conflicts will I have in this case?

2) I want to overload the math operators to be able to add vectors, multiply vectors by constants etc. This is actually the reason why I decided to build a vector class on top of std::vector. I could, however, overload the math operators for std::vector directly and save myself the trouble of creating (yet another...) vector class -- but is this a bad idea?

3) I would very much like to inherit the constructors from std::vector, but I am having lots of trouble getting this done without compiler errors. Could someone please provide me with a concrete example showing me how can this be done?

Thank you!

pap42
  • 1,236
  • 1
  • 17
  • 28
  • 5
    In 99.9% of cases, it's bad to derive from the standard containers. – chris Mar 03 '13 at 20:18
  • See also http://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector – Andreas Fester Mar 03 '13 at 20:18
  • 3
    You should strongly consider composition rather than inheritance (i.e. use a `std::vector` internally). – Oliver Charlesworth Mar 03 '13 at 20:22
  • @OliCharlesworth: yeah, but then I won't have the functions from `std::vector` on my derived class (unless I write them all as calls to the functions of `std::vector`, of course)... – pap42 Mar 03 '13 at 20:23
  • The fact is that the standard library is not meant to be extended. – Shoe Mar 03 '13 at 20:32
  • @Jeffrey: why? I understand that `std::vector` does not have a virtual destructor, but for what I am doing this has no effect. I'm working on a small private project. – pap42 Mar 03 '13 at 20:34
  • @Jeffrey - far too broad a statement. Certainly standard containers are not intended for use as base classes, but there are **many** ways to extend the standard library, and there are quite a few provisions that are there in order to **support** extension. – Pete Becker Mar 03 '13 at 22:06
  • Regarding (2), have you checked whether `valarray` suits your purposes? I think it's deprecated in C++11, but that doesn't mean it's going to disappear any time soon. – Steve Jessop Mar 04 '13 at 00:00
  • @PeteBecker, "Author of The C++ Standard Library Extensions". Wow. – Shoe Mar 04 '13 at 11:50
  • @SteveJessop - `valarray` is not deprecated. – Pete Becker Mar 04 '13 at 13:26

3 Answers3

3

I would discourage you from doing that. If you need a new container, just embed (or inherit privately from) std::vector<> rather than inheriting publicly from it.

Concerning your questions:

1) Is it a bad idea to call my derived class vector (inside of another namespace, of course)? What kind of conflicts will I have in this case?

As long as neither you nor any of your clients will import both the std namespace and your namespace through using directives, I do not see particular problems with this.

2) I want to overload the math operators to be able to add vectors, multiply vectors by constants etc. This is actually the reason why I decided to build a vector class on top of std::vector. I could, however, overload the math operators for std::vector directly and save myself the trouble of creating (yet another...) vector class -- but is this a bad idea?

Yes, this is a bad idea. If you created overloads of the math operators for std::vector, you could not create them in the namespace where std::vector belongs. By ADL, a global operator + is likely to be found in that namespace, even if not suitable. If that's the case, your operator + won't even be looked up, and you will get a compiler error.

3) I would very much like to inherit the constructors from std::vector, but I am having lots of trouble getting this done without compiler errors. Could someone please provide me with a concrete example showing me how can this be done?

In C++11, you could use inherited constructors. For instance:

#include <vector>

template<typename T, typename Allocator = std::allocator<T>>
class myvector : public std::vector<T, Allocator>
{
    using typename std::vector<T, Allocator>::vector;
};

#include <iostream>

int main()
{
   std::vector<int> vi { 1, 2, 3, 4, 5};

   // Uses inherited constructor
   myvector<int> v(vi.begin(), vi.end());

   for (auto i : v) { std::cout << i << " "; };
}

Here is a live example of this working with GCC 4.8.0 (beta), which supports inherited constructors.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
2

First, be aware that you can obfuscate your inheritance if you like. Use private inheritance, and then make all the functions of vector available with using statements. It's still a fair amount to type, since vector has a lot in it, but it's nothing like as much as explicitly delegating every function and it prevents the usual objections to inheritance, that people will accidentally slice your derived class and/or delete it using the wrong type when there's no virtual destructor. Not that anyone should be deleting vector anyway.

1) using the same name from namespace std is not inherently a problem (that's what namespaces are for, after all), but it might be confusing for readers sometimes. They might just assume you've done using std::vector; somewhere. This is their own fault, but if you can think of another suitable name then there's nothing to be gained from punishing your readers for their mistakes.

2) You can overload operators for standard classes, but not in the std namespace. This leaves a question what scope you should overload them in. Generally you don't want to put stuff into the global scope in a header file, but you could for example put them in a namespace called vector_arithmetic and then put using namespace vector_arithmetic; into each scope from which you want to use them. Just because you can do it doesn't mean it's wise -- readers expect to know what operators are available for common classes like vector, and changing the set of available operators might frighten and disturb them.

3) If you don't have C++11 constructor inheritance, you cannot inherit constructors. Instead you need to laboriously write out your own constructors that take the right parameters and call the appropriate base class constructor in the initializer list. The standard (or other documentation) will tell you all the constructor signatures you need. Take especial care with the templated constructor and note that the constructors aren't the same in C++03 and C++11.

Finally, consider just writing some free functions:

template <typename T>
T sequence_add(const T &lhs, const T &rhs) {
    if (rhs.size() != lhs.size()) throw std::logic_error("size mismatch");
    T result(lhs.size());
    std::transform(lhs.begin(), lhs.end(), rhs.begin(), result.begin(),
        std::plus<typename T::value_type>()
    );
    return result;
}

std::vector<int> i,j;
std::vector<int> k = sequence_add(i,j);

and so on. If operator overloads are going to cause confusion then they're generally not worth it.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
1

1) Write your own vector under your namespace. But, try to not derive from STLs.

2,3) Forget std::vector, write your own methods and operators.

Also, you can wrap std::vector in your new class and write interfaces to manipulate it.

masoud
  • 55,379
  • 16
  • 141
  • 208