2015-12-28 84 views
6

我有一個名爲mat [3] [3]的類的私有成員,我希望能夠在我的類之外訪問此3x3數組(僅讀取它,不變)。是否有可能編寫accessor方法返回指向我的數組的指針?我怎樣才能做到這一點?請提供代碼示例。如何編寫二維數組的訪問器(私有成員)

這裏是我的類:

class myClass { 
private: 
    int mat[3][3]; 
public: 
    return_value get_mat(void); 
}; 

我知道我可以使用類似

int get_mat(int i, int j); 

訪問一個數組中的一個內的每個INT,但不會是低效的來電數組的每個成員的訪問器?

+0

'int i,int j'版本不會低效。編譯器擅長處理這類事情。 –

回答

9

是否有可能編寫accessor方法返回指向我的數組的指針?我怎樣才能做到這一點?

這裏有一種方法:

#include <iostream> 
#include <algorithm> 
#include <iterator> 

class myClass { 
public: 

    const int* operator[](size_t i) const { 
     return mat[i]; 
    } 

    int* operator[](size_t i) { 
     return mat[i]; 
    } 

    int* get_mat() { 
     return &mat[0][0]; 
    } 

    const int* get_mat() const { 
     return &mat[0][0]; 
    } 

private: 
    int mat[3][3]; 
}; 

int main() 
{ 
    using namespace std; 

    myClass m; 
    m[0][1] = 6; 
    cout << m[0][1] << endl; 

    fill(m.get_mat(), m.get_mat() + 9, 11); 
    copy(m.get_mat(), m.get_mat() + 9, ostream_iterator<int>(cout, ", ")); 
    cout << endl; 

    return 0; 
} 

,但不會是低效的呼籲陣列中的每個成員的訪問?

令人高興的是,沒有。在發佈版本中,你的編譯器會比你想象的要好得多。

優雅地表達你的意圖。允許編譯器爲您編寫最佳代碼(它會)。

預期輸出:

6 
11, 11, 11, 11, 11, 11, 11, 11, 11, 

當我們開始充實矩陣類,我們很可能要動工建設,針對緩衝區溢出的一些安全防護措施(此代碼可能需要C++ 14)。 ..

#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include <functional> 
#include <random> 
#include <cassert> 

template<class T, size_t N> 
struct safe_array_ref 
{ 
    constexpr safe_array_ref(T* data) : _data(data) {} 

    constexpr T& operator[](size_t i) const noexcept { 
     assert(i < N); 
     return _data[i]; 
    } 

    constexpr T* begin() const { 
     return _data; 
    } 

    constexpr T* end() const { 
     return _data + N; 
    } 

    constexpr size_t size() const { 
     return N; 
    } 

private: 
    T* _data; 
}; 

class myClass { 
public: 

    auto operator[](size_t i) const { 
     // provide some degree of safety 
     assert(i < extent_1); 
     return safe_array_ref<const int, extent_2>(mat[i]); 
    } 

    auto operator[](size_t i) { 
     // provide some degree of safety 
     assert(i < extent_1); 
     return safe_array_ref<int, extent_2>(mat[i]); 
    } 

    int* get_mat() { 
     return &mat[0][0]; 
    } 

    const int* get_mat() const { 
     return &mat[0][0]; 
    } 

    const int* begin() const { 
     return get_mat(); 
    } 

    const int* end() const { 
     return get_mat() + total_extent; 
    } 

    int* begin() { 
     return get_mat(); 
    } 

    int* end() { 
     return get_mat() + total_extent; 
    } 

    constexpr size_t size() const { 
     return total_extent; 
    } 


private: 
    int mat[3][3]; 

public: 
    constexpr static size_t extent_1 = std::extent<decltype(mat)>::value; 
    constexpr static size_t extent_2 = std::extent<std::remove_extent_t<decltype(mat)>>::value; 
    constexpr static size_t total_extent = extent_1 * extent_2; 
}; 

int main() 
{ 
    using namespace std; 

    myClass m; 
    m[0][1] = 6; 
    cout << m[0][1] << endl; 

    generate(m.begin(), 
      m.end(), 
      bind(uniform_int_distribution<int>(0,99), 
        default_random_engine(random_device()()))); 

    // copy the whole matrix to stdout 
    copy(m.begin(), 
     m.end(), 
     ostream_iterator<int>(cout, ", ")); 
    cout << endl; 

    // copy one row/column of the matrix to stdout   
    copy(m[1].begin(), 
     m[1].end(), 
     ostream_iterator<int>(cout, ", ")); 
    cout << endl; 


    return 0; 
} 

輸出樣本:

6 
76, 6, 39, 68, 40, 77, 28, 28, 76, 
68, 40, 77, 
+0

我認爲最好允許使用範圍檢查的語法'M [i] [j]'w/o範圍檢查和'M.at(i,j)',類似於'std :: vector'。通常範圍檢查可以安全地省略。另外,一個合適的C++矩陣應該拋出一個'std :: out_of_range'而不是'assert()' - 超出範圍的錯誤不在矩陣類的內部。 – Walter

+0

這是一個品味的問題。我更喜歡原始版本。 (我認爲op [] /不同是錯誤的)。最後,op []不是「沒有範圍檢查」 - 這只是未定義的行爲。觸發一個斷言是一個完全合理的方式來實現未定義的行爲。 (如果是內聯,優化器將刪除大部分範圍檢查) –

+0

@Walter如果使用NDEBUG集(發佈版本)進行編譯,assert會編譯爲NOP,因此在生產中它不是範圍檢查的,但至少您有機會在開發過程中發現錯誤。我絕對同意'.at()'版本應該會引發range_error。 –

0

是否有可能編寫訪問器方法返回指向我的數組的指針?

你可以使用這個醜陋的語法返回引用您的內部陣列

const int (&myClass::as_array())[3][3] const { return mat; } 

這可能與typedef被簡化:

using int3x3 = int [3][3]; 

const int3x3& myClass::as_array() const { return mat; } 

std::array是一個很好的選擇了。

但是,如果爲數組中的每個成員調用訪問器都不是無效的。

int myClass::get_value(int i, int j) const { return mat[i][j]; }是完全有效的,應該由編譯器內聯。

如果您必須訪問數組中的每個int,幾乎所有替代結果都在相同的彙編代碼中。

這個getter的陷阱是你不能使用stl中的大多數算法,它可以用迭代器代替索引。

簡單易用的一種簡單的方法是將數組的維數從[3][3]更改爲[3*3](並手動執行索引計算)。