sobrecarga sencillos relacionales operadores matrices ejemplos definicion aritmeticos c++ operator-overloading

c++ - sencillos - Sobrecarga del operador



sobrecarga de operadores python (16)

¿Es posible sobrecargar al operador [] dos veces? Para permitir, algo como esto: function[3][3] (como en una matriz de dos dimensiones).

Si es posible, me gustaría ver algún código de ejemplo.


¿Tienes alguna idea sobre qué function , function[x] y function[x][y] significan?

Primero eche un vistazo a donde se define la function . Tal vez hay alguna declaración o definición como

SomeClass function;

(Debido a que dijiste que era una sobrecarga del operador, creo que no te interesaría la matriz como la SomeClass function[16][32]; )

Entonces la function es una instancia de tipo SomeClass . Luego busque la declaración de SomeClass para el tipo de retorno de la sobrecarga del operator[] , al igual que

ReturnType operator[](ParamType);

Entonces la function[x] tendrá el tipo ReturnType . Vuelva a buscar ReturnType para la sobrecarga del operator[] . Si existe tal método, podría usar la function[x][y] expresión function[x][y] .

Tenga en cuenta que, a diferencia de la function(x, y) , la function[x][y] es 2 llamadas separadas. Ni el compilador ni el tiempo de ejecución garantizan la atomicidad. Otro ejemplo similar es que libc dice que printf es atómico, mientras que las llamadas sucesivas al operator<< sobrecargado operator<< en la secuencia de salida no lo son. Una declaración como

std::cout << "hello" << std::endl;

podría tener un problema en la aplicación de múltiples hilos, pero algo como

printf("%s%s", "hello", "/n");

está bien

En conclusión, aunque C ++ puede ofrecerle dicho azúcar sintáctico, no es la forma recomendada de programarlo.


Código de muestra:

template<class T> class Array2D { public: Array2D(int a, int b) { num1 = (T**)new int [a*sizeof(int*)]; for(int i = 0; i < a; i++) num1[i] = new int [b*sizeof(int)]; for (int i = 0; i < a; i++) { for (int j = 0; j < b; j++) { num1[i][j] = i*j; } } } class Array1D { public: Array1D(int* a):temp(a) {} T& operator[](int a) { return temp[a]; } T* temp; }; T** num1; Array1D operator[] (int a) { return Array1D(num1[a]); } }; int _tmain(int argc, _TCHAR* argv[]) { Array2D<int> arr(20, 30); std::cout << arr[2][3]; getchar(); return 0; }


Con std::vector<std::vector<type*>> , puede construir el vector interno utilizando un operador de entrada personalizado que itere sobre sus datos y devuelva un puntero a cada dato.

Por ejemplo:

size_t w, h; int* myData = retrieveData(&w, &h); std::vector<std::vector<int*> > data; data.reserve(w); template<typename T> struct myIterator : public std::iterator<std::input_iterator_tag, T*> { myIterator(T* data) : _data(data) {} T* _data; bool operator==(const myIterator& rhs){return rhs.data == data;} bool operator!=(const myIterator& rhs){return rhs.data != data;} T* operator*(){return data;} T* operator->(){return data;} myIterator& operator++(){data = &data[1]; return *this; } }; for (size_t i = 0; i < w; ++i) { data.push_back(std::vector<int*>(myIterator<int>(&myData[i * h]), myIterator<int>(&myData[(i + 1) * h]))); }

Ejemplo en vivo

Esta solución tiene la ventaja de proporcionarle un contenedor STL real, por lo que puede usar bucles for especiales, algoritmos STL, etc.

for (size_t i = 0; i < w; ++i) for (size_t j = 0; j < h; ++j) std::cout << *data[i][j] << std::endl;

Sin embargo, sí crea vectores de punteros, por lo que si está utilizando pequeñas estructuras de datos como esta, puede copiar directamente el contenido dentro de la matriz.


Es posible si devuelve algún tipo de clase proxy en la primera llamada []. Sin embargo, hay otra opción: puede sobrecargar el operador () que puede aceptar cualquier cantidad de argumentos ( function(3,3) ).


