2 Dimension Subscript Operator Overload?

Pages: 12
Hi all,

I am trying to figure out how to do a 2-dimensional subscript operator overload. I have tried searching for some information and found that it is better to use parentheses. However, my lab question states that they want [][], so i dont have a choice. Anyway, it is a slightly modified version.

So is there anyway i can take in 2 arguments? Because i just want to check if for example: [1][1] will be equals to "a" and [1][2] will be equals to "b" and so on. So i am not trying to get anything out of any array. Hoping someone can enlighten me, thanks.
You can create two classes both with subscripting overloaded for you desired type:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct s
{
	int n;
	s(int i):n(i){}
	void operator [] (int);
};
struct t
{
	s operator[] (int n) {return s(n);}        
};
//...
t foo;
foo[1][2];

Last edited on
Hi Bazzy,

Thanks for the reply. Currently, i have 2 files, M22.h and M22.cpp. So with the code you provided above, the struct s class is like the M22.h class in a sense? So if i implement operator overload on subscript twice, shouldn't i implement it in struct s too and why only have implementation code in struct t?

Sorry, but i just learned C++ and not very sure how "s operator[] (int n) {return s(n);" is able to take in values of [1] and [2]. Thanks
Last edited on
I'll show what my code does:

/* ( t ) */foo[1][2]; foo[1] returns an unnamed instance of class s so that would be as s(1).
s has a [] operator overloaded so s(1)[2] is legal, consequently you can use foo[1][2]
The class t is only used to have an extra [] operator available.
Last edited on
Hi Bazzy,

Thanks for explaining! Should i create separate .cpp files for struct s and t, or can i put them in the same .cpp file? So since i have an additional header.h file that is included is stored in 2x2.cpp for example (without the int main() as it is in another test.cpp file).

So how do i call or include this struct s class as i am assuming that struct t is like my 2x2.cpp file? Should the struct s code be within 2x2.cpp or another file? If another file, how do i call it? Thanks!
Hi Bazzy,

I tried to do this, but i can't seem to make it work. The error i keep getting when trying to compile (test.cpp with main() not included here) is: M22* is not a structure type.

And i only get this error when i uncomment this code in [] operator overload:

 
TmpM22 tmpM22(lhs,this.a);


At the moment, my operator overload for [] returns a 1 because i keep facing the error above. If i uncomment that code above, everything compiles. Any thoughts? Thanks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

#include "2x2.h"
#include <iostream>
using namespace std;
M22::M22(int e=1,int f=0,int g=1,int h=0){//constructor
a=e;
b=f;
c=g;
d=h;
}

M22::M22() : a(1),b(0),c(0),d(1){} //constructor by initializer list

int M22::operator [](int lhs){
//if(
//return 1;
//M22 tmpM22(this.a,this.b,this.c,this.d);
//M22 *ptr=&tmpM22;
TmpM22 tmpM22(lhs,this.a);
return 1;
}

//cout overload
ostream & operator << (ostream &lhs, M22 const & rhs){
return lhs << '[' << rhs.a << ',' << rhs.b << ']' << ',' << '[' << rhs.c << ',' << rhs.d << ']';
}

M22::TmpM22::TmpM22(int lhs,int aVal){
i=lhs;
aValue=aVal;
}

int M22::TmpM22::operator [](int rhs){

if(i==1 && rhs==1){
return aValue;
}
        
//return 1;
} 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

#include <iostream>
using namespace std;
class M22 {

int a;
int b;
int c;
int d;
public:
M22(int a,int b,int c,int d);
M22(); 
int operator [] (int lhs);

class TmpM22{
int i;
int aValue;
  TmpM22(int lhs, int aVal);
 int operator [](int rhs);

};

};
Last edited on
this is a pointer so try with this->a
Thanks for pointing that out! I have also made the TmpM22 constructor as public because it gave me problems. But now, my test.cpp file doesn't compile because it complains of: Error: Pointer type needed instead of int.

The error only occur if i do this:
cout << m[1][1] << endl;

But if i change it to the code below, it works fine:

