1

I currently have a matrix class which is a std::vector<std::vector<double>>. I also have a vector class (not to get confused with stl's vector its more of math's vector of 1,2,3 .. dimension) which is a std::vector<double>.

After I made these two class I came into problem since now I wanted to do tmp_vector*tmp_matrix but since they are of different type I was not able to do it.

So my question is:

What would be a appropriate design choice?

  • Should I inherit both matrix and vector from same class (lets say for example matvec class which is just a empty class) or
  • should I inherit vector from matrix class (Here I am inheriting vector from a heavy matrix class)
pokche
  • 1,141
  • 12
  • 36

2 Answers2

3

Should I inherit both matrix and vector from same class?

I suppose that such design won't help you to get multiplication work.

Should I inherit vector from matrix class?

May be. But if I were you, I wouldn't do so if a single reason is an implementation of multiplication operation.

I advice you to simply overload operator* for both (vector, matrix) and (matrix, vector) combinations. I believe that it is the most natural way to solve the problem.

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
2

In general implementing classes that represent (mathematical) vectors and matrices as derived classes from stl vector or vector of vectors isn't very efficient. What's mostly done in numerical libraries is have a Matrix class that doesn't derive from anything, but contains a pointer to a very simple and straight one-dimensional array of e.g. doubles, not using stl at all.

Behaviour as multi-dimensional matrix is achieved by suitably overloading the () operator, to do the proper index computations.

Vectors could very well be Matrices with either one column or one row, since you can have multiple overloads of () as long as the parameter lists are different. This would allow you to address elements in your Vector's with only one index.

You can overload +, - and * for these classes, and give them conversion constructors. Don't forget to add a destructor to deallocate the memory and a copy constructor to prevent two such matrices from sharing the same memory.

You also need to overload the assignment operator, for the same reason. It should deallocate the old contents of the lefthand side of your assignments and reallocate the right amount of memory.

Jacques de Hooge
  • 6,750
  • 2
  • 28
  • 45
  • 1
    Simple example of what Jacques is talking about in the first half of his answer: https://isocpp.org/wiki/faq/operator-overloading#matrix-subscript-op – user4581301 Oct 25 '16 at 18:54
  • @user4581301 (I actually meant this question for op but you can chime in if you want) Why wouldn't using a std::vector as container be efficient, wouldn't allocating and maintaining a dynamically allocated memory be over kill or be like re-inventing a wheel ? If its efficiency then I don't see any data anywhere which proves your statement though ( just saying) – pokche Oct 25 '16 at 19:19
  • 2
    Look at the source code of ANY major numerical processing library if you want to see it... And it is not difficult at all, made things like that for as long as I can remember. – Jacques de Hooge Oct 25 '16 at 19:29
  • 1
    @pokche `vector` is great. It's awesome actually. Makes life so much easier. But... There is no such thing as a 2D vector. There is only `vector` containing `vector` which mean you actually have N+1 `vector`s scattered through RAM with nothing but a logical connection between them. This leads to low spatial locality and poor caching behaviour. The logic off the program is no slower, but the actual handling of the data by the CPU is hindered because it's ability to look ahead and preload data is diminished. Waiting for the CPU to get data from RAM can slow things down by orders of magnitude. – user4581301 Oct 25 '16 at 19:34
  • 1
    The Take-away: Use `vector` for the automatic memory management unless you have a really good reason not to. But use a 1D `vector` and do the 2D to 1D indexing math by hand. And since doing the math by hand means a lot of repetition, sooner or later you'll slip up and introduce a bug, so you want to wrap that 1D `vector` in a class and provide an access function to do the indexing math only in that one function. – user4581301 Oct 25 '16 at 19:38
  • @user4581301 Thank you for the detailed answer. For some reason I thought 2d vector are contiguous, details are discussed here too (http://stackoverflow.com/questions/6465133/stdvector-and-contiguous-memory-of-multidimensional-arrays). So for matrix I am planning to use 1D vector which can hold 2d length and use access function which would help map logical 2d into 1d. – pokche Oct 25 '16 at 19:54
  • 1
    1 `vector` is contiguous. But a `vector` is basically a set of pointers to a dynamically allocated block of memory. The outer `vector` contains a pointer to N contiguous `vector`s, but in each of those inner `vector`s is a pointer to their own dynamically allocated block. That ruins the contiguity. You can have a `vector` of fixed-size arrays to maintain contiguity, for example an Nx3 matrix, but if both dimensions are configurable, you're stuck. – user4581301 Oct 25 '16 at 20:21
  • 1
    @pokche That sounds reasonable, but remember a vector is just a matrix with one of the dimensions set to 1. Rather than inheriting or overloading you may be able to solve this with an indexing operator with a default value of 1. eg: `double& Matrix::operator() (unsigned row, unsigned col = 1)` Now you can use a matrix for both cases and still eat the one passed parameter cake. – user4581301 Oct 25 '16 at 20:26
  • @user4581301 but what if I want to call `matrix with col = 1` a special name in our case a `vector`. Because if we do 'double& Matrix::operator() (unsigned row, unsigned col = 1)' then we are stuck with Matrix only aren't we? – pokche Oct 26 '16 at 00:42
  • @user4581301 What I meant to say was .. we won't have another type called vector anymore and we are stuck with type Matrix only. – pokche Oct 26 '16 at 00:50
  • @pokche Yes, but why have a whole extra class to handle what's essentially a special case of another? Code that doesn't exist has no bugs. – user4581301 Oct 26 '16 at 02:15