C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
84 CHAPTER 3. CLASSES<br />
Approach 3: Returning proxies<br />
Instead of returning a pointer we can build a specific type that keeps a reference to the matrix<br />
and the row index and that provide an operator[] <strong>for</strong> accessing matrix entries. This proxy must<br />
be there<strong>for</strong>e a friend of the matrix class to reach its private data. Alternatively, we can keep<br />
the operator with the parentheses and call this one from the proxy. In both cases, we encounter<br />
cyclic dependencies. 10<br />
If we have several matrix types, each of them would need its own proxy. We would also need<br />
different proxies <strong>for</strong> constant and mutable access respectively. In Section 6.5 we will show how<br />
to write a proxy that works <strong>for</strong> all matrix types. The same templated proxy will handle constant<br />
and mutable access. Fortunately, it even solves the problem of mutual dependencies. The only<br />
minor flaw is that eventual errors cause lenghty compiler messages.<br />
Approach 4: Multi-index type (advanced)<br />
Preliminary note: this approach contains several new language features and discusses some<br />
subtle details. If you do not understand the first time, don’t worry. If you like to skip it, do<br />
it. That will not be a problem <strong>for</strong> understanding the rest of the book. But please read the<br />
comparing discussion.<br />
The fact that operator[] accepts only one argument does not necessarily mean that we cannot<br />
give two. But we need a tricky technique to build one object out of two, without explicitly<br />
constructing the object. The implementation is based on the matrix example from an onlinetutorial<br />
[Sch].<br />
First, we define a type:<br />
struct double index<br />
{<br />
double index (int i1, int i2): i1 (i1), i2 (i2) {}<br />
int i1, i2;<br />
};<br />
For this type we define the access operator:<br />
double& operator[](double index i) { return data[i.i1∗ncols + i.i2]; }<br />
const double& operator[](double index i) const { return data[i.i1∗ncols + i.i2]; }<br />
Now we can write:<br />
A[double index(1, 0)];<br />
This works but it was not the concise notation we were looking <strong>for</strong>.<br />
We introduce a second type:<br />
struct single index<br />
{<br />
single index (int i1): i1 (i1) {}<br />
double index operator, (single index j) const {<br />
10 The dependencies cannot be resolved with <strong>for</strong>ward declaration because we not only define references or<br />
pointers but call member functions in the matrix and in the proxy. We will explain this in § ??.