cout << m[1] << endl;
Last edited on
TmpM22 has everything private, declare its constructor to be public or declare M22 to be its friend.
The [] operator needs to be public
How do you declare M22 to be its friend? I have made some changes to my code and made them public for simplicity sake. And also added a new variable called matrixVal so that it can be called for display at M22::operator [](int lhs). However, i am still getting the same error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
class M22 {
//private:
int a;
int b;
int c;
int d;
public:
M22(int a,int b,int c,int d); // init by initializer list
M22();
int operator [] (int lhs);
friend ostream& operator << (ostream &lhs, M22 const  & rhs);

class TmpM22{
public:
int i,matrixVal;
int aValue,bValue,cValue,dValue;
 TmpM22(int lhs, int aVal,int bVal,int cVal,int dVal,int matrix);
 void operator [](int rhs);
};

};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "2x2.h"
#include <iostream>
using namespace std;
M22::M22(int e=1,int f=0,int g=1,int h=0){//constructor
a=e;
b=f;
c=g;
d=h;
}

M22::M22() : a(1),b(0),c(0),d(1){} //constructor by initializer list

int M22::operator [](int lhs){
TmpM22 tmpM22(lhs,this->a,this->b,this->c,this->d,0);//matrix value set to 0 default
return tmpM22.matrixVal;
}


//cout overload
ostream & operator << (ostream &lhs, M22 const & rhs){
return lhs << '[' << rhs.a << ',' << rhs.b << ']' << ',' << '[' << rhs.c << ',' << rhs.d << ']';
}


M22::TmpM22::TmpM22(int lhs,int aVal,int bVal,int cVal,int dVal,int matrix){
i=lhs;
//j=0;
aValue=aVal;
bValue=bVal;
cValue=cVal;
dValue=dVal;
matrixVal=matrix;
}

void M22::TmpM22::operator [](int rhs){

if(i==1 && rhs==1){
matrixVal= aValue;
}else if(i==1 && rhs==2){
matrixVal= bValue;
}else if(i==2 && rhs==1){
matrixVal=cValue;
}else{
matrixVal=dValue;
}

        
} 
Here are some errors I can spot:
> You don't need the constructor with no arguments for M22 as the other constructor you provided has all optional values so it could create ambiguities
> The M22 operator [] is returning an int where you need to return an M22::TmpM22 in order to have the second subscripting operator
> M22::TmpM22 operator [] has void return type but I would expect it to return matrixVal ( int )
> using namespace std; is better if avoided in headers
> you don't need to include iostream in the cpp file as it is already included in 2x2.h


You can declare a friend class as you declare a friend function
Eg:
1
2
3
4
class C
{
    friend class OtherClass;
}
In regards to your comments:

> When i did not create a M22() with no arguments, my compiler complained and do not allow me to compile until i declare one.

> I changed void M22::TmpM22 operator [] to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int M22::TmpM22::operator [](int rhs){

if(i==1 && rhs==1){
matrixVal= aValue;
}else if(i==1 && rhs==2){
matrixVal= bValue;
}else if(i==2 && rhs==1){
matrixVal=cValue;
}else{
matrixVal=dValue;
}
return matrixVal;
        
} 


> I also tried to remove the using namespace std, but when i did so i was met with errors but when i declared it my errors were gone.

> "The M22 operator [] is returning an int where you need to return an M22::TmpM22 in order to have the second subscripting operator"

--> Do you mean i should do this:
1
2
3
4
M22::TmpM22 operator [](int lhs){
TmpM22 tmpM22(lhs,this->a,this->b,this->c,this->d,0);
return tmpM22;
}


Am i doing it right? Cause i wasn't sure i understood what you meant. Thanks
Last edited on
Do you mean i should do this:
...
Yes, You can also do that in a single line of code:
1
2
3
M22::TmpM22 operator [](int lhs){
     return TmpM22(lhs,this->a,this->b,this->c,this->d,0);
}
(The result would be the same)

I also tried to remove the using namespace std...

You just need to use std::ostream instead of just ostream.
Using namespaces in headers is not an error but is best if avoided
Last edited on
Thanks for the reply and so sorry for asking so many questions as i am always met with new errors after solving one.

So i added the lines of code below and met with this errors:

1
2
3
M22::TmpM22 operator [](int lhs){
     return TmpM22(lhs,this->a,this->b,this->c,this->d,0);
}


"2x2.cpp", line 9: Error: operator[](int) must be a member function.
"2x2.cpp", line 10: Error: Can only use this within a non-static member function.
"2x2.cpp", line 10: Error: Can only use this within a non-static member function.
"2x2.cpp", line 10: Error: Can only use this within a non-static member function.
"2x2.cpp", line 10: Error: Can only use this within a non-static member function.
"2x2.cpp", line 10: Error: Too many arguments in cast to TmpM22.


i also tried to remove the using namespace std..

So for this you suggest i just use std::ostream in the 2x2.cpp file i suppose? Anyway i added a copy of my files below, hopefully you can spot something that i very much can't.

