This page explains the design of the core classes in Eigen's class hierarchy and how they fit together. Casual users probably need not concern themselves with these details, but it may be useful for both advanced users and Eigen developers.
Table of contents
Eigen's class hierarchy is designed so that virtual functions are avoided where their overhead would significantly impair performance. Instead, Eigen achieves polymorphism with the Curiously Recurring Template Pattern (CRTP). In this pattern, the base class (for instance, MatrixBase
) is in fact a template class, and the derived class (for instance, Matrix
) inherits the base class with the derived class itself as a template argument (in this case, Matrix
inherits from MatrixBase<Matrix>
). This allows Eigen to resolve the polymorphic function calls at compile time.
In addition, the design avoids multiple inheritance. One reason for this is that in our experience, some compilers (like MSVC) fail to perform empty base class optimization, which is crucial for our fixed-size types.
These are the classes that you need to know about if you want to write functions that accept or return Eigen objects.
m
is a Matrix
, then, for instance, m+m
is no longer a Matrix
, it is a "matrix expression".MatrixBase
is something that can be added, matrix-multiplied, LU-decomposed, QR-decomposed... All matrix expression classes, including Matrix
itself, inherit MatrixBase
.x
is an Array
, then, for instance, x+x
is no longer an Array
, it is an "array expression".ArrayBase
is something that can be added, array-multiplied, and on which you can perform all sorts of array operations... All array expression classes, including Array
itself, inherit ArrayBase
.ArrayBase
and MatrixBase
inherit DenseBase
. DenseBase
is where all the methods go that apply to dense expressions regardless of whether they are matrix or array expressions. For example, the block(...) methods are in DenseBase
.These classes serve as base classes for the five core classes mentioned above. They are more internal and so less interesting for users of the Eigen library.
PlainObjectBase
is inherited by Matrix
and by Array
. But above, we said that Matrix
inherits MatrixBase
and Array
inherits ArrayBase
. So does that mean multiple inheritance? No, because PlainObjectBase
itself inherits MatrixBase
or ArrayBase
depending on whether we are in the matrix or array case. When we said above that Matrix
inherited MatrixBase
, we omitted to say it does so indirectly via PlainObjectBase
. Same for Array
.DenseBase
. The reason for DenseCoeffsBase
to exist is that the set of available coefficient accessors is very different depending on whether a dense expression has direct memory access or not (the DirectAccessBit
flag). For example, if x
is a plain matrix, then x
has direct access, and x.transpose()
and x.block
(...) also have direct access, because their coefficients can be read right off memory, but for example, x+x
does not have direct memory access, because obtaining any of its coefficients requires a computation (an addition), it can't be just read off memory.EigenBase
is really the absolute base class for anything that remotely looks like a matrix or array. It is a base class for DenseCoeffsBase
, so it sits below all our dense class hierarchy, but it is not limited to dense expressions. For example, EigenBase
is also inherited by diagonal matrices, sparse matrices, etc...The inheritance diagram for Matrix looks as follows:
EigenBase<Matrix> <-- DenseCoeffsBase<Matrix> (direct access case) <-- DenseBase<Matrix> <-- MatrixBase<Matrix> <-- PlainObjectBase<Matrix> (matrix case) <-- Matrix
The inheritance diagram for Array looks as follows:
EigenBase<Array> <-- DenseCoeffsBase<Array> (direct access case) <-- DenseBase<Array> <-- ArrayBase<Array> <-- PlainObjectBase<Array> (array case) <-- Array
The inheritance diagram for some other matrix expression class, here denoted by SomeMatrixXpr
, looks as follows:
EigenBase<SomeMatrixXpr> <-- DenseCoeffsBase<SomeMatrixXpr> (direct access or no direct access case) <-- DenseBase<SomeMatrixXpr> <-- MatrixBase<SomeMatrixXpr> <-- SomeMatrixXpr
The inheritance diagram for some other array expression class, here denoted by SomeArrayXpr
, looks as follows:
EigenBase<SomeArrayXpr> <-- DenseCoeffsBase<SomeArrayXpr> (direct access or no direct access case) <-- DenseBase<SomeArrayXpr> <-- ArrayBase<SomeArrayXpr> <-- SomeArrayXpr
Finally, consider an example of something that is not a dense expression, for instance a diagonal matrix. The corresponding inheritance diagram is:
EigenBase<DiagonalMatrix> <-- DiagonalBase<DiagonalMatrix> <-- DiagonalMatrix