String Class Operator Overloading
: String Class에 연산자를 오버로딩해보자<<
<<
1. Operator Overloading이란?
연산자를 중복정의하는 것을 의미한다
① 사용자가 정의한 Type에 연산자를 새로 정의할 수 있다
② Operator 오버로딩 시, 읽기 쉬운 코드가 되는 것을 지향해야 한다
③ Function Overloading과 유사하다
④ 연산자 중복정의는 아래 2가지 방법으로 가능하다
- 멤버함수로 정의
- friend를 이용한 외부함수 정의
※ 예시코드
① 복소수 Class Complex 정의 시, operator+와 operator- 를 overloading
class Complex //복소수 a + bi
{
private :
double m_real, m_imag;
public :
Complex() { m_real = m_imag = 0.0; }
//멤버함수로 정의: Complex c 앞에 this가 숨겨져 있다
//Complex operator+(this, Complex c);
Complex operator+(Complex c);
//friend로 정의: Complex Class 외부의 함수도 접근 가능하게 한다
friend Complex operator-(Complex c1, Complex c2);
};
※ this 포인터?
① 객체자신을 가리키는 포인터이다
② 모든 멤버함수들의 숨겨진 인자를 의미한다 (단, static 멤버함수는 제외)
※ friend ?
클래스 외부의 함수이더라도, 클래스의 멤버에 접근 가능하도록 한다
② operator+와 operator- 를 overloading 하는 코드 정의 작성
Complex Complex::operator+(Complex c)//operator+가 Complex의 멤버함수라는 의미
{
Complex c3;
c3.m_real = m_real + c.m_real;
c3.m_imag = m_imag + c.m_imag;
return c3;
}
Complex operator-(Complex c1, Complex c2) //operator-가 외부함수라는 의미
{
Complex c3;
c3.m_real = c1.m_real - c2.m_real;//Complex 클래스의 멤버에 접근 가능
c3.m_imag = c1.m_imag - c2.m_imag;
return c3;
}
③ main 코드 작성
int main() {
Complex c1, c2, c3;
c3 = c1 + c2; //c3 = c1.operator+( c2);
c3 = c1 - c2; //c3 = operator-(c1,c2);
}
2. Copy Constructor vs Assignment
복제 생성자와 할당, 이 둘에 대한 정의 구분이 왜 필요할까? 그 이유는 바로 어떤 것을 복사한다는 copy라는 행위 자체가 단순히 값을 복사하기 위한 shallow copy와 주소 메모리까지 새롭게 할당하는 deep copy 두 가지로 이루어져 있기 때문이다.
- Copy Constructor (deep copy): 초기상태에서 시작한다
String str1("String1");
String str2 = str1;
- Assignment (shallow copy): 기존 데이터를 지운 후 새로운 값을 할당시킨다
String str1("Test String");
String str2;
str2 = str1;
3. 연산자의 우선순위와 결합순서
① 연산자 우선순위 (Precedence): 서로 다른 연산자들 중 어떤 연산자를 우선으로 연산할까?
② 결합순서
- 동일한 연산자가 여러 항 사용될 경우 어떤 연산자부터 결합되
- 할당 연산자는 ← 방향이며, 그 외 대부분의 연산자는 → 방향이다
//operator+, → 방향
str = String("aaa") + "bbb" + "ccc";
//operator=, ← 방향
str1 = str2 = str3 = str4;
③ 연산자별 우선순위 및 결합순서 참고
4. 두 Type 간의 상호변환
① 두 Type 모두 User Defined Class인 경우: 상호간의 Class Type을 인자로 하는 생성자가 필요하다
A::A(B); //Class B를 인자로 하는 A 생성자 필요
B::B(A); //Class A를 인자로 하는 B 생성자 필요
② 한 Type은 Class, 다른 Type은 Primitive Data Type인 경우
//String Class에 Primitive Data Type인 char형을 인자로 하는 생성자
String::String(const char*);
//String 연산자 operator에 char형을 인자로 받기
String::operator const char*();
//사용예시
str2 = (const char*)str1;
자 이제 마지막으로, String Class에 각종 연산자들을 overloading하는 코드들을 추가해보자
① String Class 정의에 =, +=, +, << 연산자 Overloading 원형 추가
class String
{
protected:
int len;
char* m_pBuffer; //string 버퍼
void _Init();
void _Clear();
void _Copy(const char* lpsz);
public:
//constructors,destructor
String(); //default constructor
String(const String&); //copy constructor
String(char*);
String(const char*);
String(char);
String(long);
String(int);
String(double);
~String();
//operators
const String& operator=(const String&);
const String& operator+=(const String&);
String operator+(const String&);
friend ostream& operator<<(ostream&, const String&);
//other member functions: 추후 추가 예정
};
② String Class의 함수 정의 부분에 operator 연산자들을 overloading하기 위한 코드들을 추가
//(추가) operator 연산자 Overloading
const String& String::operator=(const String& stringSrc)
{
_Clear();
len = stringSrc.len;
_Copy(stringSrc.m_pBuffer);
return *this;
}
const String& String::operator+=(const String& stringSrc)
{
len = len + stringSrc.len - 1;
char* ctemp = new char[len];
strcpy(ctemp, m_pBuffer);
strcat(ctemp, stringSrc.m_pBuffer);
if (m_pBuffer != NULL)
{
delete[]m_pBuffer;
}
m_pBuffer = ctemp;
return *this;
}
String String::operator+(const String& stringSrc)
{
char* temp= new char[len + stringSrc.len - 1];
strcpy(temp, m_pBuffer);
strcat(temp, stringSrc.m_pBuffer);
String stemp(temp);
delete[] temp;
return stemp;
}
ostream& operator<<(ostream& os, const String& stringSrc)
{
os << stringSrc.m_pBuffer << endl;
return os;
}
//(기존) 생성자,파괴자
String::String() {
_Init();
}
String::String(const String& stringSrc) {
_Init();
len = strlen(stringSrc.m_pBuffer);
_Copy(stringSrc.m_pBuffer);
}
String::String(const char* lpsz) {
_Init();
len = strlen(lpsz) + 1;
_Copy(lpsz);
}
String::String(char* lpsz) {
_Init();
len = strlen(lpsz) + 1;
_Copy(lpsz);
}
String::String(char ch) {
char str[2];
str[0] = ch;
str[1] = '\0';
_Init();
len = 2;
_Copy(str);
}
String::String(long l) {
_Init();
char num_char[10 + sizeof(char)];
sprintf(num_char, "%d", l);
len = strlen(num_char);
_Copy(num_char);
}
String::String(int i) {
_Init();
char num_char[10 + sizeof(char)];
sprintf(num_char, "%d", i);
len = strlen(num_char);
_Copy(num_char);
}
String::String(double d) {
_Init();
char num_char[10 + sizeof(char)];
sprintf(num_char, "%d", (int)d);
len = strlen(num_char);
_Copy(num_char);
}
String::~String() {
_Clear();
}
//(기존) void 함수
void String::_Init() {
len = 0;
m_pBuffer = 0;
}
void String::_Clear() {
if (m_pBuffer)//m_pBuffer != 0 일 때
delete[] m_pBuffer;
_Init();
}
void String::_Copy(const char* lpsz) {
if (lpsz != 0) {
m_pBuffer = new char[strlen(lpsz) + 1];//null이 저장되는 공간 +1 추가
if (m_pBuffer)
strcpy(m_pBuffer, lpsz);
}
}
③ main 코드 작성
int main() {
//Constructor
String str1; //default Constructor
String str2("I can do"); //Constructor
String str3(" it!!"); //Constructor
String str4('A'); //Constructor
String str5 = str4; //Copy Constructor
String str6(156); //Constructor
String str7(1.1); //Constructor
//cout << str1;
cout << str2;
cout << str3;
cout << str4;
cout << str5;
cout << str6;
cout << str7;
String str8 = str2 + str3;
cout << str8;
String str9("I knew");
str9 += str3;
cout << str9;
}
출력 결과
※ 해당 게시글은 개인 학습의 목적으로, 아래 강의를 수강한 후 정리한 학습노트입니다.
'C++ 프로그래밍 > 자료구조와 알고리즘' 카테고리의 다른 글
[자료구조와 알고리즘] 배열과 미로탐색 (0) | 2024.03.02 |
---|---|
[자료구조와 알고리즘] String Class 사용법 (0) | 2024.03.01 |
[자료구조와 알고리즘] String Class 생성자와 제거자 (0) | 2024.02.26 |
[자료구조와 알고리즘] String Class 디자인 (0) | 2024.02.25 |
[자료구조와 알고리즘] String Class (0) | 2024.02.24 |