[문과 코린이의 IT 기록장] C,C++-String 클래스의 디자인(C++ 표준과 표준 string 클래스, 문자열 처리 클래스의 정의)
1. C++ 표준과, 표준 String 클래스
[ 표준 String 클래스 ]
* C++ 표준 라이브러리에는 string이라는 이름의 클래스가 정의되어 있음.
- string클래스 : 문자열 처리를 목적으로 정의된 클래스
- string 클래스의 사용 : 헤더파일 <string> 포함
Case 1 )
#include<iostream>
#include<string>
using namespace std;
int main() {
string str1 = "I like ";
string str2 = "string class";
string str3 = str1 + str2;
// str1.operator+(str2) 연산자 오버로딩
cout << str1 << endl;
cout << str2 << endl;
cout << str3 << endl;
// string 클래스가 << 연산자에 대해서도 오버로딩 되어있음
str1 += str2;
if (str1 == str3) {
cout << "동일 문자열!" << endl;
}
else
cout << "동일하지 않은 문자열! " << endl;
string str4;
cout << "문자열 입력: ";
cin >> str4;
// string 클래스는 >>연산자에 대해서도 오버로딩 되어 있음
cout << "입력한 문자열 : " << str4 << endl;
return 0;
}
2. 문자열 처리 클래스의 정의
* string클래스를 대체할 수 있는(유사한), String 클래스를 실제로 구현해보기
- 그렇다면, 우리가 String클래스를 구현하기 위해서는 무엇들이 요구되는가?
1) 문자열을 인자로 받는 생성자의 정의
앞의 예제에서
string str1 = "I like ";
string str2 = "string Class";
이 코드는
string str1("I like ");
string str2("string Class");
이와 같은 의미이다.
따라서, 이에 적절한 생성자를 정의할 필요가 있다.
2) 생성자, 소멸자, 복사생성자, 대입 연산자의 정의
: 구현해야 하는 String 클래스는, 문자열을 저장 및 표현하는 클래스이다.
- 생성자, 동적할당
: 그런데 저장하고자 하는 문자열의 길이가 일정하지 않다. 따라서 문자열의 저장을 위한 메모리 공간을, 생성자 내에서 동적 할당해야한다.
- 소멸자, 깊은 복사
: 그리고 이로 인해 소멸자를 정의해야 하며, 깊은 복사를 하는 복사생성자와 대입연산자까지 함께 정의하고자 한다.
3) 결합된 문자열로 초기화된 객체를 반환하는 +연산자의 오버로딩
string str3 = str1 + str2;
이 연산의 결과로 str1,str2는 변화가 없지만, str3는 해당 반환값으로 초기화된다.
따라서, 이 둘 중 하나는 반환되도록 오버로딩을 진행해야 한다.
a. 문자열의 주소 값 (str1과 str2가 지니고 있는 문자열을 합한 문자열의 주소 값)
b. string 객체 (str1과 str2가 지니고 있는 문자열을 합한 문자열을 저장하고 있는 객체)
4) 문자열을 덧붙이는 += 연산자의 오버로딩
str1 += str2
이 코드가 동작할 수 있도록, +=연산자를 오버로딩 해야 한다.
5) 내용 비교를 진행하는 == 연산자의 오버로딩
if (str1 == str3){ ... }
==연산자가 객체에 저장된 문자열의 내용을 비교하도록 오버로딩 해야 한다.
6) 콘솔입출력이 가능하도록 <<, >> 연산자의 오버로딩
cout << "문자열 입력: ";
cin >> str4;
이 여섯가지 기능을 모두 완성한 String 클래스를 정의하면, 위 Case 1)의 표준 string 클래스를 대체할 수 있다.
Case 2 )
1) String 클래스 선언부분
class String {
private:
int len;
char* str;
public:
String(); // 생성자
String(const char* s); // 생성자
String(const String& s); //복사 생성자
~String(); // 소멸자
String& operator=(const String& s); // 대입 연산자
String& operator+=(const String& s); // += 연산자
bool operator==(const String& s); // 비교 연산자
String operator+(const String& s); // + 연산자
friend ostream& operator<<(ostream& os, const String& s);
friend istream& operator>>(istream is, String& s);
};
2) String 클래스 정의부분
a. 생성자
String::String() {
len = 0;
str = NULL;
}
b. 생성자 (char *)
String::String(const char*s) {
len = strlen(s) + 1;
// strlen값은 맨 마지막 NULL값을 포함하지 않음. 따라서 +1을 해줌으로서 공백 문자까지 넣을 수 있도록 공간을 마련함
str = new char[len];
strcpy(str, s);
}
* strcpy(a,b) : b문자열을 a에 복사
* strncpy(a,b,n) : b문자열을 a에 n길이만큼 복사
c. 복사 생성자
String::String(const String& s) {
len = s.len; // strlen을 사용한 것이 아니고, s.len값을 대입한 것이므로 +1이 필요 없음
str = new char[len];
strcpy(str, s.str);
/* 깊은 복사 진행 : 기존에 생성된 객체를 이용해 새로운 객체 초기화 (각각 다른 주소값 지님)*/
}
d. 소멸자
String::~String() {
if (str != NULL) { // 맴버변수 str이 NULL이 아니라면
delete[] str; // 맴버변수 str 메모리 해제 진행
}
}
e. 대입연산자
String& String :: operator=(const String& s) {
// 매개변수로 들어오는 객체 s는 값이 변화하면 안되므로, const 붙여주기
if (str != NULL) { // 맴버변수 str에 값이 존재한다면
delete[]str; // 맴버변수 str 메모리 해제 진행
}
len = s.len;
str = new char[len];
strcpy(str, s.str);
return *this; //대입연산자의 반환형은 참조형 (객체를 반환)
}
f. += 연산자
String& String :: operator+=(const String& s) {
len += (s.len - 1); // 맴버변수 len에는 NULL값이 포함되어 있음. (그런데 +=로 인해 2번 포함되어 -1해주는 것)
char* tempstr = new char[len];
strcpy(tempstr, str);
strcat(tempstr, s.str);
if (str != NULL) { // 만약 맴버변수 str에 값이 존재한다면
delete[]str; // 맴버변수 str 메모리 해제 진행
}
str = tempstr; // tempstr값을, str에 넣어라
return *this; // 참조형 (객체 자기 자신) 반환
}
* strcat(a,b) : a 뒤에 b를 붙여라
g. 비교 연산자
bool String :: operator==(const String& s) {
return strcmp(str, s.str) ? false : true;
}
* strcmp(s1,s2) : 두 문자열이 같으면 0 반환, ASCII코드 기준으로 s1<s2이면 -1 반환, s1>s2이면 1 반환
* A ? B : C -> A가 참이면, B를 리턴 거짓이면 C를 리턴한다.
// strcmp(str,s.str)가 같으면 0 반환 -> 0=거짓 -> true 리턴
// strcmp(str,s.str)가 같지 않으면 다른 값 반환 -> 참 -> false 리턴
h. + 연산자
String String :: operator+(const String& s) {
char* tempstr = new char[len + s.len - 1];
strcpy(tempstr, str);
strcat(tempstr, s.str);
String temp(tempstr);
delete[]tempstr;
return temp;
}
i. <<연산자, >>연산자
ostream& operator<<(ostream & os, const String& s) {
os << s.str;
return os;
}
istream& operator>>(istream& is, String& s) {
char str[100];
is >> str;
s = String(str);
return is;
}
3) Main 함수 부분
int main() {
string str1 = "I like ";
string str2 = "string class";
string str3 = str1 + str2;
cout << str1 << endl;
cout << str2 << endl;
cout << str3 << endl;
str1 += str2;
if (str1 == str3) {
cout << "동일 문자열!" << endl;
}
else
cout << "동일하지 않은 문자열! " << endl;
string str4;
cout << "문자열 입력: ";
cin >> str4;
cout << "입력한 문자열 : " << str4 << endl;
return 0;
}
* 유의사항 - 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다. - 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다. - 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :) |