본문 바로가기

문과 코린이의, [C. C++] 기록/C++ 이론

[문과 코린이의 IT 기록장] C,C++ - String 클래스의 디자인(C++ 표준과 표준 string 클래스, 문자열 처리 클래스의 정의)

반응형

[문과 코린이의 IT 기록장] C,C++ - String 클래스의 디자인(C++ 표준과 표준 string 클래스, 문자열 처리 클래스의 정의)

[문과 코린이의 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길이만큼 복사

 

[문과 코린이의 IT 기록장] C,C++ - 클래스, 생성자( 클래스에 대한 이해, 생성자, 매개변수에 따른

[문과 코린이의 IT 기록장] C,C++ - 클래스, 생성자 ( 클래스에 대한 이해, 생성자, 매개변수에 따른 생성자 오버로딩, 이니셜라이저(:) 이용, 소멸자 )  1. 클래스에 대한 이해 ex ) cf )..

vansoft1215.tistory.com

 

 

 c. 복사 생성자

String::String(const String& s) { 
	len = s.len; // strlen을 사용한 것이 아니고, s.len값을 대입한 것이므로 +1이 필요 없음
	str = new char[len];
	strcpy(str, s.str);
	/* 깊은 복사 진행 : 기존에 생성된 객체를 이용해 새로운 객체 초기화 (각각 다른 주소값 지님)*/
}
 

[문과 코린이의 IT 기록장] C,C++ - 복사생성자( 복사생성자란?, 얕은 복사 vs 깊은 복사 )

 [문과 코린이의 IT 기록장] C,C++ - 복사생성자( 복사생성자란?, 얕은 복사 vs 깊은 복사 )  1. 복사생성자란? 1) 복사생성자 형태 : 클래스이름 (const 클래스 이름 &참조변수){ } ex) SoSimple..

vansoft1215.tistory.com

 

 

 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; //대입연산자의 반환형은 참조형 (객체를 반환)
}
 

[문과 코린이의 IT 기록장] C,C++ - 연산자 오버로딩 3 : 대입연산자 (대입연산자, 디폴트 대입 연산

[문과 코린이의 IT 기록장] C,C++ - 연산자 오버로딩 3 : 대입연산자 (대입연산자, 디폴트 대입 연산자의 문제점,  상속 구조에서의 대입 연산자 호출, 이니셜라이저)  1. 대입연산자

vansoft1215.tistory.com

 

 

 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;
}

* 유의사항
- 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다.
- 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다.
- 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :)
반응형