str3 = str1 + str2;
str4 = str1 + "World";
str5 = "AAA" + str1;
객체 + 객체가 있고, 객체 + 문자열이 있기 때문에 두가지로 만들어줬다.
CMyString operator+(CMyString& _pBuff)
{
char* pTemp = new char[strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1];
strcpy_s(pTemp, strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1, m_pBuff);
strcat_s(pTemp, strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1, _pBuff.m_pBuff);
return CMyString(pTemp);
}
CMyString operator+(char* _rBuff)
{
char* pTemp = new char[strlen(m_pBuff) + strlen(_rBuff) + 1];
strcpy_s(pTemp, strlen(m_pBuff) + strlen(_rBuff) + 1, m_pBuff);
strcat_s(pTemp, strlen(m_pBuff) + strlen(_rBuff) + 1, _rBuff);
return pTemp;
}
strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1
-> 이 부분에서 +1은 null도 포함해야하기 때문
연산자 오버로딩은 좌측 객체의 operator를 호출한다!
문자열 + 객체는 위치가 바꼈기 때문에 교환법칙을 이용해야한다.
-- 교환법칙
연산자 오버로딩을 전역에 구현한다.
* 인자 중 하나는 객체 타입이거나 객체의 레퍼런스 타입이 와야한다!
(레퍼런스를 사용하는 이유 : 복사생성자의 연산을 줄이기 위해)
CMyString operator+(char* _pName, CMyString& _rBuff)
{
char* pTemp5 = new char[strlen(_pName) + strlen(_rBuff.Get_Buff()) + 1];
strcpy_s(pTemp5, strlen(_pName) + strlen(_rBuff.Get_Buff()) + 1, _pName);
strcat_s(pTemp5, strlen(_pName) + strlen(_rBuff.Get_Buff()) + 1, _rBuff.Get_Buff());
return pTemp5;
}
나는 이런식으로 위의 operator+함수와 동일한 방식으로 구현했다.
하지만, 더 간단하게 이렇게 할 수 있다.
CMyString operator+(char * _pName, CMyString & _pBuff)
{
return CMyString(_pName) + _pBuff;
}
임시객체를 이용하여 리턴한다.
(임시객체는 코드라인을 벗어나면 소멸하기 때문에 자주 사용한다.)
이 때, 객체의 위치가 바뀌지 않도록 주의해야한다. 아니면 문자의 위치가 바뀔 수 있음.
(AAAHello가 출력되야하는데 HelloAAA가 출력되는 상황이 생긴다...)
여기서 operator+ 함수만 만들면 안된다. 객체 = 객체 + 객체 이기 때문에 = 연산자도 필요하다!
=연산자 오버로딩을 구현하지 않아서 계속 오류가 생겼었다..
CMyString operator=(const CMyString& _rBuff)
{
m_pBuff = new char[strlen(_rBuff.m_pBuff) + 1];
strcpy_s(m_pBuff, strlen(_rBuff.m_pBuff) + 1, _rBuff.m_pBuff);
return *this;
}
CMyString operator=(char* _rBuff)
{
m_pBuff = new char[strlen(_rBuff) + 1];
strcpy_s(m_pBuff, strlen(_rBuff) + 1, _rBuff);
return *this; // 나 자신이 반환되야하기 때문에 역참조 this 포인터 사용
}
이렇게 코드를 작성했는데 여기에서 동적할당을 하기 전에 객체가 대입 될 예정이니 나 자신(m_pBuff)은 필요없기 때문에 동적할당을 해제해주는 것이 좋다. (null값이 됨!)
객체(나) = 객체(나) + 객체이다. 어쨌든 객체(나)는 값이 변하게된다. 함수가 종료되어도 나는 메모리에서 소멸하지 않아야 해서 반환타입에 레퍼런스!!를 붙여주는 것이 좋다.
-> 연산 속도를 높이기 위해. 내가 소멸되어도(함수가 종료되어도) 복사된 놈은 살아있음, 지역 변수가 반환되면 그냥 반환타입~
여기서 기억해야 할
<<< 복사 생성자의 호출 시점 3가지 >>>
1. 먼저 생성한 객체를 나중에 생성하는 객체의 생성자로 전달하는 경우
2. 함수의 매개 변수로 객체가 전달되는 경우
3. 함수의 반환 타입으로 객체가 반환되는 경우
이제 출력 해보면
이렇게 출력된다.
str1 += str2;
str2 += "World";
str3 = str1;
str4 = "World";
+=연산은 누적 연산이다. 즉, =연산자와 마찬가지로 나 자신이 반환되어야한다. 그래서 반환타입에 레퍼런스를 사용하는게 좋다.
CMyString operator+=(CMyString& _pBuff)
{
strcat_s(m_pBuff, strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1, _pBuff.m_pBuff);
return CMyString(m_pBuff);
}
CMyString operator+=(char* _rBuff)
{
strcat_s(m_pBuff, strlen(m_pBuff) + strlen(_rBuff) + 2, _rBuff);
return CMyString(m_pBuff);
}
여기는 왜 동적할당을 안했었는지 모르겠지만........ 이렇게 코드를 짰었는데 여기도 동적할당을 해줘야한다. (깊은복사)
======> 오류발생!!!!
CMyString& operator+=(CMyString& _pBuff)
{
char* pTemp = new char[strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1];
strcpy_s(pTemp, strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1, m_pBuff);
strcat_s(pTemp, strlen(m_pBuff) + strlen(_pBuff.m_pBuff) + 1, _pBuff.m_pBuff);
return *this;
}
CMyString& operator+=(char* _rBuff)
{
char* pTemp = new char[strlen(m_pBuff) + strlen(_rBuff) + 1];
strcpy_s(pTemp, strlen(m_pBuff) + strlen(_rBuff) + 1, m_pBuff);
strcat_s(pTemp, strlen(m_pBuff) + strlen(_rBuff) + 1, _rBuff);
return *this;
}
=============> 깊은 복사가 되도록 수정했다!!!!
cout << (str1 == str2) << endl;
cout << ("AAA" == str1) << endl;
int operator==(CMyString& _pBuff)
{
if (strcmp(m_pBuff, _pBuff.m_pBuff) == 0)
return 1; //참
return 0; // 거짓
}
이런식으로 코드를 짰지만 간단하게 아래와 같은 방법도 있다.
bool CMyString::operator==(CMyString & _String)
{
return !strcmp(m_pString, _String.m_pString); // 참이면 0 , 거짓이면 0아닌 값 반환
}
bool CMyString::operator==(char * _pStr)
{
return !strcmp(m_pString, _pStr);
}
==연산도 마찬가지로 교환법칙이 필요하다!
int operator==(char* _rBuff, CMyString& _pBuff)
{
if (strcmp(_rBuff, _pBuff.Get_Buff()) == 0)
return 1; //참
return 0; // 거짓
}
bool operator==(char * _pStr, CMyString & _string)
{
return _string == _pStr;
}
==연산은 단순비교이기 때문에 객체의 위치가 바껴도 상관없다!!
이 과정들을 해보니 연산자 오버로딩을 좀 더 이해하게 된듯하다. 하지만 아직은 더 연습이 필요할듯.
string 다른 기능도 구현해봐야지..
'c++ > c++' 카테고리의 다른 글
알고리즘 - for_each (0) | 2021.05.29 |
---|---|
STL - vector container (0) | 2021.05.26 |
STL(Standard Template Library) (0) | 2021.05.23 |
연산자 오버로딩 - string class 구현1 (0) | 2021.05.22 |
const와 포인터 (0) | 2021.05.22 |