#include <iostream>
class Array {
private:
int* ptr;
int size;
public:
Array(int val, int size)
:size{ size }
{
ptr = new int[size];//배열 동적생성
for (int i = 0; i < size; i++)
{
ptr[i] = val + i;
}
}
int GetSize() const
{
return size;
}
int GetValue(int index) const
{
//if (index < size && index >= 0)//index 범위 안에 있다면
// return ptr[index];
//else
//{
// std::cout << "Out of Range!!" << std::endl;
//}
return ptr[index];
}
Array& operator=(const Array& rhs)//대입 연산자
{
if (this == &rhs)//동일 객체 대입 방지
return *this;//객체 반환
delete[] ptr;//메모리 누수 방지
size = rhs.size;
ptr = new int[size];
for (int i = 0; i < size; i++)
{
ptr[i] = rhs.ptr[i];
}
}
~Array()
{
delete[] ptr;
}
};
int main()
{
Array a1{ 5,10 };
std::cout << a1.GetValue(1) << std::endl;
std::cout << a1.GetValue(-1) << std::endl; //쓰레기 값
std::cout << a1.GetValue(15) << std::endl; //쓰레기 값
}
경계 검사 : 내가 사용하겠다고 한 범위 (위의 코드에서는 0~9 index 까지)에서만 안전하게 사용가능하도록 검사하는 것. 위의 -1,15는 range 범위 밖의 값이기 때문에 접근이 불가능 하도록 해주는 것이 좋다.
#include <iostream>
class Array {
private:
int* ptr;
int size;
public:
Array(int val, int size)
:size{ size }
{
ptr = new int[size];//배열 동적생성
for (int i = 0; i < size; i++)
{
ptr[i] = val + i;
}
}
int GetSize() const
{
return size;
}
Array& operator=(const Array& rhs)//대입 연산자
{
if (this == &rhs)//동일 객체 대입 방지
return *this;//객체 반환
delete[] ptr;//메모리 누수 방지
size = rhs.size;
ptr = new int[size];
for (int i = 0; i < size; i++)
{
ptr[i] = rhs.ptr[i];
}
}
~Array()
{
delete[] ptr;
}
int operator[](int index)
{
if (index < 0 || index > size) //경계 검사
{
std::cout << "Out of Range!" << std::endl;
exit(1);// 1을 출력해주고 종료 됨 (문제를 알려주는 것)
}
else
return ptr[index];
}
};
int main()
{
Array a1{ 5,10 };
std::cout << a1[1];//a1.operator[](1)로 변환
std::cout << a1[-1];// exited with code 1
}
operator[ ]를 멤버 함수로 선언하여 경계 검사를 진행해 주고 내가 할당한 range 밖에 접근할 때 exit(1)을 사용하여 1을 호출해주고 오류를 알려준다.
Point& operator[](int idx)
{
if( idx < 0 || idx >= arr_len)
{
cout << "Array out of bound!" << endl;
exit(1);
}
return arr[idx];
}
위에서 배운 코드로 예를 들어보면
int& operator[](int index)
{
if (index < 0 || index > size) //경계 검사
{
std::cout << "Out of Range!" << std::endl;
exit(1);// 1을 출력해주고 종료 됨 (문제를 알려주는 것)
}
else
return ptr[index];
}
위와 같이 참조자로 반환을 해야한다 그렇지 않다면 ptr[index]의 값을 ‘복사'하여 반환해 줄 것이고 5 = 10; 과 같이 상수에 상수를 대입하려 할 것이다. 이때 참조자로 반환을 해야 a[0] = 10;과 같이 배열에 값을 할당 가능하다.
#include <iostream>
class Array {
private:
int* ptr;
int size;
public:
Array(int val, int size)
:size{ size }
{
ptr = new int[size];//배열 동적생성
for (int i = 0; i < size; i++)
{
ptr[i] = val + i;
}
}
int GetSize() const
{
return size;
}
Array& operator=(const Array& rhs)//대입 연산자
{
if (this == &rhs)//동일 객체 대입 방지
return *this;//객체 반환
delete[] ptr;//메모리 누수 방지
size = rhs.size;
ptr = new int[size];
for (int i = 0; i < size; i++)
{
ptr[i] = rhs.ptr[i];
}
}
~Array()
{
delete[] ptr;
}
int& operator[](int index)//값의 변환 가능 ( 참조형으로 반환하니까!)
{
if (index < 0 || index > size) //경계 검사
{
std::cout << "Out of Range!" << std::endl;
exit(1);// 1을 출력해주고 종료 됨 (문제를 알려주는 것)
}
else
return ptr[index];
}
int operator[](int index) const//값의 변환 불가능
{
if (index < 0 || index > size) //경계 검사
{
std::cout << "Out of Range!" << std::endl;
exit(1);// 1을 출력해주고 종료 됨 (문제를 알려주는 것)
}
else
return ptr[index];
}
};
int main()
{
const Array a1{ 5,10 };//값의 변형 불가능
std::cout << a1[0]; //const 함수 호출 함
Array a2{ 3,5 };
a2[0] = 10;//값의 변형
}
main에 const 객체와 그냥 객체가 있을 때 첨자 연산자 오버로딩은 위와 같이 따로따로 구현해 줘야한다.
사용 목적이 전혀 다르기 때문에 반환형이 다르고 const 객체에서는 컴파일러가 const 함수를 찾기 때문에 반드시 따로 구현 해줘야한다.
그럼 아래와 같이 하면 안돼?
int& operator[](int index) const
{
if (index < 0 || index > size) //경계 검사
{
std::cout << "Out of Range!" << std::endl;
exit(1);
}
else
return ptr[index];
}
컴파일러 오류가 발생해서 안된다. (사실 안돼야 하는데 컴파일러에 따라 가능한 경우도 있는 것 같다… like me), int&이 반환형이기 때문에 const와 모순이 된다. 이는 컴파일러가 error처리를 한다.
두 가지 방법이 존재
#include <iostream>
class Array {
private:
int* ptr;
int size;
Array& operator=(const Array& rhs)//대입 연산자
{
}
Array(const Array& other)//복사 생성자
{
}
public:
///중략~~
};
int main()
{
const Array a1{ 5,10 };
Array a2{ 3,5 };
a2 = a1;//a2.operator=(a1) 불가능
Array a3 = a1;//복사 생성자 호출 됨
}
#include <iostream>
class Array {
private:
int* ptr;
int size;
public:
Array& operator=(const Array& rhs) = delete;
Array(const Array& other) = delete;
Array(int val, int size)
:size{ size }
{
ptr = new int[size];//배열 동적생성
for (int i = 0; i < size; i++)
{
ptr[i] = val + i;
}
}
//중략~
};
int main()
{
const Array a1{ 5,10 };
Array a2{ 3,5 };
a2 = a1;//a2.operator=(a1) 불가능
Array a3 = a1;//복사 생성자 호출 됨
}
해당 함수를 구현하지 못하도록 delete로 명시해 주는 것! 자동 생성도 불 가능함