한성대학교 김설현교수님 강의내용을 바탕으로 작성함
연산자 오버로딩
정수형, 실수형, 문자형 등의 기본 자료형에 +,-,*,/,++,--등의 연산자를 적용할 수 있다.
하지만 개발자가 만든 자료형에는 이러한 연산자를 사용할 수 없다.
C++에서는 클래스에 함수로 정의한 후 사용할 수 있는데 이를 연산자 오버로딩(재정의)혹은 연산자 함수라고 한다.
문자열에서의 연산자 함수
string s1("Washington");
string s2("California");
cout << "The first character in s1 is " << s1[0] << endl;
cout << "s1 + s2 is " << (s1 + s2) << endl;
cout << "s1 < s2? " << (s1 < s2) << endl;
이렇게 사용해왔던 것들이 실제로는
string s1("Washington");
string s2("California");
cout << "The first character in s1 is " << s1.operator[](0) << endl;
cout << "s1 + s2 is " << operator+(s1, s2) << endl;
cout << "s1 < s2? " << operator<(s1, s2) << endl;
이렇게 함수로 재정의 되어있다고 생각하면 된다.
연산자 함수
1.오버로딩이 가능한 연산자는 아래와 같다.
+, -, *, /, %, ^, &, |, ~, !, =, <, >, +=, -=, *=, /=, %=, ^=, &=, |=, <<, >>, >>=, <<=, ==, !=, <=, >=, &&, ||, ++, --,
-*&, ,, ->, [], ( ), new, delete
2.C++에는 오버로딩 할 수 없는 4개의 연산자가 있다.
?:, ., .*, ::
3.대부분의 연산자는 멤버 함수나 일반 함수로 작성할 수 있지만, =, ( ), [], ->연산자는 멤버 함수로, << 연산자는 일반 함수로 작성해야 한다.
4.연산자 오버로딩에서 C++의 기존 연산 방법을 바꿀 수 없다.
아래와 같은 클라스가 있다고 하면
Rational.h
#ifndef RATIONAL_H
#define RATIONAL_H
#include <string>
using namespace std;
class Rational
{
public:
Rational();
Rational(int numerator, int denominator);
int getNumerator() const;
int getDenominator() const;
Rational add(const Rational& r2) const;
Rational subtract(const Rational& r2) const;
private:
int numerator; //분자
int denominator; //분모
int gcd(int n, int d); //최대공약수
};
#endif
Rational.cpp
#include "Rational.h"
#include <cstdlib> // for the abs
Rational::Rational()
{
numerator = 0;
denominator = 1;
}
Rational::Rational(int numerator, int denominator)
{
int factor = gcd(numerator, denominator); //최대공약수로 나누어 최저항으로 만듬
this->numerator = ((denominator > 0) ? 1 : -1) * numerator / factor;
this->denominator = abs(denominator) / factor;
}
int Rational::gcd(int n, int d)
{
int n1 = abs(n);
int n2 = abs(d);
int gcd = 1;
for (int k = 1; k <= n1 && k <= n2; k++) {
if (n1 % k == 0 && n2 % k == 0) //분자, 분모 모두 나누어 떨어지는 수
gcd = k; //그 중 가장 큰 수를 찾음
}
return gcd;
}
int Rational::getNumerator() const {
return numerator;
}
int Rational::getDenominator() const {
return denominator;
}
Rational Rational::add(const Rational& r2) const // /𝑏 + 𝑐/𝑑 = (𝑎𝑑+𝑏𝑐)/𝑏𝑑
{
int n = numerator * r2.getDenominator() + denominator * r2.getNumerator();
int d = denominator * r2.getDenominator();
return Rational(n, d);
}
Rational Rational::subtract(const Rational& r2) const //𝑎/𝑏 - 𝑐/𝑑 = (𝑎𝑑−𝑏𝑐)/𝑏𝑑
{
int n = numerator * r2.getDenominator() - denominator * r2.getNumerator();
int d = denominator * r2.getDenominator();
return Rational(n, d);
}
main.cpp
#include <iostream>
#include "Rational.h"
using namespace std;
int main()
{
Rational r1(4, 2);
Rational r2(2, 3);
Rational r3 = r1.add(r2); //연산자 오버로딩이 없기에 r1 + r2불가
Rational r4 = r1.subtract(r2); //마찬가지로 r1 - r2불가
// add() 함수와 subtract() 함수를 테스트 함
cout << "r1 + r2 = " << r3.getNumerator() << "/" << r3.getDenominator() << endl;
cout << "r1 - r2 = " << r4.getNumerator() << "/" << r4.getDenominator() << endl;
return 0;
}
이런식으로 사용할 것이다.
하지만 연산자 오버로딩을 한다면
Rational add(const Rational& r2) const;
Rational Rational::add(const Rational& r2) const // /𝑏 + 𝑐/𝑑 = (𝑎𝑑+𝑏𝑐)/𝑏𝑑
{
int n = numerator * r2.getDenominator() + denominator * r2.getNumerator();
int d = denominator * r2.getDenominator();
return Rational(n, d);
}
위의 함수를
Rational operator+(const Rational& r2) const;
Rational Rational::operator+(const Rational& r2) const //add 함수 그대로
{
int n = numerator * r2.getDenominator() + denominator * r2.getNumerator();
int d = denominator * r2.getDenominator();
return Rational(n, d);
}
이렇게 구현할 수 있다.
연산자 오버로딩을 구현했다면, 아래처럼 사용할 수 있다.
Rational r3 = r1.add(r2);
Rational r3 = r1 + r2; //연산자 오버로딩
그외 <, <=, []등등 도 구현가능하다.
<연산자 오버로딩
bool operator<(const Rational& r1, const Rational& r2);
bool operator<(const Rational& r1, const Rational& r2)
{
Rational temp = r1 – r2;
if (temp.getNumerator() < 0)
return true;
else return false;
}
[]연산자 오버로딩
int operator[](int index);
int Rational::operator[](int index)
{
if (index == 0)
return numerator;
else
return denominator;
}
<<연산자 오버로딩
Ration객체를 화면에 출력하려면 스트림 삽입 연산자(<<)를 오버로딩 하면 된다.
cout << r;
cout << r은 실제로 operator << (cout, r)와 동일하다.
operator << (cout, r);
첫 번째 피연산자가 Ration클래스가 아니라 ostream 클래스의 인스턴스이므로 Rational클래스의 멤버 함수가 아닌 일반 함수로 정의해야 한다.
또한 연속된 수식에서 <<연산자를 사용하려면 ostream의 참조를 반환해야 한다.
cout << r << "followed by" << r2;
Rational.h
friend ostream& operator<<(ostream& out, const Rational& r );
Rational.cpp
ostream& operator<<(ostream& out, const Rational &r)
{
out << r.numerator << "/" << r.denominator;
return out;
}
cout 의 동작 방식
cout << r1 << r2<< r3;
cout << r2 << r3;
cout << r3;
cout; //무시
friend 함수와 friend 클래스
클래스의 private 멤버는 클래스 외부에서 접근할 수 없다.
경우에 따라 외부함수나 클래스가 클래스의 private 멤버에 접근하도록 허용하는 것이 편리할 때가 있다.
C++에서는 friend키워드를 사용한다.
'개발 > C++' 카테고리의 다른 글
C++ 클래스 메모리 할당 정리 (0) | 2021.12.27 |
---|---|
16장 예외처리 (0) | 2021.12.09 |
15장 상속과 다형성 (0) | 2021.12.09 |
13장 파일 입력과 출력 (0) | 2019.05.21 |
12장 템플릿, 벡터, 스택 (0) | 2019.05.13 |
11장 포인터와 동적 메모리 관리(후) (0) | 2019.05.09 |
11장 포인터와 동적 메모리 관리(전) (0) | 2019.05.08 |
10장 객체 지향 개념 (0) | 2019.02.11 |
댓글