Use Inheritance, Multiple Inheritance, and Polymorphism to solve a problem Implement Operator Overloading

Implement Iterators

Gain exposure to Google Test


Matthew’s Stats


Time taken: 2 hours Files: 26

Lines of Code: 1106 including whitespace and comments


Restrictions and Requirements


No global variables may be used

You may NOT change the signatures of any of the provided methods You may add additional members and methods if you wish

You may NOT remove any methods

Again, adding members and methods is completely fine All code must be a part of the Matrix namespace

Everything I've started you with is already inside of it


Problem Description

Implement a library that allows users to create classes that represent mathematical Matrices and Vectors as well as provide some basic methods on them. If you have never done any matrix or vector arithmetic please read the following

Matrix Addition Matrix Multiplication

Vector addition is the same as matrix addition. Just treat each vector as a 1 X N matrix Dot Product

Multiply the elements in the corresponding positions together and then sum the products


Scalar Arithmetic

The scalar operations that you have to implement don't technically exist in Vector/Matrix arithmetic. What you should do is add/subtract/multiply the scalar with each element in the Vector/Matrix.


Scalar Arithmetic Examples


{1, 2, 3} + 10 == {11, 12, 13}

{10, 20, 30} - 5 == {5, 15, 25}

{1, 2, 3} * 2 == {2, 4, 6}

Inheritance in the Problem

To avoid rewriting code we will be using inheritance. Admittedly, this is probably the worst reason to use inheritance but it does give us a chance to practice with the technique.




An abstract class that contains all of the operations you can perform on a Vector without modifying it.




An abstract class that represents all of the operations you can perform on a generic Vector. Inherits from ConstBaseVector




The concrete Vector class. Inherits from BaseVector




A class that represents a reference to a vector. We can't get away with just a Vector& in this problem because when we build the Matrix class we will want to be able to get a column. A column is a Vector, but there won't be a physical Vector in the Matrix class that holds the column so we have to create a VectorRef over this logical Vector.

Inherits from ConstVectorRef AND BaseVector




The const version of VectorRef Inherits from ConstBaseVector



You will have to provide iterators for both your Vector and Matrix classes. For Vector, you have VectorIterator and ConstVectorIterator which are random access iterators. Random access means in addition to being able to go forward we can also go backward and are also able to access any element in the container through this iterator.

Matrices have RowIterators, ConstRowIterators, ColumnIterators, and ConstColumnIterators, all of which are random access iterators.

You will find that that 98% of the code across all of the iterators is the same but unless you use some advanced C++ concepts you will have to copy and paste the code across the classes because of type differences. I do recommend doing that copy and pasting though for this assignment as it will save you quite a bit of time.

I highly recommend using iterators in your solution. This would be the standard thing to do if you were in industry and should make writing your solution easier.

This would also be a great time to practice using the functions in the algorithm and functional libraries. For example, you could use transform and negate to easily and concisely implement operator-.


Starter Code


Make sure to start your assignment from the starter code. The starter code comes with all of the CmakeLists.txt as well as the correct structure for what to submit. If you fail to use the starter code not only will your life be much harder as you are writing things from scratch, but it is unlikely that everything will compile together correctly.

The starter code contains all of the source files and methods you have to write in addition to the testing code. The header files contain a description of what each method does and each one should be fairly straightforward to implement. Most of the functions should be implementable in 5 or fewer lines of code. My longest was 8 lines of code so don't feel too overwhelmed by the number of functions you have to write.

You must implement all of the functions given and are not allowed to change their signatures. If you need to change the behavior from the methods that are using the compiler provided defaults you may change them. You are also free to add as many new functions as you wish.

You will need to add data members to some of the classes.

The code I had to write contains some advanced techniques that we haven't covered in class. They are discussed below but I also left them in the provided code everywhere they need to be used.


Virtual Inheritance

This solves the "dreaded diamond problem" by ensuring that the base class only appears a single time in a derived class that inherits from multiple parents that all inherit from a common ancestor. You can read more about here and here.

Files Used In

It is used in BaseVector and ConstVectorRef as VectorRef inherits from both of them.



const_cast can be used to add or remove const on a type. It is useful when trying to implement logical constness but bitwise const is preventing you from doing it as well as to make sure the correct function gets called when there are multiple functions with the same signature but only differ based on whether they are const or not.

Logically Const: From the outside nothing appears to change while internally they may have been some change

Bitwise Const: None of the bits in the object change.

While a very powerful tool const_cast can lead to many subtle bugs if not used appropriately and so I suggest not using it in your code yet. You can read more about it here.

Files Used In

const_cast is used in ConstVectorRef to allow nonconst pointers to point to const objects. This is ok because in ConstVectorRef we only perform const operations on the object. This allows VectorRef to later inherit from ConstVectorRef and still modify the elements if it needs to. This saves us from having to recreate everything in ConstVectorRef again inside of VectorRef.

RowIterator and ColumnIterator to ensure that the const version of Matrix::at is called and not the nonconst version.


Interior Type Declarations

You will see a lot of statements of the form using newTypeName = oldTypeName; throughout the code. These are called type aliases and allow you to give a different name to an old type. These are useful because it allows you to update your code quickly if the type of a variable might change. For example, in our code if we wanted to go from a Vector of ints to a Vector of doubles we could just change the line value_type = int to value_type = double in BaseVector.h and then we would be done instead of having to replace each instance of int with double.


When the type aliases are inside of a class like the ones you see in the starter code they are a part of the class and can be accessed by doing ClassName::type_alias. For example, ConstBaseVector::value_type. This form of type aliasing is extremely common with containers, especially with templated ones. For example, did you ever wonder what the type of an iterator of an std::vector<int> is? It is std::vector<int>::iterator.

These type aliases are heavily used by iterator based code and value_type, difference_type, pointer, reference, and iterator_category are required in your iterator for them to be able to be used with the methods

in algorithm.

Files Used In

Pretty much all of them.


Google Test

We are using Google Test to test your assignment. Google Test is a unit testing framework that helps you write tests to verify your code is working. We will be covering Google Test soon but I wanted to show it to you here so you can get some exposure to it. Make sure to take a look at the test files to see what is happening and to get a feel for how to use Google Test.

We will not test you with any invalid input. For example, we won't do Vectors/Matrices of the incorrect size for the operation

Index out of bounds

Dereference an iterator that is out of bounds

In CLion, the configuration to run the tests is called MatrixTester.

Google Test will greatly increase your build time. This is because Google Test uses a lot of templating and macros which makes the compiler do a lot more work than it has had to do in our previous programs.

Not all of the tests are up yet but there are a few to give you an idea of what is to come.

Almost all if not all of the tests depend on your iterators working correctly so if things are failing double check your iterators.


What to Submit

A zip file containing the src directory. Yes, you really are zipping the folder this time.




Iterators are very, very useful for this problem

Some basic math concepts can be used to reduce the amount of code you write For example, a - b is the same as a + -b

For implementing Matrix *= Matrix it is easiest to implement Matrix * Matrix and then just do *this =

*this * rhs;

I think that this project involves a lot of technicality so please ask questions if you get confused about anything.



创建时间:2022-05-24 16:57