c ++类返回对自身的引用

时间:2016-09-01 15:36:46

标签: c++ reference

c ++对象可以有一个返回对自身引用的方法吗? 我想要对象的类的多个独立实例。

用于实现多维数组的[]运算符。 我想要像Array[0][1][2]这样的东西。

感谢。

更新

实现多维数组:

预期用途:

A[0][1] = 4;    //the element at 0th row and 1st column is now 4.
A[0] = 5;       //all elements of the 0th row are now 5.
A["all"][1] = 10; //all elements of the 1st column are now 10;

对象A具有指针ptr_buffer到一块具有正确simd对齐的内存块。 A的构造函数将分配内存。 A的析构函数释放内存。 A []返回对象B.

对象B有一个指针ptr_A_buffer指向A的内存子节.B []修改ptr_A_buffer并返回对它自身的引用。我不想为每个[]操作不断地制作一堆对象B.

A和B都属于同一个抽象类。数学函数将抽象类作为参数。

1 个答案:

答案 0 :(得分:1)

我对这个想法很好奇。这是一种似乎符合要求的数据类型。它是一种数组类型,当用维度的三个整数调用时,分配连续的内存,然后允许用户定义"视图"进入具有较小尺寸的数据(平面,行,单个值)。

我使用了之前没有用过的共享指针,所以我可能犯了错误。我欢迎更正。

这个想法是复制视图很浅;它们都在相同的底层数据上运行。这使我能够以合理的效率传递价值。

#include <iostream>
#include <iomanip>
#include <memory>

using namespace std;

/// This class is a three-dimensional array of doubles.
/// It defines an index operator which returns a view into that
/// data that is of one lesser dimension, just like the standard
/// index operator on plain old arrays. The last index operation 
/// yields an "array" which is a single value. 
/// Converting to double and assigning from double is defined as
/// using the first double in the view.
class NDimArrT 
{
    /// All slices hold a shared pointer to the base data they
    /// are looking into so that their view stays valid.
    const shared_ptr<double> baseData;

    /// The data the view is looking at. Identical to the shared
    /// ptr for the original object.
    double *const slice;

    /// The three dimensions, in the order of indexing.
    /// All three of them may be zero, indicating a single value.
    const int dim1, dim2, dim3;

public:

    /// A single double value view into a one-dimensional array
    NDimArrT(const shared_ptr<double> base, double *sliceStart) 
        : baseData(base), slice(sliceStart), dim1(0), dim2(0), dim3(0) {}

    /// A 1D vector/row view into a two-dimensional array.
    /// @param dim1Arg is the length of the row.
    NDimArrT(const shared_ptr<double> base, double *sliceStart, int dim1Arg) 
        : baseData(base), slice(sliceStart), dim1(dim1Arg), dim2(0), dim3(0) {}

    /// A 2D matrix plane view into the cube
    NDimArrT(const shared_ptr<double> base, double *sliceStart, int dim1Arg, int dim2Arg) 
        : baseData(base), slice(sliceStart), dim1(dim1Arg), dim2(dim2Arg), dim3(0) {}

    /// A 3D cube. This actually allocates memory.
    NDimArrT(int dim1Arg, int dim2Arg, int dim3Arg) 
        :   baseData(new double[dim1Arg*dim2Arg*dim3Arg], std::default_delete<double[]>() ),
            slice(baseData.get()), // the data view is the whole array
            dim1(dim1Arg), dim2(dim2Arg), dim3(dim3Arg) {}

    /// Perform a shallow copy. We assume that e.g. returning a slice means
    /// essentially returning another view into the main base array.
    NDimArrT(const NDimArrT &rhs) = default;

    /// Use standard move semantics. The rhs will be invalidated, and the
    /// reference count to the base array does not grow. Can be used to return results from 
    /// functions.
    NDimArrT(NDimArrT &&rhs) = default;

    /// Default destructor; destroy baseData if it's the last reference.
    ~NDimArrT() = default;

    /// Get the value of the first element we look at. Handy for 
    /// single value views.
    operator double() const { return *slice; }

