C++ Your own string class.
1.Introduction.
문자열 클래스를 만들어보자.
문자열 클래스는 아패와 같은 내용들을 지원해야 한다.
문자(char) 로 부터의 생성, C 문자열 (char *) 로 부터의 생성.
문자열 길이를 구하는 함수.
문자열 뒤에 다른 문자열 붙이기.
문자열 내에 포함되어 있는 문자열 구하기.
문자열이 같은지 비교.
문자열 크기 비교 (사전 순).
기존 C에서는 문자열을 나타내기 위해 널 종료 문자열(Null-terminating string)이라는 개념을 도입해서 문자열 끝에 NULL 문자를 붙여 문자열을
나타내는 방식을 사용하였다.
C++에서는 표준 라이브러리로 string 킇해스를 지원하고 있다. 일단 간단히 생각해서 우리가 만들 MyString 클래스에 멤버 변수로 뭘 필요할지
고민해본다. 대표적으로 아래 두 개의 데이터들이 필요하다고 볼 수 있다.
문자열 데이터가 저장된 공간을 가리키는 포인터.
문자열 데이터의 길이.
객체에 문자열 데이터를 직접 보관하는 것이 아니라, 그 저장된 공간을 가리키는 포인터를 보관하냐고 의문점을 가질 수 있다. 이렇게 하는 이유는 나중에 문자열 데이터의 크기가 바뀔 때, 저장된 공간을 가리키는 방식으로 하면, 그 메모리를 해제한 뒤에, 다시 할당할 수 있지만, 직접 보관하면 그럴 수 없기 때문이다. 또한 문자열 데이터의 길이를 보관하는 이유는 문자열 길이를 사용할 일이 많은데, 그 때마다 계속 길이를 구하는 것은 불필요한 일이기 때문이다. 따라서 길이를 한 번 구해놓고 길이가 바뀔 때까지 변경하지 않는 방법이 나을 것 같다.
class MyString
{
char *string_content; //문자열 데이터를 가리키는 포인터.
int string_length;// 문자열 길이.
}
일단 정보는 private로 설정하였다. 왜냐하면 원하는 모든 작업들을 수행할 수 있도록 충분한 함수들을 제공해야 할 것이다 생성자들은 어떻냐면, 아래와 같은 생성자들을 만들어야 한다.
// 문자 하나로 생성
MyString(char c);
// 문자열로 부터 생성
MyString(const char* str);
// 복사 생성자
MyString(const MyString &str);
위의 소스코드같이 3개의 생성자들을 정의하였고, string_content를 동적 할당으로 처리하였기 떄문에 반드시 소멸자에서 동작해제하는 것을
처리해줘야 한다.사실 이 점이 클래스의 큰 장점이다. C에서 구조체같은 것으로 문자열을 구현하였다면 이를 동작해제하는 것도
처리해줘야 했었기 때문이다. 즉 클래스를 사용하는 사람은 안에서 어떻게 돌아가는지 신경쓰지 않아도 된다.
이제 우리는 쉽게 문자열의 길이를 구하는 함수를 만들 수 있게 되었다. string_length를 리턴해주면 된다. 참고로 내부 변수의 내용을 바꾸지
않거나, 상수 함수들로만 호출하는 함수들은 length 함수처럼 const 함수로 정의해주면 된다.
int MyString::length() const { return string_length; }
void MyString::print()
{
for(int i = 0; i != string_length; i ++)
cout << string_content[i];
}
MyString str1("very very very long string"); str1.assign("short string"); str1.assign("very long string");
따라서 이러한 비효율 적인 막기 위해서는 얼마나 많은 공간이 할당되어 있는지 알 수 있는 정보를 따로 보관하는 것이 좋을 것이라 생각된다. =memory_capacity 라는, 현재 할당된 메모리 공간의 크기를 나타내는 새로운 변수를 사용할 수 있다.
char MyString::at(int i)
{
if(i >= string_length || i < 0) return NULL;
else return string_content[i];
}
i가 허용되는 범위를 초과한다면 NULL을 리턴하도록 한다.문자열 처리에서 가장 사용되는 작업으로, 문자열 중간에 다른 문자열을 삽입하는 작업이다. 여태까지 만들언 놓은 함수들만을 가지고도 insert 작업을 쉽게 구현할 수 있지만, 자주 사용되는 작업이다 보니까 미리 만들어 놓아서 인터페이스로 제공하는 것도 좋다.
MyString& MyString::insert(int loc, MyString& str);
MyString& MyString::insert(int loc, const char* str);
MyString& MyString::insert(int loc, char c);
일단 insert 작업이 많은 용도로 사용되기 때문에 3 개의 insert 함수를 준비한다. loc을 어떻게 생각할 지 기준을 정해야 하는데, insert 함수에서 입력 위치를 받는 경우, 그 입력 위치 '앞' 에 문자를 insert 하는 경우가 많다. 예를 들어서 abc라는 문자열에 insert(1, "d") 를 하게 된다면,1의 위치에 있는 b 앞에 (참고로 모든 위치는 배열의 인덱스로 생각한다. 즉 a 는 0 의 위치) d 가 삽입된다. insert 함수는, 이전의 assign 함수 처럼 새로 메모리를 할당해야 할 경우와, 할당할 필요가 없는 경우를 나누어서 처리한다. 만일 원 문자열의 길이 + 새로 삽입되는문자열의 길이가, 현재의 할당된 메모리의 크기 보다 크다면 메모리를 새로 할당해야 하지만, 작은 경우에는, 메모리를 해제하고 재할당하는데 시간을 낭비할 필요가 없다. 메모리를 다시 할당해야 하는 경우, 일단 string_content 에 새로운 할당된 메모리 주소가 들어가므로, 이전의 메모리 주소를 보관하기 위해 prev_string_content 함수를 이용한다.즉 string_content 에 삽입된 문자열을 손쉽게 집어 넣을 수 있다. 반면에, 메모리를 다시 할당할 필요가 없는 경우 원래의 문자열 내용을 이용하며 삽입된 문자열을 string_content 에 넣어야 하므로 약간의 트릭을 이용한다.자리가 바뀌는 문자열들을 먼저 뒤로 밀어버리는 것이다. 이미 메모리의 할당된 공간은 충분하기 때문에 뒤로 미는 것을 쉽게 수행할 수 있다.
4.C++Erase function
erase 함수는 insert 함수보다 만들기 훨씬 쉬운데, 기본적으로 데이터의 양이 줄어 드는 것이기 때문에 복잡하게 capacity 이런 것들을 생각할 필요가 없다.
MyString& erase(int loc, int num);
erase 함수는 위와 같이 생겼고, loc은 insert 와 동일하게 loc 의 해당하는 문자 '앞' 을 의미한다. num은 지우는 문자의 수를 의미한다. 예를 들어서 abcd 라는 문자열에서 erase(1, 2); 를 하게 된다면, 1 에 해당하는 문자 'b' 의 앞에서 부터 2 문자를 지우게 되어, bc 가 지워져서 ad 가 리턴된다.
5.C++ Find function
insert 와 erase 이외에 사용되는 또 다른 작업으로 find 함수가 있다. 사실 insert, erase, find 는 문자열 연산의 필수적인 함수다. 그렇기 때문에 find 함수 자체를 어떻게 구현하느냐에 따라 문자열 클래스의 전반적인 성능이 좌지우지 되는 경우도 있다. 왜냐하면 insert 와 erase 는 연산 시간이 크게 오래 걸리지는 않지만, 문자열의 크기가 매우 크다면 find 연산은 오래 걸릴 수 있게 될 수 있다.
문자열을 검색하는 알고리즘은 많지만, 어떤 상황에 대해서도 좋은 성능을 발휘하는 알고리즘은 없다. (예를 들어 짧은 문자열 검색에 최적화 된 알고리즘과 긴 문자열 검색에 최적화 된 알고리즘들.) 그렇기에 특별한 알고리즘을 사용하는 경우에는 그 클래스의 사용 목적이 명확해서 그 알고리즘이 좋은 성능을 발휘할 수 있는 경우에만 사용하는 것이 보통이다.
int find(int find_from, MyString& str);
int find(int find_from, const char* str);
int find(int find_from, char c);
int compare(MyString& str);
'#Programming Language > C++' 카테고리의 다른 글
C++ Various overloading. (0) | 2018.04.01 |
---|---|
C++ Operator overloading. (0) | 2018.04.01 |
C++ Object-oriented programming. (0) | 2018.03.30 |
C++ Everything in an object. (0) | 2018.03.30 |
C++ Features of C ++ only. (0) | 2018.03.30 |