2

I come from a C background and I'm now learning OOP with C++. As an exercise (so please don't just say "this already exists"), I want to implement a wrapper for BLAS that will let the user write matrix algebra in an intuitive way (e.g. similar to MATLAB) e.g.:

A = B*C*D.Inverse() + E.Transpose();

My problem is how to go about dealing with real (R) and complex (C) matrices, because of C++'s "curse" of letting you do the same thing in N different ways.

I do have a clear idea of what it should look like to the user: s/he should be able to define the two separately, but operations would return a type depending on the types of the operands (R*R = R, C*C = C, R*C = C*R = C). Additionally R can be cast into C and vice versa (just by setting the imaginary parts to 0).

I have considered the following options:

  • As a real number is a special case of a complex number, inherit CMatrix from RMatrix. I quickly dismissed this as the two would have to return different types for the same getter function.

  • Inherit RMatrix and CMatrix from Matrix. However, I can't really think of any common code that would go into Matrix (because of the different return types).

  • Templates. Declare Matrix<T> and declare the getter function as T Get(int i, int j), and operator functions as Matrix *(Matrix RHS). Then specialize Matrix<double> and Matrix<complex>, and overload the functions.

  • Then I couldn't really see what I would gain with templates, so why not just define RMatrix and CMatrix separately from each other, and then overload functions as necessary?

Although this last option makes sense to me, there's an annoying voice inside my head saying this is not elegant, because the two are clearly related. Perhaps I'm missing an appropriate design pattern?

So I guess what I'm looking for is either absolution for doing this, or advice on how to do better.

3

Although this last option makes sense to me, there's an annoying voice inside my head saying this is not elegant, because the two are clearly related.

Your difficulty comes from your conception that the two are clearly related. You are probably right, but in this pretty vague form, this statement is only puzzling you instead of helping you. What you have to do is to turn that clearly into a specific statement about the relations you expect within your implementation, and what they do imply for the library client and maybe the end-user of the application using that library. Once you have this specific statement, you can use it to evaluate the merits and demerits of your various designs.

I do have a clear idea of what it should look like to the user: s/he should be able to define the two separately, but operations would return a type depending on the types of the operands (R*R = R, C*C = C, R*C = C*R = C)

First of all, defining such an interface has little practical interest—but you warned everybody: this is a toy-example. In numerical computations, where one typically uses BLAS, matrices are huge and sometimes really huge so that one actually wants to avoid implicit or automatic allocations of memory and one would use a register-like interfaces pretty similar to the one you will find in the original library.

If you want to type formulas as in a math book you could make evaluation be an extra step, i.e. R*R returns a formula, which, when evaluated, returns an actual matrix, e.g.

 C.eval(R*R)

would set C to the product of R and R.

I have considered the following options: […]

Trying to model the world as we understand it (your first attempt with RMatrix ← CMatrix) is often wrong in OO-programming because what we actually need, is to model the world in a way that makes the treatments we want to make easy to describe.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.