    /// Return an instance of NDimArrT representing a view
    /// with one dimension less than this. If we have a single value
    /// already, simply return this single value. (We should
    /// perhaps throw an exception there.)
    NDimArrT operator[](int ind)
    {
         // This could be regarded an error, because this view 
         // is already a single element.
        if(GetDims() == 0) { return *this; }

        // This view is a 1-dimensional vector. Return the element at ind.
        if(dim2==0) { return NDimArrT(baseData, slice + ind); } // return a single value.

        // This view is a 2D matrix. Return the row no. ind.
        // The row length is dim2. (Dim 1 indicates how many rows.)
        if(dim3==0) { return NDimArrT(baseData, slice + dim2*ind, dim2); } // return a 1D vector

        // This view is a true 3D cube matrix. dim1 is the number of planes,
        // dim2 is the number of rows in a plane, dim3 is the length of each row.
        // Return the plane no. ind, which starts at ind*planesize, i.e. ind*dim2*dim3.
        // The number of rows and row length are dim2 and dim3, respectively.
        return NDimArrT(baseData, slice + dim2*dim3*ind, dim2, dim3); // return a 2D matrix.
    } 

    NDimArrT &operator=(double d) { *slice = d; }

    int Len() { return dim1 ? dim1 : 1; } // interestingly, length is always dim1.

    int GetDims() const
    { 
        return dim1 
                ? dim2 
                    ? dim3
                        ? 3
                        : 2
                    : 1
                : 0;
    }

};

/// An example function which initializes an NDimArr of unknown
/// dimensionality with nice numbers..
void initNDimArr(NDimArrT arr, int &startVal)
{
    // Single value? Give it the start value and increment that.
    if( arr.GetDims() == 0 ) { arr = startVal++; }
    else
    {
        for(int ind=0; ind<arr.Len(); ind++) { initNDimArr(arr[ind], startVal); }
    }
}

// An example function doing something with
// an unknown n-dimensional array
void printNdimArr( NDimArrT nDimArr)
{
    if( nDimArr.GetDims() == 0) { cout << setw(4) << nDimArr << " "; }
    else 
    { 
        for(int i=0; i<nDimArr.Len(); i++) { printNdimArr(nDimArr[i]); }
        cout << endl;
    }   
}
int main()
{
    NDimArrT arr(3,4,5);
    int start = 1;
    initNDimArr(arr, start);
    printNdimArr(arr);

    // now use the middle plane of the 3 4x5 planes
    cout << "Middle plane, values starting at 100:" << endl;
    auto middlePlane = arr[1];
    start = 100;
    initNDimArr(middlePlane, start);
    printNdimArr(middlePlane);

    cout << "Whole array now:" << endl;
    printNdimArr(arr);

    cout << "Print line 2 of the 3rd plane:" << endl;
    printNdimArr(arr[2][1]);

    cout << endl << "Last number in that row is " << arr[2][1][4] << endl;
}

示例会话:

$>g++ -std=c++11 -o ndimContiguousArr ndimContiguousArr.cpp && ./ndimContiguousArr
   1    2    3    4    5
   6    7    8    9   10
  11   12   13   14   15
  16   17   18   19   20

  21   22   23   24   25
  26   27   28   29   30
  31   32   33   34   35
  36   37   38   39   40

  41   42   43   44   45
  46   47   48   49   50
  51   52   53   54   55
  56   57   58   59   60


Middle plane, values starting at 100:
 100  101  102  103  104
 105  106  107  108  109
 110  111  112  113  114
 115  116  117  118  119

Whole array now:
   1    2    3    4    5
   6    7    8    9   10
  11   12   13   14   15
  16   17   18   19   20

 100  101  102  103  104
 105  106  107  108  109
 110  111  112  113  114
 115  116  117  118  119

  41   42   43   44   45
  46   47   48   49   50
  51   52   53   54   55
  56   57   58   59   60


Print line 2 of the 3rd plane:
  46   47   48   49   50

Last number in that row is 50
相关问题