logo

C++의 연산자 오버로딩

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>

연산자 오버로딩에 관한 퀴즈