[]
运算符可以重载两次吗?允许的是这样的:function[3][3]
(如二维数组)。 如果可能的话,我想看一些示例代码。
#1 楼
您可以重载operator[]
以返回可以再次使用operator[]
在其上获得结果的对象。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;
};
然后可以使用它,如:
ArrayOfArrays aoa;
aoa[3][5];
这只是一个简单的示例,您想添加一些边界检查和内容,但是您知道了。
评论
可以使用析构函数。并且Proxy :: operator []应该返回int&而不仅仅是int
–瑞安·海宁(Ryan Haining)
2013年12月16日6:14
最好使用std :: vector
– Jarod42
14年8月20日在12:35
Boost的multi_array和extent_gen都是该技术的很好示例。 boost.org/doc/libs/1_57_0/libs/multi_array/doc / ...
– alfC
15年1月23日在22:06
但是,const ArrayOfArrays arr; arr [3] [5] = 42;将能够通过编译并更改arr [3] [5],这与用户对arr为const的期望有所不同。
–abcdabcd987
15年11月8日在12:45
@ abcdabcd987这有两个原因是不正确的。首先,Proxy :: operator []不会在此代码中返回引用(假设您的评论未回复Ryan Haining)。更重要的是,如果arr是const,则无法使用operator []。您将必须定义一个const版本,当然您需要使其返回const Proxy。然后,代理本身将具有const和非const方法。然后您的示例仍然无法编译,程序员将很高兴宇宙中的一切都很好。 =)
–paddy
16年4月5日在6:20
#2 楼
表达式x[y][z]
要求x[y]
评估为支持d
的对象d[z]
。这意味着
x[y]
应该是带有operator[]
且评估为“代理对象”且也支持operator[]
的对象。 /> 这是链接它们的唯一方法。
或者,重载
operator()
以接受多个参数,以便您可以调用myObject(x,y)
。评论
为什么括号的重载允许获得两个输入,但是括号却不能相同?
– A.疯狂
5月21日22:49
@ A.Frenzy因为:1.用2个参数覆盖将导致对myObj [2,3]而不是myObj [2] [3]的调用。和2.无法更改操作符采用的参数数量。[]运算符仅采用一个int,而()则采用任意数量的任何类型的参数。
–天蝎座
12月18日13:07
#3 楼
具体地说,对于二维数组,您可能会避免使用单个operator []重载而返回指向每一行第一个元素的指针。然后您可以使用内置的索引操作符来访问行中的每个元素。
评论
在我看来,这是最实用,最有效的解决方案。想知道为什么它没有获得更多的选票-也许是因为它没有醒目的代码。
–伊格·里斯(Yigal Reiss)
17-4-26在19:20
#4 楼
如果您在first []调用中返回了某种代理类,则是可能的。但是,还有另一种选择:您可以重载可以接受任意数量参数(function(3,3)
)的operator()。#5 楼
一种方法是使用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];
}
当然,您可以
typedef
pair<int,int>
评论
对于C ++ 11和大括号初始化,这变得更具吸引力。现在您可以编写nValue = theArray [{2,3}];
–马丁·邦纳(Martin Bonner)支持莫妮卡(Monica)
16-9-29在16:51
#6 楼
您可以使用代理对象,如下所示:#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;
}
#7 楼
如果您能告诉我function
,function[x]
和function[x][y]
是什么,那就太好了。但是无论如何,让我把它看作是声明为SomeClass function;
的对象(因为您说的是运算符重载,所以我认为您对
SomeClass function[16][32];
这样的数组不感兴趣)所以
function
是类型SomeClass
的实例。然后查找SomeClass
的声明以获取operator[]
重载的返回类型,就像ReturnType operator[](ParamType);
,然后
function[x]
将具有ReturnType
类型。再次查询ReturnType
是否过载。如果有这种方法,则可以使用表达式operator[]
。注意,与
function[x][y]
不同,function(x, y)
是2个单独的调用。因此,除非您在上下文中使用锁,否则编译器或运行时很难保证原子性。一个类似的例子是,libc说function[x][y]
是原子的,而连续调用输出流中的重载printf
却不是。像std::cout << "hello" << std::endl;
这样的语句可能在多线程应用程序中有问题,但是像
printf("%s%s", "hello", "\n");
这样的语句是很好。
#8 楼
#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;
}
#9 楼
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];
};
找到了我自己的简单解决方案。
#10 楼
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)};}
这允许您获取lambda并生成索引器(支持
[]
)。假设您有一个
operator()
,它支持将onxe的两个坐标作为两个参数传递。现在编写[][]
支持只是: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);}
);
}
完成。不需要自定义类。
#11 楼
如果您不想说a [x] [y],而是想说a [{x,y}],则可以这样:struct Coordinate { int x, y; }
class Matrix {
int** data;
operator[](Coordinate c) {
return data[c.y][c.x];
}
}
#12 楼
使用专门的模板处理程序可以重载多个[]。只是为了演示其工作原理:#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;
}
现在使用
SubscriptHandler<ClassType,ArgType,RetType,N>
的定义来使前面的代码起作用。它仅显示如何完成。此解决方案既不是最佳解决方案,也不是没有错误(例如,不是线程安全的)。#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);
}
};
#13 楼
使用std::vector<std::vector<type*>>
,您可以使用自定义输入运算符构建内部向量,该运算符将对数据进行迭代并返回指向每个数据的指针。例如,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])));
}
实时示例
此解决方案的优点是为您提供了一个真正的STL容器,因此您可以使用特殊的for循环,STL算法等。
for (size_t i = 0; i < w; ++i)
for (size_t j = 0; j < h; ++j)
std::cout << *data[i][j] << std::endl;
但是,它确实会创建指针向量,因此,如果您使用的是这种小型数据结构,则可以直接在数组内部复制内容。
#14 楼
示例代码: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;
}
#15 楼
仅当具有可变长度的行时才需要vector,并且在内存使用/分配方面效率太低
,如果您需要矩形数组,请考虑做一些数学运算!
请参阅at()方法:
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; }
};
#16 楼
使用C ++ 11和标准库,您可以在一行代码中创建一个非常漂亮的二维数组: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;
通过确定内部矩阵表示行,您可以使用
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();
,并且可以将range-
for
用于输出:for (const auto &row : myMatrix) {
for (const auto &elem : row) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
(确定内部
array
代表列将允许使用foo[x][y]
语法,但您需要使用笨拙的for(;;)
循环来显示输出。)#17 楼
我的5美分。我凭直觉知道我需要做很多样板代码。这就是为什么我没有重载operator []而是重载了operator(int,int )。然后在最终结果中,我做了m(1,2)
,而不是m [1] [2],我知道这是不同的事情,但仍然非常直观,看起来像数学脚本。 br />
#18 楼
最短,最简单的解决方案:class Matrix
{
public:
float m_matrix[4][4];
// for statements like matrix[0][0] = 1;
float* operator [] (int index)
{
return m_matrix[index];
}
// for statements like matrix[0][0] = otherMatrix[0][0];
const float* operator [] (int index) const
{
return m_matrix[index];
}
};
评论
顺便说一句,相反,重载operator()(int,int)更加简单和普遍了...为什么要重新制作轮子?只需将std :: vector与范围构造函数一起使用:stackoverflow.com/a/25405865/610351
或者您也可以使用array2d = std :: array