2 Dimension Subscript Operator Overload?

Pages: 12
Feb 21, 2009 at 5:29pm
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.
Feb 21, 2009 at 5:41pm
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 Feb 21, 2009 at 5:42pm
Feb 23, 2009 at 10:32am
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 Feb 23, 2009 at 10:34am
Feb 23, 2009 at 1:06pm
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 Feb 23, 2009 at 1:06pm
Feb 23, 2009 at 3:47pm
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!
Feb 23, 2009 at 4:52pm
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 Feb 23, 2009 at 4:52pm
Feb 23, 2009 at 5:46pm
this is a pointer so try with this->a
Feb 23, 2009 at 6:31pm
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 Feb 23, 2009 at 6:41pm
Feb 23, 2009 at 6:41pm
TmpM22 has everything private, declare its constructor to be public or declare M22 to be its friend.
The [] operator needs to be public
Feb 23, 2009 at 7:00pm
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;
}

        
} 
Feb 23, 2009 at 9:32pm
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;
}
Feb 24, 2009 at 5:45am
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 Feb 24, 2009 at 5:59am
Feb 24, 2009 at 11:18am
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 Feb 24, 2009 at 11:18am
Feb 24, 2009 at 12:06pm
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);
};

Feb 24, 2009 at 12:30pm
line 9 (cpp file): int M22::TmpM22::operator [](int lhs){ (Sorry I didn't noticed the missing part)
Feb 24, 2009 at 12:55pm
(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 Feb 24, 2009 at 12:57pm
Feb 24, 2009 at 1:21pm
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 Feb 24, 2009 at 1:25pm
Feb 24, 2009 at 1:39pm
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 Feb 24, 2009 at 1:49pm
Feb 24, 2009 at 1:52pm
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 Feb 24, 2009 at 1:52pm
Feb 24, 2009 at 3:21pm
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 Feb 24, 2009 at 3:30pm
Pages: 12