Как написать accessor для 2D массива (private member)
У меня есть частный член класса под названием mat [3][3], и я хочу иметь возможность получить доступ к этому массиву 3x3 вне моего класса (только читать его, а не изменять). Можно ли написать метод доступа, который возвращает указатель на мой массив? Как я могу это сделать? Пожалуйста, предоставьте пример кода.
Вот мой класс:
class myClass {
private:
int mat[3][3];
public:
return_value get_mat(void);
};
Я знаю, что могу использовать что-то вроде
int get_mat(int i, int j);
Чтобы получить доступ к каждому int внутри массива по одному, но не было бы неэффективно вызывать метод доступа для каждого члена массива. массив?
2 ответа:
Можно ли написать метод доступа, который возвращает указатель на мой массив? Как я могу это сделать?
Вот один из способов:
#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; }
Но не будет ли неэффективно вызывать метод доступа для каждого члена массива?
К счастью, нет. в сборке релиза ваш компилятор оптимизирует все это гораздо лучше, чем вы, вероятно, можете себе представить.
Выразите свое намерение элегантно. Позвольте компилятору написать оптимальный код для вас (it будет).
Ожидаемый результат:
6 11, 11, 11, 11, 11, 11, 11, 11, 11,
Поскольку мы начинаем конкретизировать класс matrix, мы, вероятно, захотим начать строить некоторые меры безопасности против переполнения буфера (этот код, вероятно, требует 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,
Можно ли написать метод доступа, который возвращает указатель на мой массив?
Вы можете использовать этот уродливый синтаксис для возврата ссылки на ваш внутренний массив
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
из массива, почти все альтернативные приводят к одному и тому же ассемблерному коду.Ловушкаэтого геттера заключается в том, что вы не можете использовать большинство алгоритмов из stl, которые работают с итератором вместо индекса.
Один из простых способов получить более простой
iterator
- это изменить размерность массива из[3][3]
в[3*3]
(и выполнить индексацию вручную).