2x2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "2x2.h"
using namespace std;
#include <iostream>

M22::M22(int e=1,int f=0,int g=1,int h=0):a(e),b(f),c(g),d(h) {}

M22::M22():a(1),b(0),c(0),d(1){}

M22::TmpM22 operator [](int lhs){
     return TmpM22(lhs,this->a,this->b,this->c,this->d,0);
}

ostream & operator << (ostream &lhs, M22 const & rhs){
return lhs << '[' << rhs.a << ',' << rhs.b << ']' << ',' << '[' << rhs.c << ',' << rhs.d << ']';
}

//TmpM22
M22::TmpM22::TmpM22(int _lhs,int _aVal,int _bVal,int _cVal,int _dVal,int matrix){
lhs=_lhs;
_a=_aVal;
_b=_bVal;
_c=_cVal;
_d=_dVal;
matrixVal=matrix;
}

int M22::TmpM22::operator [](int rhs){
if(lhs==1 && rhs==1){
matrixVal= _a;
}else if(lhs==1 && rhs==2){
matrixVal= _b;
}else if(lhs==2 && rhs==1){
matrixVal=_c;
}else{
matrixVal=_d;
}
return matrixVal;

}


2x2.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using namespace std;
#include <iostream>

class M22 {
private:
int a,b,c,d;
friend class TmpM22;
public:
M22(int a,int b,int c,int d); // init by initializer list
M22();
friend ostream& operator << (ostream &lhs, M22 const  & rhs);


class TmpM22{
friend class M22;

//public:
int lhs,_a,_b,_c,_d,matrixVal;
M22 *m22;
TmpM22(int lhs,M22 *ptr);
TmpM22(int lhs,int _aVal,int _bVal,int _cVal, int _dVal, int matrix);
int operator [](int rhs);
};

TmpM22 operator [] (int lhs);
};

line 9 (cpp file): int M22::TmpM22::operator [](int lhs){ (Sorry I didn't noticed the missing part)
(cpp file) If i change line 9 to int M22::TmpM22::operator [](int lhs), i already declare int M22::TmpM22::operator [](int lhs) in line 27 onwards. And i will get an error:

"2x2.cpp", line 10: Error: a is not a member of M22::TmpM22.
"2x2.cpp", line 10: Error: b is not a member of M22::TmpM22.
"2x2.cpp", line 10: Error: c is not a member of M22::TmpM22.
"2x2.cpp", line 10: Error: d is not a member of M22::TmpM22.
"2x2.cpp", line 27: Error: M22::TmpM22::operator[](int) already had a body defined.

Shouldn't M22 operator[] return a TmpM22 class as declared as my return type in line 25 of .h file? And a pointer such as this can use "->" to point to variables (e.g. a,b,c,d) and member functions too?
Last edited on
Shouldn't M22 operator[] return a TmpM22 class as declared as my return type in line 25 of .h file?

Yeah, with two [] operators overloaded I got a bit of confusion,
so that should be M22::TmpM22 M22::operator [](int lhs){



And a pointer such as this can use "->" to point to variables (e.g. a,b,c,d) and member functions too?

Yes




at line 22 of the header: int operator [](int rhs); should be public
Last edited on
Excellent! Wow, it works!

But i am just wondering for this code: M22::TmpM22 M22::operator [](int lhs)

I don't quite understand why the code is this way. Usually we put the return type in front, followed by the class (M22)::embedded class(TmpM22). So why is there a space between M22::TmpM22 and M22 operator[int rhs]?

Why is this wrong TmpM22 M22::operator[](int lhs)? Could you explain the structure/sequence of the construction of the code above given to me by you?

Also, when we do return TmpM22(lhs,this->a,this->b,this->c,this->d,0);, how does this work with how we call it via the int main() class like
1
2
M22 m(1,2,8,0);
cout << m[1][1] << endl
Last edited on
You should remember that TmpM22 is a nested class so it has to be accessed from M22

As I explained some posts above, when returning TmpM22(constructor arguments) you are returning an unnamed instance of that class.
the code
1
2
M22 m(1,2,8,0);
cout << m[1][1] << endl;
is the same as
1
2
3
M22 m(1,2,8,0);
M22::TmpM22 t ( 1, m.a, m.b, m.c, m.d, 0 );
cout << t[1] << endl;
Last edited on
I would just like to state that, in reality, if you need to pass a location inside an n-dimensional array, you'd just pass a vector of size n. Nobody does this fooling around with syntax.
Last edited on
Pages: 12