2015-07-02 70 views
1

我有一個現有的類,它是通過以下方式構成:重載索引操作符來模擬POD多維數組?

class Matrix 
{ 
public: 
    float Data[4][4]; 
    // ... methods 
}; 

,隨後在下面的使用方式:

Matrix m; 
m.Data[0][0] = 1.0f; 
float local = m.Data[0][0]; 
//... 

我想用一個重載的索引來代替Data成員運算符,所以我可以對使用的索引執行範圍檢查。儘管我可以更改Matrix類本身及其成員函數的實現,但我無法修改其在現有代碼中的用法,因此任何解決方案都要求使用語法保持相同。也希望解決方案不會改變sizeof(Matrix)。有沒有辦法做到這一點?

+0

您需要幾個間接級別,每個類只能爲一個索引操作符重載。 –

+0

是的,我知道 - 但是,因爲已知它是2D數組,Matrix的索引操作符可能會返回某種接口,這也可能會覆蓋其索引操作符? ......如果事實上有可能,不確定它將如何構建。 – MuertoExcobito

+0

順便說一句,你想如何實際存儲數據?如果每行在內存中仍然是連續的,那麼你可以重載一個'operator []'來返回'float *'---行開始的地址---和第二個'[]'將被自動處理。 – Petr

回答

1

另一種方法是定義一個代理類與語義的載體

class Matrix 
{ 
public: 
    struct SubMatrix 
    { 
     class Vector 
     { 
     public: 
      Vector(float *data) : Data(data) {} 
      float &operator[](int index) { return Data[index]; } 
     private: 
      float *Data; 
     }; 
     Vector operator[](int index) 
     { 
      return Vector(Data[index]); 
     } 
     float Data[4][4]; 
    }; 
    SubMatrix Data; 
    // ... methods 
}; 

然後你就可以使用這種方式:

Matrix m; 
float f = m.Data[1][2]; 
+0

與其他答案一樣,這需要更改語法 - m [1] [2]'而不是'm.Data [1] [2]'。 – MuertoExcobito

+0

更改語法有什麼問題? – celticminstrel

+0

@MuertoExcobito這樣你可以保持語法 – marom

3

通常對於這類事情,您需要使用代理類來處理第二個索引操作符。它看起來像這樣,然後進入Matrix課程的private部分。我將忽略邊界檢查(你自己應該不難添加)。

class Proxy { 
    Matrix& ref; 
    size_t i; 
public: 
    Proxy(Matrix& on, size_t i) : ref(on), i(i) {} 
    float operator[] (size_t j) { 
     return ref.Data[i][j]; 
    } 
}; 

然後,只需有你Matrix::operator[]返回這個類的一個實例:

Proxy operator[] (size_t i) { 
    return Proxy(*this, i); 
} 

需要注意的是,如果你想讓一個const過載(即您要使用的索引操作上const Matrix對象),你需要一個單獨的ConstProxy類,它有const Matrix& ref而不是Matrix& ref,但是在其他方面是相同的。


還有對數組返回引用的選項。 (注:作爲一個評論指出,這沒有太大的幫助與約束檢查,但我認爲這是有趣的,所以我會離開這裏。)

float (&operator[](size_t i))[4] { 
    return Data[i]; 
} 

該語法是相當神祕,我相信它在Visual Studio 2013中不起作用,但是你可以用typedef使它更清潔一些。

using Proxy = float[4]; 
Proxy& operator[](size_t i) { 
    return Data[i]; 
} 

還有一個選擇,如果你不介意放棄方括號索引。你可以重載函數調用操作是這樣的:

float operator()(size_t i, size_t j) { 
    return Data[i][j]; 
} 
+1

對於第二種語法,爲什麼不只是返回'float *'?無論如何,這無助於檢查。 – Petr

+1

通過返回一個數組引用,數組的大小被記住。這意味着您可以執行類似'for(float n:my_matrix [i])'的操作。如果你返回'float *',大小會丟失。 – celticminstrel

+0

另外,使用引用可以更好地推廣到更高維的數組。 – celticminstrel