2025. 5. 2. 12:32ㆍProgramming Language/C++
비교 관계 연산자 오버로딩은 C++에서 객체끼리 ==, <, >, !=, <=, >= 같은 비교 연산을 직접 정의할 수 있도록 해주는 기능으로 객체 간의 정렬, 비교, 검색 등에 매우 중요하게 사용된다.
우리가 해보고자 하는건 std::string의 기능을 따라 만들어보고자 한다.
std:string에서는 객체간의 비교연산이 가능했었다.
이 기능을 한번 만들어보고자 한다.
우선 이 기능을 만들기 위해서는 C언어의 기능을 가져와서 사용하기 위해서 cstring과 보안이슈를 위한 pragma warning을 추가해주자.
그리고 class String을 하나 생성해주고 멤버 변수로는 생성자를 통해 초기화 하는 크기에 맞게 문자열을 넣어주기 위해서 char형 포인터를 만들어주자.
그리고 생성자를 추가해주는데 이 생성자에서는 const char * 타입을 받아주는데(리터럴로 오는 경우 const 이며, 이 값은 읽기만 해야하기 때문임)
생성자 이니셜라이져 리스트에서는 값 자체를 바로 넣어줄수는 없고 동적할당을 통해서 초기화하려는 문자열의 크기 + 1만큼의 공간의 할당만 가능하다.
그리고 실제 값의 저장은 strcpy를 사용해서 넣어줘야 한다.
그리고 이 값을 print라는 함수를 하나 선언해서 출력해보자.
이제 비교연산에 대해서 한번 구현해보도록 하자.
우리가 구현해보고자 하는 비교 연산은 ==, !=, <, >, <=, >=, <=> 이다.
그럼 각각의 연산의 결과는 true/false이기에 해당 연산자 오버로딩 함수의 반환값은 bool형이 될것이다.
이제 각각의 연산자 오버로딩을 한번 해보자.
1. == 연산자
== 연산자의 경우는 같은 String 타입의 객체를 받아 내부에서 비교한 후에 그 값을 반환해준다.
먼저 기본적인 형태는 반환타입 bool에 연산자 ==에 대해서 함수를 생성하고 매개변수는 동일한 타입인 const String&의 형태로 const 함수가 될것이다.
그리고 내부에서는 cstring의 함수인 strcmp를 사용해서 현재 클래스 내부의 m_chars와 매개변수로 전달된 s의 m_chars의 비교를 진행한다.
strcmp함수의 경우는 두 값이 완전히 같을때 0을, 첫번째 값이 두번째 값보다 크면(각 글자별로 사전순으로 크다면) 0보다 큰값을, 그 반대라면 0보다 작은 값을 반환한다.
우리는 ==, 동일한 상태를 확인하기에 그 값이 0 일 경우에 대한 비교연산의 결과를 반환하면 된다.
이걸 이제 사용해보면
이렇게 비교연산이 되는 것을 볼 수 있다.
값을 조금 바꿔서 동일하지 않을 경우에 대해서도 한번 출력해보면
이렇게 정확하게 연산을 하는 것을 볼 수 있다.
2) != 연산자
위 연산의 형태를 비슷하게 가져와 strcmp의 결과가 0이 아닐 경우에 대한 비교 연산의 결과를 반환하면 된다.
추가로 위에 있는 == 연산자를 그대로 사용하는 것도 가능하다.
이것도 한번 사용해보면
이렇게 연산을 진행 하는 것을 볼 수 있다.
물론 그 반대의 경우도
이렇게 잘 확인하는 것을 볼 수 있다.
3) <, > 연산자
이 또한 위 방법을 그대로 사용하면 된다.
작은 경우는 strcmp가 0보다 작은 경우로 구현하면 된다
큰 경우는 strcmp가 0보다 큰 경우로 구현하면 된다
> 경우는 먼저 만들어져 있는 < 연산자가 있기에 그걸 활용하는 것은 불가능하다 그 이유는 < 연산의 반대는 = 연산도 포함되기 때문이다.
4) <=, >= 연산자
그러면 위의 > 연산의 반대의 경우는 <=이고
< 연산의 반대는 >= 연산이니 그걸 그대로 사용하면 된다.
5) <=> 연산자.
operator<=>는 C++20에 도입된 새로운 비교 연산자로, 일명 우주선 연산자 또는 삼항 비교 연산자(three-way comparison)라고 불린다.
그래서 먼저 이 연산자를 사용하기 위해서는 C++ 컴파일러를 최신버전으로 변경해줘야한다.
프로젝트 오른쪽 클릭 > 속성
C++ 언어 표준 > C++20표준 혹은 최신 C++ 초안의 기능을 눌러줘서 컴파일러를 변경해준다
그리고 소스에서 compare라는 모듈을 include해줘야 사용이 가능하다.
우선 <=>연산자는 a <=> b는 두 값을 비교해서 작다, 같다, 크다를 한 번에 판단하게 해주는데 이 반환값은 bool 타입이 아니라 특수한 타입이 반환된다.
반환 타입은 기본 타입 (int, std::string, 사용자 정의 타입 등)에 대한 std::strong_ordering타입, 정렬은 되지만, 동등성과 동일성이 다를 수 있다는 의미의 std::weak_ordering타입, NaN 등 비교 불가능한 값도 있을 수 있다는 의미의(예: float) std::partial_ordering타입으로 나뉜다.
대부분에서는 그냥 std::strong_ordering을 사용하면 된다.
그래서 연산의 결과에 따른 실 내용은 a <=> b의 결과가 std::strong_ordering::less일 경우 a < b인거고 a <=> b의 결과가 std::strong_ordering::equal라면 a == b 인거고 a <=> b의 결과가 std::strong_ordering::greater라면 a > b인 것이다.
우리가 클래스 내부에서 <=> 연산자 오버로딩 함수를 만들때에는 반환 타입을 strong_ordering으로 반환하면 된다.
그리고 여기서 strcmp를 사용할 것인데 그냥 사실 구현 방식은 단순하게 if-elseif 구문을 사용해서 분기로 값을 less, equal, greater로 분기쳐서 보내주면 된다.
이걸 비교하는 것도 그냥 0이랑 비교 연산해주면 된다.
주의점
여기서 추가적으로 객체 == 상수의 비교를 한번 확인해보면
이건 우리가 따로 정의하지 않았는데도 불구하고 컴파일에서 문제가 없는것을 볼 수 있는데
디버깅해보면
이렇게 b에서 생성자를 타고 String 객체로 만드는 것을 볼 수 있다
이는 암묵적으로 "b"라는 값을 String 타입으로 만들어 비교연산을 진행하는 것으로 더 디버깅을 진행해보면
이 연산으로 들어오는 것을 볼 수 있다.
그래서 사실 생성자에 explicit 키워드를 붙여주면(추후 배울 내용이라 인지만 하고 넘어가자)
이렇게 이제는 받아줄 수없다고 나오는 것을 볼 수 있다.
그래서 이렇게 암시적 형변환이 안될 경우에는 이것에 맞는 구현을 추가로 해줘야만 한다.
그렇다면 상수 == 객체의 경우는 어떻게 구현해야할까?
이는 조금더 단순하다.
이전에 상수 + 객체 했던것과 비슷하게 상수 == 객체도 같은 방식으로 구현해주면된다.
1. 전역 함수 선언 후 friend로 프로토타입 클래스에 넣어주기
이렇게 전역함수를 하나 선언해주고 클래스 내부에 friend를 붙인 프로토타입을 선언해주면
에러가 사라진것을 볼 수 있다.
실제 비교 연산할때도 문제가 없는 것을 확인할 수 있다.
'Programming Language > C++' 카테고리의 다른 글
Part2::Ch 02. 연산자 오버로딩- 05. 비트 연산자 오버로딩 (0) | 2025.05.02 |
---|---|
Part2::Ch 02. 연산자 오버로딩- 04. 논리 연산자 오버로딩 (0) | 2025.05.02 |
Part2::Ch 02. 연산자 오버로딩- 01&02. 산술 연산자 오버로딩 (0) | 2025.05.02 |
Part2::Ch 01. 클래스 - 09. 멤버 함수 포인터 (0) | 2025.04.29 |
Part2::Ch 01. 클래스 - 08. 정적 멤버 (0) | 2025.04.29 |