Es posible sobrecargar múltiples [] usando un manejador de plantillas especializado. Solo para mostrar cómo funciona:

#include <iostream> #include <algorithm> #include <numeric> #include <tuple> #include <array> using namespace std; // the number ''3'' is the number of [] to overload (fixed at compile time) struct TestClass : public SubscriptHandler<TestClass,int,int,3> { // the arguments will be packed in reverse order into a std::array of size 3 // and the last [] will forward them to callSubscript() int callSubscript(array<int,3>& v) { return accumulate(v.begin(),v.end(),0); } }; int main() { TestClass a; cout<<a[3][2][9]; // prints 14 (3+2+9) return 0; }

Y ahora la definición de SubscriptHandler<ClassType,ArgType,RetType,N> para hacer que el código anterior funcione. Solo muestra cómo se puede hacer. Esta solución es óptima y no está exenta de errores (no es enhebrable, por ejemplo).

#include <iostream> #include <algorithm> #include <numeric> #include <tuple> #include <array> using namespace std; template <typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler; template<typename ClassType,typename ArgType,typename RetType, int N,int Recursion> class SubscriptHandler_ { ClassType*obj; array<ArgType,N+1> *arr; typedef SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion-1> Subtype; friend class SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion+1>; friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>; public: Subtype operator[](const ArgType& arg){ Subtype s; s.obj = obj; s.arr = arr; arr->at(Recursion)=arg; return s; } }; template<typename ClassType,typename ArgType,typename RetType,int N> class SubscriptHandler_<ClassType,ArgType,RetType,N,0> { ClassType*obj; array<ArgType,N+1> *arr; friend class SubscriptHandler_<ClassType,ArgType,RetType,N,1>; friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>; public: RetType operator[](const ArgType& arg){ arr->at(0) = arg; return obj->callSubscript(*arr); } }; template<typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler{ array<ArgType,N> arr; ClassType*ptr; typedef SubscriptHandler_<ClassType,ArgType,RetType,N-1,N-2> Subtype; protected: SubscriptHandler() { ptr=(ClassType*)this; } public: Subtype operator[](const ArgType& arg){ Subtype s; s.arr=&arr; s.obj=ptr; s.arr->at(N-1)=arg; return s; } }; template<typename ClassType,typename ArgType,typename RetType> struct SubscriptHandler<ClassType,ArgType,RetType,1>{ RetType operator[](const ArgType&arg) { array<ArgType,1> arr; arr.at(0)=arg; return ((ClassType*)this)->callSubscript(arr); } };


Para una matriz bidimensional, específicamente, puede salirse con la sobrecarga de un solo operador [] que devuelve un puntero al primer elemento de cada fila.

Luego puede usar el operador de indexación incorporado para acceder a cada elemento dentro de la fila.


Puede sobrecargar el operator[] para devolver un objeto sobre el que puede usar el operator[] nuevamente para obtener un resultado.

class ArrayOfArrays { public: ArrayOfArrays() { _arrayofarrays = new int*[10]; for(int i = 0; i < 10; ++i) _arrayofarrays[i] = new int[10]; } class Proxy { public: Proxy(int* _array) : _array(_array) { } int operator[](int index) { return _array[index]; } private: int* _array; }; Proxy operator[](int index) { return Proxy(_arrayofarrays[index]); } private: int** _arrayofarrays; };

Entonces puedes usarlo como:

ArrayOfArrays aoa; aoa[3][5];

Este es solo un ejemplo simple, querrías agregar un montón de comprobaciones de límites y otras cosas, pero entiendes la idea.


Puede usar un objeto proxy, algo como esto:

#include <iostream> struct Object { struct Proxy { Object *mObj; int mI; Proxy(Object *obj, int i) : mObj(obj), mI(i) { } int operator[](int j) { return mI * j; } }; Proxy operator[](int i) { return Proxy(this, i); } }; int main() { Object o; std::cout << o[2][3] << std::endl; }


Si, en lugar de decir un [x] [y], le gustaría decir un [{x, y}], puede hacer esto:

struct Coordinate { int x, y; } class Matrix { int** data; operator[](Coordinate c) { return data[c.y][c.x]; } }


