[C++] Operator Overloading - const/Index Operator of Array
Array in C, C++ have a bound issue, which can be a problem or not.
So the following code can be excuted.
int main(void)
{
int arr[5] = {1,2,3,4,5};
cout<<arr[-2]<<endl; //access location of 'arr address + sizeof(int) * -2'
cout<<arr[-1]<<endl; //access location of 'arr address + sizeof(int) * -1'
cout<<arr[5]<<endl; //access location of 'arr address + sizeof(int) * 5'
cout<<arr[6]<<endl; //access location of 'arr address + sizeof(int) * 6'
return 0;
}
It can be applied usefully, and as I said at the beginning sometimes not.
So when the code need an array which have a clear range, just overload index operator '[ ]'.
Actually, it's a class that 'operates like array'.
#include <iostream>
#include <cstdlib>
using namespace std;
class BoundCheckIntArray
{
private:
int* arr;
int arrlen;
BoundCheckIntArray(const BoundCheckIntArray& arr){ }
BoundCheckIntArray& operator=(const BoundCheckIntArray& arr){ }
public:
BoundCheckIntArray(int len) : arrlen(len)
{
arr=new int[len];
}
int& operator[](int idx)
{
if(idx<0 || idx>=arrlen)
{
cout<<"Array index out of bound exception"<<endl;
exit(1);
}
return arr[idx];
}
int& operator[](int idx) const
//const defined array could be passed, so usually overloads both
{
if(idx<0 || idx>=arrlen)
{
cout<<"Array index out of bound exception"<<endl;
exit(1);
}
return arr[idx];
}
int GetArrLen() const
{
return arrlen;
}
~BoundCheckIntArray()
{
delete []arr;
}
};
void ShowAllData(const BoundCheckIntArray& ref)
{
int len = ref.GetArrLen();
for(int idx=0; idx<len; idx++)
cout<<ref[idx]<<endl;
}
int main(void)
{
BoundCheckIntArray arr(5);
for(int i=0; i<5; i++)
arr[i]=(i+1)*10;
ShowAllData(arr);
return 0;
}
Result
10
20
30
40
50
In C/C++ copy of array like this code is not available
int arr1[3] = {1,2,3};
int arr2[3] = {4,5,6};
arr1 = arr2;
Basically, in C/C++ line3 occurs error because 'arr1' and 'arr2' in line3 mean constant of the array address.
An array is a storage, and the data in the storage should be guaranteed in the usual.
Many experts say that using two same data storage is dangerous, so we should avoid copying the storge.
(Of course, there are exceptions case by case.)
Defining array class for the storage of class objects
We can use two different ways of defining array class for the storage of class objects.
1. A class based in array and contains the address of the class object.
2. A class that contains the class object.
1.
#include <iostream>
#include <cstdlib>
using namespace std;
class Point{
private:
int xpos, ypos;
public:
Point(int x=0, int y=0) : xpos(x), ypos(y){}
friend ostream& operator<<(ostream& os, const Point& pos);
};
ostream& operator<<(ostream& os, const Point& pos){
os << '[' << pos.xpos << " ," << pos.ypos << ']' << endl;
return os;
}
class BoundCheckPointArray{
private:
Point* arr;
int arrlen;
BoundCheckPointArray(const BoundCheckPointArray& arr){}
BoundCheckPointArray& operator=(const BoundCheckPointArray& arr){}
public:
BoundCheckPointArray(int len) : arrlen(len){arr = new Point[len];}
Point& operator[](int idx){
if(idx<0 || idx>=arrlen){
cout << "Array index out of bound exception" << endl;
exit(1);
}
return arr[idx];
}
Point& operator[](int idx) const{
if(idx<0 || idx>=arrlen){
cout << "Array index out of bound exception" << endl;
exit(1);
}
return arr[idx];
}
int GetArrLen() const {return arrlen;}
~BoundCheckPointArray(){delete []arr;}
};
int main(){
BoundCheckPointArray arr(3);
arr[0] = Point(3, 4);
arr[1] = Point(5, 6);
arr[2] = Point(7, 8);
for(int i = 0; i < arr.GetArrLen(); i++){
cout << arr[i];
}
return 0;
}
2.
#include <iostream>
#include <cstdlib>
using namespace std;
class Point{
private:
int xpos, ypos;
public:
Point(int x=0, int y=0) : xpos(x), ypos(y){}
friend ostream& operator<<(ostream& os, const Point& pos);
};
ostream& operator<<(ostream& os, const Point& pos){
os << '[' << pos.xpos << " ," << pos.ypos << ']' << endl;
return os;
}
typedef Point * POINT_PTR;
class BoundCheckPointPtrArray{
private:
POINT_PTR * arr;
int arrlen;
BoundCheckPointPtrArray(const BoundCheckPointPtrArray& arr){}
BoundCheckPointPtrArray& operator=(const BoundCheckPointPtrArray& arr){}
public:
BoundCheckPointPtrArray(int len) : arrlen(len){arr = new POINT_PTR[len];}
POINT_PTR& operator[](int idx){
if(idx<0 || idx>=arrlen){
cout << "Array index out of bound exception" << endl;
exit(1);
}
return arr[idx];
}
POINT_PTR& operator[](int idx) const{
if(idx<0 || idx>=arrlen){
cout << "Array index out of bound exception" << endl;
exit(1);
}
return arr[idx];
}
int GetArrLen() const {return arrlen;}
~BoundCheckPointPtrArray(){delete []arr;}
};
int main(){
BoundCheckPointPtrArray arr(3);
arr[0] = new Point(3, 4);
arr[1] = new Point(5, 6);
arr[2] = new Point(7, 8);
for(int i = 0; i < arr.GetArrLen(); i++){
cout << *(arr[i]);
}
delete arr[0];
delete arr[1];
delete arr[2];
return 0;
}
Result
[3, 4]
[5, 6]
[7, 8]
Both code '1.' and '2.' have same results.
But in '2.' you don't need to consider about shallow copy and deep copy.
And '1.' is not a beautiful code because it use more data which can be saved by using pointer like '2.'.
So use '2.' in the usual.
[참고자료]
- 윤성우의 열혈 C++ 프로그래밍