C++에서 연산자 오버로딩은 컴파일 타임 다형성입니다. C++에서 원래의 의미를 바꾸지 않고 기존 연산자에 특별한 의미를 부여하려는 아이디어입니다.
이 기사에서는 예제를 통해 C++의 연산자 오버로딩에 대해 자세히 설명하고 C++에서 오버로딩할 수 있는 연산자와 불가능한 연산자를 살펴보겠습니다.
C++ 연산자 오버로딩
C++에는 연산자에 데이터 유형에 대한 특별한 의미를 제공하는 기능이 있으며, 이 기능을 연산자 오버로딩이라고 합니다. 연산자 오버로딩은 컴파일 타임 다형성입니다. 예를 들어, String과 같은 클래스에서 연산자 '+'를 오버로드하여 +만 사용하여 두 문자열을 연결할 수 있습니다. 산술 연산자가 오버로드될 수 있는 다른 예제 클래스로는 복소수, 분수, 큰 정수 등이 있습니다.
예:
int a; float b,sum; sum = a + b;>
여기서 변수 a와 b는 내장 데이터 유형인 int와 float 유형입니다. 따라서 더하기 연산자 '+'는 a와 b의 내용을 쉽게 더할 수 있습니다. 이는 덧셈 연산자 +가 내장 데이터 유형의 변수만 추가하도록 미리 정의되어 있기 때문입니다.
구현:
C++
// C++ Program to Demonstrate the> // working/Logic behind Operator> // Overloading> class> A {> > statements;> };> int> main()> {> > A a1, a2, a3;> > a3 = a1 + a2;> > return> 0;> }> |
안드로이드의 imessage 게임
>
>
이 예에는 클래스 A 유형의 3개 변수 a1, a2 및 a3이 있습니다. 여기서는 + 연산자를 사용하여 사용자 정의 유형, 즉 클래스 A 유형인 두 객체 a1 및 a2를 추가하려고 합니다. 더하기 연산자 +는 내장 데이터 유형에서만 작동하도록 미리 정의되어 있으므로 이는 허용되지 않습니다. 하지만 여기서 클래스 A는 사용자 정의 유형이므로 컴파일러에서 오류가 발생합니다. 여기서 연산자 오버로딩(Operator Overloading)의 개념이 등장합니다.
이제 사용자가 + 연산자가 두 개의 클래스 개체를 추가하도록 하려면 사용자는 두 개의 클래스 개체를 추가하도록 + 연산자의 의미를 재정의해야 합니다. 이는 연산자 오버로딩(Operator Overloading) 개념을 사용하여 수행됩니다. 따라서 연산자 오버로딩의 주요 아이디어는 클래스 변수 또는 클래스 객체와 함께 C++ 연산자를 사용하는 것입니다. 연산자의 의미를 재정의해도 원래 의미는 바뀌지 않습니다. 대신 기존 의미와 함께 추가적인 의미가 부여되었습니다.
C++의 연산자 오버로딩 예
C++
// C++ Program to Demonstrate> // Operator Overloading> #include> using> namespace> std;> class> Complex {> private> :> > int> real, imag;> public> :> > Complex(> int> r = 0,> int> i = 0)> > {> > real = r;> > imag = i;> > }> > // This is automatically called when '+' is used with> > // between two Complex objects> > Complex operator+(Complex> const> & obj)> > {> > Complex res;> > res.real = real + obj.real;> > res.imag = imag + obj.imag;> > return> res;> > }> > void> print() { cout << real <<> ' + i'> << imag <<> '
'> ; }> };> int> main()> {> > Complex c1(10, 5), c2(2, 4);> > Complex c3 = c1 + c2;> > c3.print();> }> |
>
>산출
12 + i9>
연산자 함수와 일반 함수의 차이점
연산자 함수는 일반 함수와 동일합니다. 유일한 차이점은 연산자 함수의 이름은 항상 연산자 키워드 그 뒤에 연산자 기호가 붙고, 해당 연산자가 사용될 때 연산자 함수가 호출됩니다.
예
C++
#include> using> namespace> std;> class> Complex {> private> :> > int> real, imag;> public> :> > Complex(> int> r = 0,> int> i = 0)> > {> > real = r;> > imag = i;> > }> > void> print() { cout << real <<> ' + i'> << imag << endl; }> > // The global operator function is made friend of this> > // class so that it can access private members> > friend> Complex operator+(Complex> const> & c1,> > Complex> const> & c2);> };> Complex operator+(Complex> const> & c1, Complex> const> & c2)> {> > return> Complex(c1.real + c2.real, c1.imag + c2.imag);> }> int> main()> {> > Complex c1(10, 5), c2(2, 4);> > Complex c3> > = c1> > + c2;> // An example call to 'operator+'> > c3.print();> > return> 0;> }> |
>
>산출
12 + i9>
모든 연산자를 오버로드할 수 있나요?
몇 가지를 제외하고 거의 모든 연산자가 오버로드될 수 있습니다. 다음은 오버로드할 수 없는 연산자 목록입니다.
sizeof typeid Scope resolution (::) Class member access operators (.(dot), .* (pointer to member operator)) Ternary or conditional (?:)>
C++에서 오버로드할 수 있는 연산자
우리는 과부하가 걸릴 수 있습니다
단항 연산자 이항 연산자 특수 연산자( [ ], () 등)
하지만 그 중에는 오버로딩이 불가능한 연산자도 있습니다. 그들은
범위 결정 연산자(: 멤버 선택 연산자 *를 통한 멤버 선택
멤버 변수에 대한 포인터
- 조건 연산자(? Sizeof 연산자 sizeof()
오버로드될 수 있는 연산자 | 예 |
---|---|
이진 산술 | +, -, *, /, % |
단항 산술 | +, -, ++, — |
과제 | =, +=,*=, /=,-=, %= |
비트별 | &, | , <> , ~ , ^ |
역참조 | (->) |
동적 메모리 할당, 할당 해제 | 신규, 삭제 |
아래첨자 | [ ] |
함수 호출 | () |
논리적 | &, | |, ! |
관계형 | >, <, = =, = |
위에서 언급한 연산자는 왜 오버로드될 수 없나요?
1. 크기 연산자
피연산자로 입력된 객체 또는 데이터 유형의 크기를 반환합니다. 이는 컴파일러에 의해 평가되며 런타임 중에는 평가될 수 없습니다. 객체 배열에서 포인터의 적절한 증가는 암묵적으로 sizeof 연산자에 따라 달라집니다. 오버로딩을 사용하여 의미를 변경하면 언어의 기본 부분이 붕괴될 수 있습니다.
2. typeid 연산자
이는 포인터나 참조에 의해 참조되는 객체의 실제로 파생된 유형을 복구하는 기능을 CPP 프로그램에 제공합니다. 이 연산자의 핵심은 유형을 고유하게 식별하는 것입니다. 사용자 정의 유형을 다른 유형처럼 '보이게' 하려면 다형성을 사용할 수 있지만 typeid 연산자의 의미는 변경되지 않은 상태로 유지되어야 합니다. 그렇지 않으면 심각한 문제가 발생할 수 있습니다.
3. 범위 결정(::) 연산자
이는 네임스페이스를 지정하여 식별자가 참조하는 컨텍스트를 식별하고 지정하는 데 도움이 됩니다. 런타임 시 완전히 평가되며 값이 아닌 이름에 대해 작동합니다. 범위 확인의 피연산자는 데이터 유형이 있는 메모 표현식이며 CPP에는 오버로드된 경우 이를 캡처하기 위한 구문이 없습니다. 따라서 이 연산자를 오버로드하는 것은 구문상 불가능합니다.
4. 클래스 멤버 접근 연산자(.(dot ), .* (멤버 연산자에 대한 포인터))
클래스 멤버 액세스 연산자의 중요성과 암시적 사용은 다음 예제를 통해 이해할 수 있습니다.
예:
C++
// C++ program to demonstrate operator overloading> // using dot operator> #include> using> namespace> std;> class> ComplexNumber {> private> :> > int> real;> > int> imaginary;> public> :> > ComplexNumber(> int> real,> int> imaginary)> > {> > this> ->진짜 = 진짜;> > this> ->상상의 = 상상의;> > }> > void> print() { cout << real <<> ' + i'> << imaginary; }> > ComplexNumber operator+(ComplexNumber c2)> > {> > ComplexNumber c3(0, 0);> > c3.real => this> ->실제 + c2.real;> > c3.imaginary => this> ->상상의 + c2.imaginary;> > return> c3;> > }> };> int> main()> {> > ComplexNumber c1(3, 5);> > ComplexNumber c2(2, 4);> > ComplexNumber c3 = c1 + c2;> > c3.print();> > return> 0;> }> |
>
>산출
5 + i9>
설명:
문 ComplexNumber c3 = c1 + c2; 내부적으로 ComplexNumber c3 = c1.operator+ (c2)로 변환됩니다. 연산자 함수를 호출하기 위해. 인수 c1은 다음을 사용하여 암시적으로 전달됩니다. '.' 운영자. 다음 명령문에서는 점 연산자를 사용하여 멤버 함수 print에 액세스하고 c3을 인수로 전달합니다.
게다가 이러한 연산자는 값이 아닌 이름에 대해서도 작동하며 이를 오버로드할 수 있는 (구문학적) 규정이 없습니다.
5. 삼항 또는 조건부(?:) 연산자
삼항 또는 조건 연산자는 if-else 문을 간략하게 표현한 것입니다. 연산자에서 참/거짓 표현식은 조건식의 진리값을 기준으로만 평가됩니다.
conditional statement ? expression1 (if statement is TRUE) : expression2 (else)>
정의를 사용하여 ABC라고 하는 클래스의 삼항 연산자를 오버로드하는 함수
ABC operator ?: (bool condition, ABC trueExpr, ABC falseExpr);>
표현식 중 하나만 평가되었다고 보장할 수는 없습니다. 따라서 삼항 연산자는 오버로드될 수 없습니다.
연산자 오버로딩에 대한 중요 사항
1) 연산자 오버로드가 작동하려면 피연산자 중 하나 이상이 사용자 정의 클래스 개체여야 합니다.
2) 할당 연산자: 컴파일러는 모든 클래스에 기본 할당 연산자를 자동으로 생성합니다. 기본 할당 연산자는 오른쪽의 모든 멤버를 왼쪽에 할당하며 대부분의 경우 잘 작동합니다(이 동작은 복사 생성자와 동일합니다). 자세한 내용은 여기를 참조하세요.
3) 변환 연산자: 한 유형을 다른 유형으로 변환하는 데 사용할 수 있는 변환 연산자를 작성할 수도 있습니다.
예:
C++
// C++ Program to Demonstrate the working> // of conversion operator> #include> using> namespace> std;> class> Fraction {> private> :> > int> num, den;> public> :> > Fraction(> int> n,> int> d)> > {> > num = n;> > den = d;> > }> > // Conversion operator: return float value of fraction> > operator> float> ()> const> > {> > return> float> (num) /> float> (den);> > }> };> int> main()> {> > Fraction f(2, 5);> > float> val = f;> > cout << val <<> '
'> ;> > return> 0;> }> |
>
>산출
0.4>
오버로드된 변환 연산자는 멤버 메서드여야 합니다. 다른 연산자는 멤버 메서드이거나 전역 메서드일 수 있습니다.
4) 단일 인수로 호출할 수 있는 모든 생성자는 변환 생성자로 작동합니다. 즉, 생성 중인 클래스에 대한 암시적 변환에도 사용할 수 있습니다.
예:
C++
// C++ program to demonstrate can also be used for implicit> // conversion to the class being constructed> #include> using> namespace> std;> class> Point {> private> :> > int> x, y;> public> :> > Point(> int> i = 0,> int> j = 0)> > {> > x = i;> > y = j;> > }> > void> print()> > {> > cout <<> 'x = '> << x <<> ', y = '> << y <<> '
'> ;> > }> };> int> main()> {> > Point t(20, 20);> > t.print();> > t = 30;> // Member x of t becomes 30> > t.print();> > return> 0;> }> |
>
>
js 온클릭산출
x = 20, y = 20 x = 30, y = 0>
연산자 오버로딩에 관한 퀴즈