Un enfoque es usar std::pair<int,int> :

class Array2D { int** m_p2dArray; public: int operator[](const std::pair<int,int>& Index) { return m_p2dArray[Index.first][Index.second]; } }; int main() { Array2D theArray; pair<int, int> theIndex(2,3); int nValue; nValue = theArray[theIndex]; }

Por supuesto, puede typedef el pair<int,int>


Una expresión x[y][z] requiere que x[y] evalúe un objeto d que admita d[z] .

Esto significa que x[y] debería ser un objeto con un operator[] que evalúa como un "objeto proxy" que también admite un operator[] .

Esta es la única forma de encadenarlos.

Alternativamente, sobrecarga al operator() para tomar múltiples argumentos, de modo que puedas invocar myObject(x,y) .


Usando C ++ 11 y la Biblioteca Estándar puede hacer una muy buena matriz bidimensional en una sola línea de código:

std::array<std::array<int, columnCount>, rowCount> myMatrix {0}; std::array<std::array<std::string, columnCount>, rowCount> myStringMatrix; std::array<std::array<Widget, columnCount>, rowCount> myWidgetMatrix;

Al decidir que la matriz interna representa filas, accede a la matriz con una myMatrix[y][x] :

myMatrix[0][0] = 1; myMatrix[0][3] = 2; myMatrix[3][4] = 3; std::cout << myMatrix[3][4]; // outputs 3 myStringMatrix[2][4] = "foo"; myWidgetMatrix[1][5].doTheStuff();

Y puede usar ranged- for para salida:

for (const auto &row : myMatrix) { for (const auto &elem : row) { std::cout << elem << " "; } std::cout << std::endl; }

(Decidir que la array interna representa columnas permitiría una sintaxis foo[x][y] pero necesitaría usar torpes for(;;) bucles for(;;) para visualizar la salida).


vector <vector <T>> o T ** solo se requiere cuando tiene filas de longitud variable y demasiado ineficiente en términos de uso de memoria / asignaciones si necesita una matriz rectangular. ¡Considere hacer algunas operaciones matemáticas en su lugar! ver en el método ():

template<typename T > class array2d { protected: std::vector< T > _dataStore; size_t _sx; public: array2d(size_t sx, size_t sy = 1): _sx(sx), _dataStore(sx*sy) {} T& at( size_t x, size_t y ) { return _dataStore[ x+y*sx]; } const T& at( size_t x, size_t y ) const { return _dataStore[ x+y*sx]; } const T& get( size_t x, size_t y ) const { return at(x,y); } void set( size_t x, size_t y, const T& newValue ) { at(x,y) = newValue; } };


#include<iostream> using namespace std; class Array { private: int *p; public: int length; Array(int size = 0): length(size) { p=new int(length); } int& operator [](const int k) { return p[k]; } }; class Matrix { private: Array *p; public: int r,c; Matrix(int i=0, int j=0):r(i), c(j) { p= new Array[r]; } Array& operator [](const int& i) { return p[i]; } }; /*Driver program*/ int main() { Matrix M1(3,3); /*for checking purpose*/ M1[2][2]=5; }


struct test { using array_reference = int(&)[32][32]; array_reference operator [] (std::size_t index) { return m_data[index]; } private: int m_data[32][32][32]; };

Encontré mi propia solución simple para esto.


template<class F> struct indexer_t{ F f; template<class I> std::result_of_t<F const&(I)> operator[](I&&i)const{ return f(std::forward<I>(i))1; } }; template<class F> indexer_t<std::decay_t<F>> as_indexer(F&& f){return {std::forward<F>(f)};}

Esto le permite tomar una lambda y producir un indexador (con soporte [] ).

Supongamos que tiene un operator() que admite pasar ambas coordenadas en onxe como dos argumentos. Ahora escribir soporte de [][] es solo:

auto operator[](size_t i){ return as_indexer( [i,this](size_t j)->decltype(auto) {return (*this)(i,j);} ); } auto operator[](size_t i)const{ return as_indexer( [i,this](size_t j)->decltype(auto) {return (*this)(i,j);} ); }

Y hecho. No se requiere clase personalizada.