C++ 5일차 - 3

JUSTICE_DER·2023년 2월 7일
0

C++

목록 보기
7/20

59강 - STL - 벡터, 리스트

#include <iostream>
#include "CList.h";
#include <vector>
#include <list>

using std::vector;
using std::list;

int main()
{
	//배열
	vector<int> vInt;

	vInt.push_back(10); //맨 뒤에 값추가 - arrAdd

	vInt[0] = 100; //특정 인덱스 접근 - 오퍼레이터 구현
	vInt.at(0);

	vInt.data(); //시작주소를 반환해줌 - 그냥 시작주소
	vInt.size(); //현재 배열에 몇개 집어 넣었는지 - iCount
	vInt.capacity(); //현재배열 최대값 - imaxCount


	//리스트
	list<int> ilist;

	ilist.push_back(10);
	ilist.push_front(20);
	ilist.size();


	return 0;
}

C++은 위처럼 include하여 배열과 리스트의 자료형을 사용할 수 있다.
대부분의 기능이 다 구현이 되어있다.

해당 자료구조의 설계를 굳이 알지 않고도,
해당 자료구조 내의 데이터를 순회할 수 있는 방법은
Iterator라는 것이 있다.

List<int>::iterator _iter
위처럼 사용할 수 있다.
List클래스내의 iterator라는 클래스가 또 존재하고(내부클래스),
해당 객체인 _iter를 만든 것이다.

	list<int>::iterator  _iter = ilist.begin();
	int iData = *_iter; //포인터가 아님
    					//오퍼레이터 오버로딩

*_iter와, ilist[0] = 1002개는 모두 연산자를 오버로딩한 것으로, 
포인터는 아니지만, 값을 참조한다는 느낌으로 포인터처럼 보이도록 *를 쓰고,
포인터지만, &라는 레퍼런스를 return타입으로 사용하여 
포인터처럼 보이지 않도록 하는 방법을 사용한다는 점에서 유사하다.

그래서 위처럼, begin이라는 것으로, 해당 자료구조의 첫 번째 노드를 가리키게 되고, *연산자가 붙으면, 노드의 데이터부분만 꺼내온다.

이를 반복자라고 한다.
자료구조안의 데이터를 간단하게 접근하고 순회하는 용도로 쓰인다.

60강 - iterator

list뿐만 아니라
vector안에도 iterator가 구현되어 있다.
그리고 해당 iterator를 자료구조에 맞게 선언하고
1을 더하면, // _iter ++;
배열이면 당연히 다음 데이터를 가리키도록 동작하겠지만,
list조차도 다음 데이터를 가리키도록 동작하게 된다.

그래서 iterator를 사용하면 for문을 돌리기 매우 쉬워진다.

_iter = listInt.begin();
for(_iter; _iter!= listInt.end(); _iter++){
	//이렇게 구현
}

위처럼 시작데이터부터 끝데이터까지 간단히 순회할 수 있다.
참고로 해당 자료구조형의 end()라는 것은, 제일 마지막 데이터노드가 아니라,
마지막에서 한칸 더 간 공간을 의미한다.
그 이유는 그냥 위처럼 더 편리하게 사용하기 위해서이다.

61강 - iterator(2)

이터레이터를 직접 구현해본다고 한다.
이터레이터는 자료구조마다 같은 이름이지만, 다른 방식으로 동작한다.
먼저 구현해볼 자료구조는 vector
이전에 구현해본 가변형 배열이다.

이전에 써봤던 size라는 기능 등 3개를 간단히 추가할 수 있었다.

template <typename T>
class CArr
{
private:
	T* iarr;
	int iCount;
	int maxCount;
public:
	CArr();
	~CArr();
public:
	void push_back(const T& _iData);
	void resizeArr(int size);
	T* data() { return iarr; }	//간단한 기능 3개를 추가해주었다.
	int size() { return iCount; }
	int capacity() { return maxCount; }
public:
	T& operator[] (int index);
};

그 외에, Vector.begin()과 같이, 처음 노드의 값을 출력한다거나
Vector.end()와 같이, 마지막에서 다음인덱스를 가리키는 노드를 탐색하는
함수들을 추가해야할 것이다.

list<int>::iterator  _iter = ilist.begin(); 

이런식으로 iterator를 설정했었다.

list라는 클래스 내의 기능을 쓴다는 의미로 ::를 붙였는데,
해당 iterator역시 클래스 이름이다.
즉, iterator라는 것은 list<>의 내부클래스로 구현을 해야한다는 것이다.
그리고 중요한 사실은, 해당 begin의 반환값은 결국, iterator일 것이다.

template <typename T>
class CArr
{
private:
	T* iarr;
	int iCount;
	int maxCount;
public:
	void push_back(const T& _iData);
	void resizeArr(int size);
	T* data() { return iarr; }	//간단한 기능 3개를 추가해주었다.
	int size() { return iCount; }
	int capacity() { return maxCount; }
public:
	T& operator[] (int index);
public:
	CArr();
	~CArr();

	class iterator {
	private:

	public:
		iterator();
		~iterator();
	};
};

이렇게 구현이 된 것으로, iterator가 내부 클래스로 들어갔고,
CArr이 template이므로, 해당 내부 클래스인 iterator도 템플릿의 영향을 받는다.

즉 CArr<int>::iterator 와 CArr<float>::iterator는 다른 것이다.

일단 Vector-가변배열에서의 iterator로서 특정 인덱스의 값에 접근하려면,
시작지점을 알고, 인덱스를 알면, 해당 Vector의 모든 값에 접근할 수 있을 것이다.

작성하다보니 클래스의 멤버함수를 지정할때쓰는 ::와,
클래스의 멤버변수를 직접지정하는 c.a와 같은 표기가 헷갈리기 시작한다..

//typedef CArr<T>::iterator CArr<T>::begin()
//아래 함수는, CArr<T>의 iterator클래스 자료형으로 반환하는 CArr<T>의 begin이라는 함수
template<typename T>
CArr<T>::iterator CArr<T>::begin()
{
	//begin은, 시작을 가리키는 iterator를 만들고, 반환해주어야함.
	//CArr<T>::iterator i_tmp(iarr, 0); //생성자 //굳이 앞을 명시할 필요는 없다.
	//아래처럼 굳이 변수명을 만들지 않고 return하여 바로 값을 전달할 수 있다.
	//바로 return을 하지 않는다면, 해당 객체에 접근할 방법이 없으므로, 바로 return
	return iterator(iarr, 0); 
}

begin이라는 기능을 구현해 보았다.

iterator에는 추가로 +1을 했을떄, 해당 자료구조에 맞게
다음 값을 가리키도록 동작했었고,
그 외에 iterator 변수를 *로 참조하는 것처럼 하여 값을 가져오기도 했다.

추후 구현해보자

profile
Time Waits for No One

0개의 댓글