iterator도 직접 구현을 해 보겠습니다.
표준 라이브러리에서 제공하는 iterator는
클래스 안에 존재하는 inner 클래스였죠?
vector(가변 배열)와 같은 기능을 하는
클래스 템플릿을 작성한 cArr.h 파일로 가서
inner 클래스 iterator를 작성하겠습니다.
cArr.h에
클래스 iterator를 추가했습니다.
long long형 멤버 m_ll가 있습니다.
이때 64Bit 환경에서 클래스 cArr의 크기는 몇 Byte일까요?
cArr의 멤버는 포인터 하나와 int형 멤버 두 개가 있네요.
포인터는 환경 크기와 같으므로 64Bit 환경에서 8Byte입니다.
여기에 int가 두 개이므로 8 + 4 + 4 = 16Byte입니다.
여기에 iterator 클래스는 long long 멤버 m_ll이 있습니다.
long long은 8Byte이죠. 해당 클래스가 내부에 존재하므로
16 + 8 = 24Byte일까요?
아닙니다.
cArr 클래스 내부에 iterator 클래스가 있지만
둘은 엄연히 다른 클래스입니다.
cArr 클래스를 통해 객체를 만들었다고 해서
해당 객체가 iterator 클래스의 멤버 m_ll을
갖고 있는 것은 아니니까요.
cArr 클래스를 통해 만든 객체의 크기는 16Byte입니다.
반대로 iterator 클래스를 통해
만든 객체의 크기는 8Byte겠죠.
또한
vector<int>::iterator;
vector<float>::iterator;
vector<short>::iterator;
위와 같은 코드가 있다면
각 iterator는 전혀 다른 클래스입니다.
같은 vector 클래스 템플릿이더라도
vector<int> 클래스와
vector<float> 클래스와
vector<short> 클래스는 다른 것이니까요.
이제 본격적으로iterator 클래스를 구현합시다.
cArr 클래스 내부의 iterator 클래스는
가변 배열의 특정 인덱스를 가리키기 위한 클래스이죠?
그럼 iterator가 있어야 하는 것은 두 가지입니다.
시작 주솟값을 저장할 T형 포인터 m_pData와
몇 번째 인덱스인지 표시할 int형 변수 idx입니다.
cArr는 클래스 템플릿이기 때문에
어떤 자료형이든 저장할 수 있는 vector(가변 배열)입니다.
내부에 있는 iterator 클래스도 어떤 자료형의 데이터든
가리킬 수 있어야겠죠. 그래서 T형 포인터로 선언한 것입니다.
iterator 클래스를 통해 만든 객체는
vector의 시작 주솟값을 알고,
시작 주솟값으로부터 몇 번째 인덱스인지
알고 있다면 모든 인덱스에 접근이 가능하죠.
만약 아래 그림처럼
iterator가 2번 인덱스를 가리키게 하고 싶다면
시작 주솟값에 2를 더하면 되니까요.
37 ~ 42번째 줄을 보시면
생성자와 소멸자를 만들었습니다.
생성자를 통해 멤버 m_pData는 초기에
아무것도 가리키지 않기 때문에 nullptr로,
멤버 idx는 아무런 인덱스에도 접근하지
않았다는 의미로 -1로 초기화하겠습니다.
이제 cArr 클래스에 inner 클래스 iterator를
만들었으니 main 함수에서 위 코드처럼
cArr<int> 클래스 내부의
iterator 클래스를 통해 객체를 만들 수 있게 되었습니다.
iterator 클래스를 통해 myiter라는 객체를 만들었고
이제 myVector이 가리키는 배열의 시작 주솟값을 받으려고 하는데
직접 구현한 vector에는 begin 함수가 없어서
오류가 발생하네요.
begin 함수를 구현해 봅시다.
27번째 줄에 begin 함수를 추가했습니다.
begin 함수를 통해 반환한 값을
iterator에 대입하려면 begin 함수가 반환하는 것은
iterator 자료형이어야겠죠?
이러한 이유로 반환 타입을 iterator로 하였고
iterator 클래스가 아래에 선언되어 있어서
27번째 줄에서는 iterator가 뭔지 모릅니다.
그래서 26번째 줄에서 보이는 것처럼
iterator 클래스가 존재한다고
먼저 선언을 해줘야 합니다.
물론 27번째 줄의 코드를
iterator 클래스 밑에 써 주면
26번째 줄을 작성할 필요가 없습니다.
아래 코드는 begin 함수의 정의입니다.
cArr<T> 클래스 내부의 iterator 클래스가 반환 타입임을
알려 줘야 하기 때문에 typename이라는 키워드를 붙여야 합니다.
그리고 cArr<T> 클래스의 멤버 함수 begin를 정의한다는 의미입니다.
해당 함수에 iterator형 지역 변수 iter를 선언합니다.
그리고 vector의 시작 주솟값을 저장하는
iter의 멤버 m_pData에
vector의 시작 주솟값을 저장하고 있는
cArr<T>형 객체의 m_pData를 저장합니다.
123번째 줄에서 오른쪽에 있는 m_pData는 앞에
this->가 생략되어 있는 것이겠죠?
해당 함수를 호출한 cArr형 객체가 가리키는 vector의
시작 주솟값을 좌항에 대입하는 것이니까요.
시작 주솟값을 저장한 후에 124번째 줄에서
현재 몇 번째 인덱스인지를 의미하는
iter의 멤버 idx에 0을 넣습니다. 시작 주솟값을
저장했다는 것은 0번째 인덱스임을 의미하니까요.
근데 이렇게 쓰고 나니 생성자로 처리해도 될 거 같습니다.
그래서 생성자를 하나 더 추가했습니다.
T형 포인터와 정수를 하나 받았을 때
호출되는 생성자이죠.
해당 생성자가 호출되면 iterator의
멤버 m_pData에 T형 포인터가 저장하고 있는
주솟값을 저장하고 멤버 idx에는 정수로 받은
값을 저장하죠.
이렇게 생성자를 만들고 나면
begin 함수를 위 코드처럼 더 간략하게 작성할 수 있습니다.
iterator 클래스를 통해 iter라는 객체를 만들고
cArr형 객체가 가리키는 vector의 시작 주솟값과
0을 인자로 넘겨서 iter를 초기화하고 이를 반환하는 것이죠.
이를 더 간략하게 쓸 수 있습니다.
어차피 지역 변수 iter를 만들고 초기화하자마자 반환하기 때문에
애초에 이름도 짓지 않고 초기화를 진행한
임시 객체를 반환하는 것입니다.
begin 함수를 구현했으니
main 함수에서 사용해 보겠습니다.
아까와 같은 코드인데
추가로 myVector에 10, 20, 30을 넣었습니다.
실행해 보니 오류 없이 잘 실행되는 것을 확인할 수 있습니다.
실행하고 나면 myiter에는
myVector의 시작 주솟값,
즉 0번째 인덱스의 주솟값이 저장되어 있을 겁니다.
여기서 끝이 아니죠?
26 ~ 27번째 줄에 있는 코드에서 볼 수 있듯이
실제 표준 라이브러리에서 제공하는 함수인
vector를 통해 iterator를 사용할 때에도
iterator에 다양한 연산이 가능했습니다.
* 연산을 통해 인덱스로 접근하여
값을 얻을 수 있었고, 대입까지 가능했죠.
또한 증감(++, --) 연산을 통해
다음 또는 이전 인덱스로 손쉽게 접근이 가능했습니다.
아래 코드처럼
list를 통해 노드에 접근하여
노드의 저장된 값을 출력하기 위해
for 문을 사용할 때 비교 연산도 가능한 것이 보입니다.
따라서 직접 구현한 vector와 같은 기능을 하는
cArr 클래스의 내부에 있는 iterator 클래스에도
이러한 연산자 오버로딩이 되어 있어야 하는 것입니다.
특히 증감 연산자는
전위와 후위라는 개념도
다 따로 구현해 주어야 합니다.
아래 코드 36번째 줄에서 보이듯이
idata에는 시작 주솟값을 저장한 myiter를 1 올렸기 때문에
20이 있는 인덱스를 가리키게 될 겁니다. 이 상태에서
역참조하여 값을 대입하기 때문에 20이 대입될 것이고,
아래 코드의 경우에는
시작 주솟값을 저장한 myiter를 먼저 역참조한 값을
idata에 대입하고 myiter를 1 올리기 때문에
10이 대입된 후 20이 있는 인덱스를 가리킬 겁니다.
강의 출처 : https://www.youtube.com/watch?v=PFc4g8mxOiI&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&pp=iAQB
'C++ > 기초' 카테고리의 다른 글
C++ 기초 : iterator (4) (0) | 2024.04.22 |
---|---|
C++ 기초 : iterator (3) (0) | 2024.04.22 |
C++ 기초 : iterator (1) (0) | 2024.04.20 |
C++ 기초 : STL (vector와 list) (0) | 2024.04.20 |
C++ 기초 : namespace와 입출력 구현 (cout, cin) (0) | 2024.04.19 |