-
[C++] 연산자 다중 정의 (Operator Overloading)프로그래밍/C & C++ 2024. 7. 8. 22:32728x90반응형
연산자 다중 정의 (Operator Overloading)
연산자 다중 정의는 특정 클래스에 대해 기존의 C++ 연산자를 재정의하여, 사용자 정의 타입도 기본 타입처럼 연산할 수 있도록 하는 기능입니다. 이를 통해 코드를 더 직관적이고 가독성 있게 만들 수 있습니다.
주요 규칙
- 새로운 연산자를 정의할 수 없습니다: 기존 연산자만 오버로딩할 수 있으며, 새로운 연산자는 정의할 수 없습니다.
- 기존 연산자의 의미를 변경하지 않습니다: 기존 연산자의 의미를 유지하면서, 클래스에 맞게 동작하도록 합니다.
- 적절한 반환 타입을 지정합니다: 연산의 결과를 반환해야 하며, 반환 타입을 잘 지정해야 합니다.
- 적절한 접근 지정자 사용: 연산자 함수가 클래스 내부 데이터를 다룰 때 필요한 접근 권한을 고려합니다.
MyString
클래스 예제이 예제에서는 문자열을 다루는
MyString
클래스를 정의하고, 다양한 연산자를 오버로딩합니다. 또한, 기존의strcpy
대신strcpy_s
를 사용하여 안전하게 문자열을 복사합니다.MyString
클래스 정의#include <iostream> #include <cstring> class MyString { private: char* str; public: // 기본 생성자 MyString() : str(nullptr) {} // 문자열을 인수로 받는 생성자 MyString(const char* s) { if (s) { size_t length = strlen(s) + 1; str = new char[length]; strcpy_s(str, length, s); } else { str = nullptr; } } // 복사 생성자 MyString(const MyString& other) { if (other.str) { size_t length = strlen(other.str) + 1; str = new char[length]; strcpy_s(str, length, other.str); } else { str = nullptr; } } // 이동 생성자 MyString(MyString&& other) noexcept : str(other.str) { other.str = nullptr; } // 소멸자 ~MyString() { delete[] str; } // 복사 대입 연산자 MyString& operator=(const MyString& other) { if (this != &other) { delete[] str; if (other.str) { size_t length = strlen(other.str) + 1; str = new char[length]; strcpy_s(str, length, other.str); } else { str = nullptr; } } return *this; } // 이동 대입 연산자 MyString& operator=(MyString&& other) noexcept { if (this != &other) { delete[] str; str = other.str; other.str = nullptr; } return *this; } // + 연산자 오버로딩 (문자열 연결) MyString operator+(const MyString& other) const { size_t len1 = str ? strlen(str) : 0; size_t len2 = other.str ? strlen(other.str) : 0; char* result = new char[len1 + len2 + 1]; if (str) strcpy_s(result, len1 + 1, str); if (other.str) strcpy_s(result + len1, len2 + 1, other.str); MyString newString(result); delete[] result; return newString; } // == 연산자 오버로딩 (문자열 비교) bool operator==(const MyString& other) const { if (!str || !other.str) return str == other.str; return strcmp(str, other.str) == 0; } // != 연산자 오버로딩 (문자열 비교) bool operator!=(const MyString& other) const { return !(*this == other); } // << 연산자 오버로딩 (출력) friend std::ostream& operator<<(std::ostream& os, const MyString& s) { if (s.str) os << s.str; return os; } // 문자열 반환 (c_str() 함수) const char* c_str() const { return str; } }; int main() { MyString s1("Hello"); MyString s2("World"); MyString s3 = s1 + " " + s2; // + 연산자 오버로딩 호출 std::cout << "s1: " << s1 << std::endl; // << 연산자 오버로딩 호출 std::cout << "s2: " << s2 << std::endl; // << 연산자 오버로딩 호출 std::cout << "s3: " << s3 << std::endl; // << 연산자 오버로딩 호출 if (s1 == s2) { // == 연산자 오버로딩 호출 std::cout << "s1 and s2 are equal" << std::endl; } else { std::cout << "s1 and s2 are not equal" << std::endl; } if (s1 != s2) { // != 연산자 오버로딩 호출 std::cout << "s1 and s2 are not equal" << std::endl; } else { std::cout << "s1 and s2 are equal" << std::endl; } return 0; }
연산자 오버로딩 설명
+
연산자:- 두
MyString
객체를 연결하여 새로운MyString
객체를 반환합니다. - 두 문자열의 길이를 계산하고, 동적 배열을 할당하여 두 문자열을 복사한 후 연결합니다.
- 두
==
연산자:- 두
MyString
객체가 같은 문자열을 가지고 있는지 비교합니다. - 문자열이 모두 존재할 경우
strcmp
함수를 사용하여 비교합니다.
- 두
!=
연산자:- 두
MyString
객체가 다른 문자열을 가지고 있는지 비교합니다. ==
연산자를 사용하여 결과를 반전시킵니다.
- 두
<<
연산자:MyString
객체를std::ostream
에 출력할 수 있도록 합니다.friend
함수로 선언되어MyString
클래스의 private 멤버에 접근할 수 있습니다.
연산자 오버로딩의 장점
- 가독성 향상: 클래스 객체 간의 연산을 기본 타입처럼 사용할 수 있어 코드가 직관적이고 읽기 쉬워집니다.
- 편의성 제공: 사용자 정의 타입에 대해 익숙한 연산자를 사용할 수 있어 코드 작성이 간편해집니다.
- 일관성 유지: 클래스의 동작을 일관되게 유지할 수 있으며, 다른 개발자가 클래스를 사용할 때도 친숙하게 느낄 수 있습니다.
결론
연산자 다중 정의는 C++의 강력한 기능 중 하나로, 사용자 정의 타입을 더욱 직관적이고 편리하게 사용할 수 있게 합니다. 이를 통해 코드의 가독성과 유지 보수성을 높일 수 있습니다.
MyString
클래스 예제는 문자열을 다루는 클래스에서 다양한 연산자를 오버로딩하여 사용하는 방법을 잘 보여줍니다.728x90반응형'프로그래밍 > C & C++' 카테고리의 다른 글
[C++] History (C++11~20) (3) 2024.07.15 [C++] L-Value & R-Value (0) 2024.07.15 [C++] Explicit (0) 2024.07.08 [C++] 대입연산자 (0) 2024.07.08 [C++] 댕글링 포인터 (Dangling Pointer) (0) 2024.07.07