삶의 공유

[C++][Study] 내가 만드는 문자열 클래스(연산자오버로딩, 복사생성자) 본문

Programing/C++

[C++][Study] 내가 만드는 문자열 클래스(연산자오버로딩, 복사생성자)

dkrehd 2021. 12. 25. 17:15
728x90
반응형

우리가 만든 MyString 문자열 클래스에 == 연산자 오버로딩하여 문자열 비교 기능을 추가해보자

 

연산자 오버로딩이란?

 

+, -, ==, [ ]와 같은 기본적으로 정의되어 있는 연산자 들을 우리의 입맛에 맞게 변형해서 사용할 수 있는것을 의미

 

operator 연산자 기본 구조는 다음과 같다.

 

 "(리턴타입) operator (연산자)(연산자가 받는인자)"

 

 

변수 정의

1) char* string_content :  문자열 데이터를 가르키는 포인터
2) int string_length : 문자열 길이
3) int memory_capacity : 현재 할당된 용량

char* string_content;
int string_length;
int memory_capacity;

 

생성자 소멸자 정의

1) 'a', 'b' 이런 1개의 문자가 입력 되었을 때의 반응하는? 생성자이다.

    즉, MyString('a') 와 같이 입력이 되면 이 생성자가 동작을 하게 된다.

MyString::MyString(char c){
    string_content = new char[1];
    string_content[0] = c;
    memory_capacity = 1;
    string_length = 1;
}

 string_content의 포인터 변수에 동적 할당을 하여 메모리 공간을 가르키게 한다.

※new 키워드를 사용하여 동적으로 할당을 하게 되면 객체를 동적으로 생성하면서, 동시에 자동으로 생성자까지 호출해준다는 점!

 

그리고 그 변수 주소의 값에 c를 대입한다.

string_content = new char[1];
string_content[0] = c;

2)  "abc", "hello" 와 같은 문자열 이 입력이 되었을 때 동작하는 생성자 이다.

     즉, MyString("abc")와 같이 입력이 되면 이 생성자가 동작을 하게 된다.

     인자만 포인터 변수로 받았을 뿐 문자만 입력 받는 생성자(1)와 동일하다.

MyString::MyString(const char* str){
    string_length = strlen(str); // c 함수
    memory_capacity = string_length;
    string_content = new char[string_length];
    for(int i = 0; i!= string_length; i++) 
        string_content[i] = str[i];
}

C 함수의 strlen함수를 써서 함수 인자 str의 길이에 대한 값을 리턴 받아 string_length변수에 대입한다.

그리고 그 크기 만큼 string_content 포인터 변수에 동적 할당을 한다.

string_length = strlen(str); // c 함수
memory_capacity = string_length;
string_content = new char[string_length];

 

3) 다음은 복사 생성자 이다.

 복사 생성자는 표준 적인 정의라고 볼 수 있다.

 기본적인 구조는 다음과 같다.

 

T(const T& a);

호출 방법은 다음과 같은데  

  - MyString str2(str1);

  - MyString str2 = str1;

과 같이 할 경우 복사 생성자가 호출 되게 된다.

MyString::MyString(const MyString& str){
    string_length = str.string_length;
    string_content = new char[string_length];
    for(int i =0; i!=string_length; i++)
        string_content[i] = str.string_content[i];
}

 

여기서 중요한 점은 복사생성자 인자를 const 레퍼런스로 받았다는 점이다 ! 이 말은 이 인자의 값 자체는 변경할 수 가 없다는 뜻 !

 

4) 소멸자

  생성자들을 통해서 동적할당되어 메모리를 차지하고 있는  포인터 변수들을 해제 해준다.

MyString::~MyString() { delete[] string_content; }

 

operator연산자와 compare 함수

 

나머지 함수들은 그리 어려운 부분이 없으니 바로 operator 연산자와 이것을 동작하게 해주는 compare함수만 다뤄보자

 

먼저 compare 함수 이다.

동작하는 방식은 다음과 같다.

현재 객체의 문자열 - 함수 인자의 문자열을 수행해서 1, 0, -1로 그 결과를 반환 한다는 의미이다.
  : 1은 현재 객체의 문자열이 사전적으로 더 뒤에 온다는 의미

  : 0은 두 문자열이 같다는 의미

  : -1은 현재객체의 문자열이 사전적으로 더 앞에 온다는 의미

 

이것을 코드로 나타내면 다음과 같다

int MyString::compare(MyString& str){
    // (*this) - (str) 을 수행해서 1,0,-1로 그 결과를 리턴한다
    // 1은 (*this)가 사전적으로 더 뒤에 온다는 의미, 0은 두 문자열이 같다는 의미
    // -1은 (*this)가 사전식으로 더 앞에 온다는 의미
    for(int i = 0; i < std::min(string_length, str.string_length); i++){
        if(string_content[i] > str.string_content[i])
            return 1;
        else if (string_content[i] < str.string_content[i])
            return -1;
    }
    if(string_length == str.string_length) return 0;
    // abc vs abcd의 크기 비교는 abcd가 더 뒤에 오게 된다.
    else if (string_length > str.string_length)
        return 1;
    return -1;
}

먼저, for문을 이용해서 string_content와, str.string_content 포인터 변수의 문자열에 접근하다.

for(int i = 0; i < std::min(string_length, str.string_length); i++)

그리고 이렇게 문를 비교하여 사전적으로 어느 객체(현재객체 vs 인자)가 사전적으로 더 앞인지 뒤인지를 비교한다.

if(string_content[i] > str.string_content[i])
	return 1;
else if (string_content[i] < str.string_content[i])
	return -1;

 

여기까지 동일하면 이제 문자열 길이를 통해서 사전적으로 더 앞인지 뒤인지 구분한다.

즉, "abc" vs "abcd" 는 사전적으로 "abcd"가 뒤라는 의미 이다!

문자열이 같으면 이 2개의 문자는 같다는 뜻이다.

if(string_length == str.string_length) return 0;
else if (string_length > str.string_length)
	return 1;
return -1;

자 이제 operator연산자 오버로딩을 이용할 차례이다.

자 함수의 리턴형태는 true, false로 리턴할 것이기 때문에 bool 형태로 정했다. 인자를 그대로 compare함수에 넘겨주기만 하면 된다!

bool MyString::operator==(MyString& str){
    return !compare(str); // str과 같으면 comapre에서 0을 리턴한다
}

이렇게 정의한 것들을 어떻게 활용하는지 살펴보면 다음과 같다. 

== 연산자를 이용하여 compare함수에 str인자를 넣어주어 호출하였다. 그리고 그 결과가 아래처럼 잘 나오는 것을 볼 수 있다.

int main()
{
    MyString str1("a word");
    MyString str2("sentence");
    MyString str3("sentence");
    
    if (str1 == str2)
        std::cout << "str1와 str2는 같다" << std::endl;
    else
        std::cout << "str1와 str2는 다르다" << std::endl;
        
    if (str2 == str3)
        std::cout << "str2와 str3는 같다" << std::endl;
    else
        std::cout << "str2와 str3는 다르다" << std::endl;
    return 0;
}

결과)

자 이렇게 우리가 만든 문자열 클래스를 이용하여 복사 생성자, 생성자에 대한 복습과 새로 나온 개념에 대한 operator 연산자 오버로딩에 대해서도 학습했다. 

 

앞으로 C++ 학습의 길은 멀고도 험하지만, 차근차근히 해내보자! 뭐든지 꾸준함이 제일 중요하니...

 

[reference] 

https://modoocode.com/

반응형