반응형
- 이번에는 클래스 템플릿 Array를 구현하는 문제
차근차근 조건대로 해보자.
- 매개변수가 없는 구성: 빈 배열을 생성합니다. unsigned int n을 매개변수로 사용하여 생성: 기본적으로 초기화된 n개 요소의 배열을 생성합니다. 팁: int * a = new int(); 그런 다음 *a를 표시합니다.
private:
T *arr;
unsigned int _len;
- 복사 및 할당 연산자에 의한 구성. 두 경우 모두 복사 후 원본 어레이나 복사본을 수정해도 다른 어레이에 영향을 주어서는 안 됩니다.
Array(const Array &array)
{
this->arr = NULL;
*this = array;
}
Array &operator=(const Array &array)
{
if (this == &array)
return (*this);
this->_len = array._len;
if (this->arr)
delete [] this->arr;
this->arr = new T[array._len];
for (unsigned int i = 0; i < array._len; i++)
{
this->arr[i] = array.arr[i];
}
return *this;
}
- 연산자를 사용하여 요소에 액세스할 때 해당 인덱스가 범위를 벗어나면 std::Exception이 발생합니다. → 이건
- 배열의 요소 수를 반환하는 멤버 함수 size(). 이 멤버 함수는 매개 변수를 사용하지 않으며 현재 인스턴스를 수정해서는 안 됩니다.
T& operator[] (unsigned int index)
{
if (index >= this->_len)
throw std::out_of_range("index is out of bounds");
return this->arr[index];
};
const T& operator[] (unsigned int index) const
{
if (index >= this->_len)
throw std::out_of_range("index is out of bounds\\n");
return this->arr[index];
};
unsigned int size(void) const
{
return this->_len;
};
여기서 중요한 거 T& operator[] 가 2개가 있다 → 이게 왜 각각 2개가 있을까? 결론부터 말하면 산자 오버로딩 함수를 상수 객체와 비상수 객체에 대해 구현하기 위함.
- 일단 먼저 T& operator[], const T& operator[]가 의미하는 걸 먼저 읽어보자
- T& operator[]: 배열에서 특정 인덱스의 요소를 수정할 수 있도록 한다. 이 함수를 통해 반환된 참조는 해당 배열 요소에 대한 수정이 가능.
- const T& operator[]: 이상수 객체에 대해 오버로딩되었다. 상수 객체의 경우 요소를 수정할 수 없으므로 이 함수는 상수 참조를 반환한다. 이를 통해 해당 배열 요소를 읽을 수 있지만 수정할 수는 없다.
두 가지 버전을 각각 구현함으로써, 상수성에 따라 적절한 동작을 보장할 수 있다. 이것은 C++에서 const-correctness(상수성을 지키는 것)를 유지하는데 중요함. 그렇기 때문에 상수성을 지키는 것은 프로그램의 안정성과 가독성을 높이고 버그를 방지하는데 도움이 된다.
정리하자면, T& operator[]는 배열 요소를 수정하기 위한 함수이고, const T& operator[]는 상수 객체의 배열 요소를 읽기 위한 함수.
그러면 예제를 통해 const T& operator[]가 언제 필요한지 한 번 보자
- constArr[0]은 상수 객체인 constArr에서 첫 번째 요소를 읽으려는 시도이다. 하지만 만약 const T& operator[]가 정의되어 있지 않으면 컴파일러는 이를 처리할 수 없기 때문에 컴파일 에러가 발생한다.
- 결론적으로, 따라서 const T& operator[]가 없는 경우, 상수성을 보장하는 코드에서 컴파일 에러가 발생할 수 있다.
main.cpp
int main(int, char**)
{
Array<int> numbers(MAX_VAL);
int* mirror = new int[MAX_VAL];
srand(time(NULL));
for (int i = 0; i < MAX_VAL; i++)
{
const int value = rand();
numbers[i] = value; // 수정 가능한 요소에 접근, T& operator[]가 필요
mirror[i] = value;
}
//const
const Array<int> constArr = numbers;
int x = constArr[0]; // 상수 객체에서 읽기 시도, const T& operator[]가 필요
std::cout << "x : " << x << std::endl;
const T& operator[]가 없는 경우
결과
main.cpp:21:21: error: no viable overloaded operator[] for type 'const Array<int>'
int x = constArr[0]; // 상수 객체에서 읽기 시도, const T& operator[]가 필요
~~~~~~~~^~
./Array.hpp:56:8: note: candidate function not viable: 'this' argument has type 'const Array<int>', but method is not marked const
T &operator[](unsigned int index)
const T& operator[]가 있는 경우
결과
jaeyojun@c3r3s3 ex02 % ./a.out
x : 432446427
main.cpp
#include <iostream>
#include <cmath>
#include <stdint.h>
#include "Array.hpp"
#define MAX_VAL 750
int main(int, char**)
{
Array<int> numbers(MAX_VAL);
int* mirror = new int[MAX_VAL];
srand(time(NULL));
for (int i = 0; i < MAX_VAL; i++)
{
const int value = rand();
numbers[i] = value; // 수정 가능한 요소에 접근, T& operator[]가 필요
mirror[i] = value;
}
//const
const Array<int> constArr = numbers;
int x = constArr[0]; // 상수 객체에서 읽기 시도, const T& operator[]가 필요
std::cout << "x : " << x << std::endl;
//SCOPE
{
Array<int> tmp = numbers;
Array<int> test(tmp);
}
for (int i = 0; i < MAX_VAL; i++)
{
if (mirror[i] != numbers[i])
{
std::cerr << "didn't save the same value!!" << std::endl;
return 1;
}
}
try
{
numbers[-2] = 0;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\\n';
}
try
{
numbers[MAX_VAL] = 0;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\\n';
}
for (int i = 0; i < MAX_VAL; i++)
{
numbers[i] = rand();
}
delete [] mirror;//
return 0;
}
반응형
'42Seoul > CPP Module 07' 카테고리의 다른 글
ex01 (0) | 2024.02.09 |
---|---|
ex00 (0) | 2024.02.09 |