10. 연산자오버로딩 연산자오버로딩소개 이항연산자오버로딩 단항연산자의오버로딩 cout, cin, endl 구현 배열인덱스연산자오버로딩 대입연산자오버로딩 Jong Hyuk Park
연산자오버로딩소개 Jong Hyuk Park
연산자오버로딩 (operator overloading) C++ 에서는기존의 C 언어에서제공하고있는연산자에대하여그의미를다시부여하는것을 " 연산자오버로딩 " 또는 " 연산자중복 ( 재정의 )" 라함 연산자오버로딩은기본적으로함수의오버로딩과같이연산자도하나의함수라는개념을사용하여중복정의 중복되는연산자함수는클래스의멤버함수나프렌드함수로정의 함수이름대신에 operator 키워드를사용하고다음에연산자를기술 반환형 operator 연산자 ( 가인수리스트 ); 두가지형태로표현 멤버함수에의한오버로딩 전역함수에의한오버로딩, friend 함수선언 3
연산자오버로딩정의예 class Complex // + 연산자오버로딩 Complex operator +(Complex x); // 멤버함수 // friend Complex operator+(complex x,complex y); // 전역함수 ; Complex a, b, c; c = a + b; // 중복된연산자를사용한복소수덧셈연산표현 복소수형클래스 + 연산자오버로딩정의예 operator + 는함수와같이간주 c = a + b는 c = a.operator + (b); 로기술할수도있음 객체 a 의멤버함수 operator + 를호출하고인수 b 를전달 4
이항연산자오버로딩 Jong Hyuk Park
6 멤버함수연산자오버로딩예 #include <iostream> using std::endl; using std::cout; class Point int x, y; Point(int _x=0, int _y=0) x = _x; y = _y; void ShowPosition(); Point operator+(const Point& p); ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point Point::operator+(const Point& p) Point temp; temp.x = x + p.x; temp.y = y + p.y; return temp; int main(void) Point p1(1, 2); Point p2(2, 1); Point p3=p1+p2; // p3 = p1.operator+(p2); p3.showposition(); #include <iostream> using std::endl; using std::cout; class Point int x, y; Point(int _x=0, int _y=0) : x(_x), y(_y) void ShowPosition(); Point operator+(const Point& p); ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point Point::operator+(const Point& p) Point temp(x+p.x, y+p.y); return temp; int main(void) Point p1(1, 2); Point p2(2, 1); Point p3=p1+p2; // p3 = p1.operator+(p2); p3.showposition();
전역함수연산자오버로딩예 #include <iostream> using std::endl; using std::cout; class Point int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) void ShowPosition(); friend Point operator+(const Point& p1, const Point& p2); ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point operator+(const Point& p1, const Point& p2) Point temp(p1.x+p2.x, p1.y+p2.y); return temp; int main(void) Point p1(1, 2); Point p2(2, 1); Point p3=p1+p2; // p3 = operator+(p1,p2) p3.showposition(); 7
복소수연산예 (1) #include <iostream> using std::endl; using std::cout; class Complex double re, im; Complex(double r, double i) re = r; im = i; Complex() re = 0; im = 0; Complex operator +(const Complex& c); // + 연산자중복 Complex operator -(const Complex& c); // - 연산자중복 void show() cout << re << " + i" << im << '\n'; ; Complex Complex::operator +(const Complex& c) Complex tmp; tmp.re = re + c.re; tmp.im = im + c.im; return tmp; Complex Complex::operator -(const Complex& c) Complex tmp; tmp.re = re - c.re; tmp.im = im - c.im; return tmp; int main() Complex a(1.2,10.6), b(2.3, 5), c(2.0,4.4); Complex sum, dif; sum = a + b; // 연산자함수 + 호출 cout << "a + b = "; sum.show(); dif = a - b; // 연산자함수 - 호출 cout << "a - b = "; dif.show(); sum = a + b + c; // 연산자함수 + 호출 cout << "a + b + c = "; sum.show(); 8
복소수연산예 (2) a + b = 3.5 + i15.6 a - b = -1.1 + i5.6 a + b + c = 5.5 + i20 복소수덧셈, 뺄셈을위해연산자 +, -를중복정의하였다. 각연산자함수가 Complex 형의객체를반환하므로 a + b + c 와같이연속적인연산이가능하다. 각연산자는다음과같이연산자함수를호출한다. a + b => a.operator +(b) a - b => a.operator -(b) a + b + c => a.operator +(b).operator +(c) 9
#include <iostream> using std::endl; using std::cout; 연산자함수의오버로딩예 class Point int x, y; Point(int _x=0, int _y=0) : x(_x), y(_y) void ShowPosition(); Point operator+(const Point& p); // + 연산자 1 Point operator+(const int v); // + 연산자 2 ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; int main(void) Point p1(1, 2); Point p2(2, 1); Point p3=p1+p2; // p3 = p1.operator+(p2); p3.showposition(); Point Point::operator+(const Point& p) Point temp(x+p.x, y+p.y); return temp; Point Point::operator+(const int d) Point temp(x+d, y+d); return temp; 10 Point p4=p1+10; // p4 = p1.operator+(10); // Point p4 = 10 + p1? p4.showposition();
교환법칙적용예 #include <iostream> using std::endl; using std::cout; class Point int x, y; Point(int _x=0, int _y=0) : x(_x), y(_y) void ShowPosition(); Point operator+(const Point& p); // + 연산자 1 Point operator+(const int d); // + 연산자 2 friend Point operator+(const int d, const Point& p); // + 연산자 3 ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point operator+(const int d, const Point& p) return p+d; int main(void) Point p1(1, 2); Point p2(2, 1); Point p3=p1+p2; // p3 = p1.operator+(p2); p3.showposition(); 11 Point Point::operator+(const Point& p) Point temp(x+p.x, y+p.y); return temp; Point Point::operator+(const int d) Point temp(x+d, y+d); return temp; Point p4=p1+10; // p4 = p1.operator+(10); p4.showposition(); Point p5=10+p2; // p4 = operator+(10,p2); p5.showposition();
교환법칙해결하기 12 /* Associative2.cpp */ #include <iostream> using std::endl; using std::cout; class Point private: int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) void ShowPosition(); Point operator+(int val); //operator+ 라는이름의함수 friend Point operator+(int val, const Point& p); ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point Point::operator+(int val) Point temp(x+val, y+val); return temp; Point operator+(int val, Point& p) return p+val; int main(void) Point p1(1, 2); Point p2=p1+3; p2.showposition(); Point p3=3+p2; p3.showposition();
교환법칙해결하기 #include <iostream> using std::endl; using std::cout; class AAA char name[20]; AAA(char* _name) strcpy(name, _name); cout<<name<<" 객체생성 "<<endl; ~AAA() cout<<name<<" 객체소멸 "<<endl; ; int main(void) AAA aaa("aaa Obj"); cout<<"-------- 임시객체생성전 ---------"<<endl; AAA("Temp Obj"); cout<<"-------- 임시객체생성후 ---------"<<endl; aaa object 객체생성 --------임시객체생성전--------- Temp object 객체생성 Temp object 객체생성 --------임시객체생성후--------- aaa object 객체소멸 13
교환법칙해결하기 14 #include <iostream> using std::endl; using std::cout; class Point private: int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) void ShowPosition(); Point operator+(int val); //operator+ 라는이름의함수 friend Point operator+(int val, const Point& p); ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point Point::operator+(int val) //Point temp(x+val, y+val); //return temp; return Point(x+val, y+val); Point operator+(int val, Point& p) return p+val; int main(void) Point p1(1, 2); Point p2=p1+3; p2.showposition(); Point p3=3+p2; p3.showposition();
관계연산자예 15 #include <iostream> using std::endl; using std::cout; class Point int x, y; Point(int _x=0, int _y=0) : x(_x), y(_y) void ShowPosition(); Point operator+(const Point& p); // + 연산자 1 Point operator+(const int v); // + 연산자 2 int operator<(const Point& p); // < 연산자 ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point Point::operator+(const Point& p) Point temp(x+p.x, y+p.y); return temp; Point Point::operator+(const int d) Point temp(x+d, y+d); return temp; Point Point::operator<(const Point& p) return ((x < p.x) && (y < p.y)); int main(void) Point pt(1, 2); if (pt < pt+10) // pt.operator<(pt.operator+(10)) cout << "pt < pt+10\n"; else cout << "pt >= pt+10\n";
단항연산자의오버로딩 Jong Hyuk Park
단항연산자중복 ++, --, ~,! 등과같은단항연산자 (unary operator) 도이항연산자와같이중복정의 멤버함수에의한오버로딩 단항연산자의경우하나의오퍼랜드는연산자함수를정의하는객체가되므로연산자멤버함수의인수가없게됨 전역함수에의한오버로딩 연산자전역함수에하나의오퍼랜드가전달 17
단항연산자예 1 #include <iostream> using std::endl; using std::cout; class Point private: int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) void ShowPosition(); Point& operator++(); friend Point& operator--(point& p); ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; Point& Point::operator++() x++; y++; return *this; Point& operator--(point& p) p.x--; p.y--; return p; int main(void) Point p(1, 2); ++p; //p 의 x, y 값을 1 씩증가. // p.operator++() p.showposition(); //2, 3 --p; //p 의 x, y 값을 1 씩감소. // operator--(p) p.showposition(); //1, 2 ++(++p); // (p.operator++()).operator++() p.showposition(); //3, 4 --(--p); // operator--(operator--(p)) p.showposition(); //1, 2
단항연산자예 2 #include <iostream> using std::endl; using std::cout; class Point int x, y; Point(int _x=0, int _y=0) : x(_x), y(_y) void ShowPosition(); Point operator-(const Point& p); // 이항연산자 - Point operator-(); // 단항연산자 - ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; int main(void) Point p1(3, 8); Point p2(2, 1); Point p3=p1-p2; // p3 = p1.operator-(p2); p3.showposition(); Point p4=-p1; // p4 = p1.operator-(); p4.showposition(); Point Point::operator-(const Point& p) Point temp(x-p.x, y-p.y); return temp; Point Point::operator-() Point temp(-x, -y); return temp; 19
단항연산자의오버로딩 선연산과후연산의구분 ++p p++ p.operator++(); p.operator++(int); --p p.operator--(); p-- p.operator--(int); 20
단항연산자의오버로딩 class Point private: int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) void ShowPosition(); Point& operator++(); Point operator++(int); ; void Point::ShowPosition() cout<<x<<" "<<y<<endl; int main(void) Point p1(1, 2); (p1++).showposition(); p1.showposition(); Point p2(1, 2); (++p2).showposition(); Point& Point::operator++() x++; y++; return *this; Point Point::operator++(int) Point temp(x, y); // Point temp(*this); x++; y++; return temp; 21
cout, cin, endl 구현 Jong Hyuk Park
입출력연산자개요 C++ 의입출력연산자 <<, >> 도연산자오버로딩에의해구현된것 이름영역 std의클래스 ostream, istream 클래스에서정의 미리정의된자료형에대해입출력 입출력연산자 <<, >> 로사용자정의객체에적용하려면아래와같은전역함수 (friend 함수 ) 정의 ostream& operator<<(ostream& os, class ob) return os; istream& operator>>(istream& is, class ob) return is; 23
ostream 구현예 1 #include<stdio.h> namespace mystd //mystd 라는이름공간시작. char* endl="\n"; class ostream // 클래스 ostream 정의 void operator<<(char * str) printf("%s", str); void operator<<(int i) printf("%d", i); void operator<<(double i) printf("%e", i); ; ostream cout; //ostream 객체생성 // mystd 이름공간끝. using mystd::cout; using mystd::endl; int main() cout<<"hello World \n"; // cout.operator<<("hello World \n"); cout<<3.14; cout<<endl; cout<<1; cout<<endl; 24
ostream 구현예 2 #include<stdio.h> namespace mystd //mystd 라는이름공간시작. char* endl="\n"; class ostream // 클래스 ostream 정의 ostream& operator<<(char * str) printf("%s", str); return *this; ostream& operator<<(int i) printf("%d", i); return *this; ostream& operator<<(double i) printf("%e", i); return *this; ; using mystd::cout; using mystd::endl; int main() cout<<"hello World"<<endl<<3.14<<endl; ostream cout; //ostream 객체생성 // mystd 이름공간끝. 25
사용자정의객체출력예 <<, >> 연산자의오버로딩 Point 객체를기반으로하는 <<, >> 입출력연산 cout<<p cout.operator<<(p); // (x) cout<<p operator<<(cout, p); // (o) ostream& operator<<(ostream& os, const Point& p) 26
사용자정의객체출력예 #include <iostream> using std::endl; using std::cout; using std::ostream; class Point private: int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) friend ostream& operator<<(ostream& os, const Point& p); ; ostream& operator<<(ostream& os, const Point& p) os<<"["<<p.x<<", "<<p.y<<"]"<<endl; return os; int main(void) Point p(1, 3); cout<<p; // operator<<(cout, p); 27
배열인덱스연산자오버로딩 Jong Hyuk Park
인덱스연산자 기본자료형데이터저장배열클래스 IdxOverloading1.cpp 객체저장할수있는배열클래스 IdxOverloading2.cpp arr[i] arr.operator[](i); 29
배열클래스예 #include <iostream> using std::endl; using std::cout; const int SIZE=3; // 저장소의크기. class Arr private: int arr[size]; int idx; Arr():idx(0) int GetElem(int i); // 요소를참조하는함수. void SetElem(int i, int elem); // 저장된요소를변경하는함수. void AddElem(int elem); // 배열에데이터저장하는함수. void ShowAllData(); ; int Arr::GetElem(int i) return arr[i]; void Arr::SetElem(int i, int elem) if(idx<=i) cout<<" 존재하지않는요소!"<<endl; return; arr[i]=elem; 30 void Arr::AddElem(int elem) if(idx>=size) cout<<" 용량초과!"<<endl; return ; arr[idx++]=elem; void Arr::ShowAllData() for(int i=0; i<idx; i++) cout<<"arr["<<i<<"]="<<arr[i]<<endl; int main(void) Arr arr; arr.addelem(1); arr.addelem(2); arr.addelem(3); arr.showalldata(); // 개별요소접근및변경 arr.setelem(0, 10); arr.setelem(1, 20); arr.setelem(2, 30); cout<<arr.getelem(0)<<endl; cout<<arr.getelem(1)<<endl; cout<<arr.getelem(2)<<endl;
배열인덱스연산자오버로딩예 #include <iostream> using std::endl; using std::cout; const int SIZE=3; // 저장소의크기. class Arr private: int arr[size]; int idx; Arr():idx(0) int GetElem(int i); // 요소를참조하는함수. void SetElem(int i, int elem); // 저장된요소를변경하는함수. void AddElem(int elem); // 배열에데이터저장하는함수. void ShowAllData(); int& operator[](int i); // 배열요소에접근 ; int Arr::GetElem(int i) return arr[i]; int& Arr::operator[](int i) return arr[i]; void Arr::SetElem(int i, int elem) if(idx<=i) cout<<" 존재하지않는요소!"<<endl; return; arr[i]=elem; 31 void Arr::AddElem(int elem) if(idx>=size) cout<<" 용량초과!"<<endl; return ; arr[idx++]=elem; void Arr::ShowAllData() for(int i=0; i<idx; i++) cout<<"arr["<<i<<"]="<<arr[i]<<endl; int main(void) Arr arr; arr.addelem(1); arr.addelem(2); arr.addelem(3); arr.showalldata(); // 개별요소접근및변경 arr[0]=10; // arr.operator[](0); arr[1]=20; arr[2]=30; cout<<arr[0]<<endl; cout<<arr[1]<<endl; cout<<arr[2]<<endl;
사용자정의객체저장배열예 (1) #include <iostream> using std::endl; using std::cout; using std::ostream; /***************** Point Class **************************/ class Point private: int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) friend ostream& operator<<(ostream& os, const Point& p); ; ostream& operator<<(ostream& os, const Point& p) os<<"["<<p.x<<", "<<p.y<<"]"; return os; /***************** PointArr Class **************************/ const int SIZE=5; // 저장소의크기. class PointArr private: Point arr[size]; int idx; 32 PointArr():idx(0) void AddElem(const Point& elem); void ShowAllData(); Point& operator[](int i); // 배열요소에접근. ; void PointArr::AddElem(const Point& elem) if(idx>=size) cout<<" 용량초과!"<<endl; return ; arr[idx++]=elem; void PointArr::ShowAllData() for(int i=0; i<idx; i++) cout<<"arr["<<i<<"]="<<arr[i]<<endl; Point& PointArr::operator[](int i) return arr[i];
사용자정의객체저장배열예 (2) int main(void) PointArr arr; arr.addelem(point(1, 1)); arr.addelem(point(2, 2)); arr.addelem(point(3, 3)); arr.showalldata(); // 개별요소접근및변경 arr[0]=point(10, 10); arr[1]=point(20, 20); arr[2]=point(30, 30); cout<<arr[0]<<endl; cout<<arr[1]<<endl; cout<<arr[2]<<endl; 33
대입연산자오버로딩 Jong Hyuk Park
디폴트대입연산자 클래스정의시기본적으로 ( 디폴트로 ) '=' 대입연산자제공 멤버대벰버복사 디폴트대입연산자는디폴트복사생성자와유사 기본적으로는얕은복사 (shallow copy) 포인터멤버변수를갖는소멸자호출시문제발생가능성 깊은복사 (deep copy) 로문제해결 35
디폴트대입연산자예 #include <iostream> using std::endl; using std::cout; using std::ostream; class Point private: int x, y; Point(int _x=0, int _y=0):x(_x), y(_y) friend ostream& operator<<(ostream& os, const Point& p); ; ostream& operator<<(ostream& os, const Point& p) os<<"["<<p.x<<", "<<p.y<<"]"; return os; int main(void) Point p1(1, 3); Point p2(10, 30); cout<<p1<<endl; cout<<p2<<endl; Point& Point::operator=(const Point& p) x=p.x; y=p.y; return *this; 36 p1=p2; // p1.operator=(p2) cout<<p1<<endl;
디폴트대입연산자예 : 얕은복사 (1) #include <iostream> using std::endl; using std::cout; using std::ostream; class Person private: char* name; Person(char* _name); Person(const Person& p); ~Person(); friend ostream& operator<<(ostream& os, const Person& p); ; Person::Person(char* _name) name= new char[strlen(_name)+1]; strcpy(name, _name); Person::Person(const Person& p) name= new char[strlen(p.name)+1]; strcpy(name, p.name); Person::~Person() delete[] name; 37 ostream& operator<<(ostream& os, const Person& p) os<<p.name; return os; int main() Person p1("lee JUNE"); Person p2("hong KEN"); cout<<p1<<endl; cout<<p2<<endl; p1=p2; // 문제의원인, p1.operator=(p2); cout<<p1<<endl; // 소멸자호출에러!!
디폴트대입연산자예 : 얕은복사 (2) p1=p2 실행전 p1=p2 실행후 38
디폴트대입연산자예 : 깊은복사 39 #include <iostream> using std::endl; using std::cout; using std::ostream; class Person private: char* name; Person(char* _name); Person(const Person& p); ~Person(); Person& operator=(const Person& p); friend ostream& operator<<(ostream& os, const Person& p); ; Person::Person(char* _name) name= new char[strlen(_name)+1]; strcpy(name, _name); Person::Person(const Person& p) name= new char[strlen(p.name)+1]; strcpy(name, p.name); Person::~Person() delete[] name; Person& Person::operator=(const Person& p) delete []name; name= new char[strlen(p.name)+1]; strcpy(name, p.name); return *this; ostream& operator<<(ostream& os, const Person& p) os<<p.name; return os; int main() Person p1("lee JUNE"); Person p2("hong KEN"); cout<<p1<<endl; cout<<p2<<endl; p1=p2; // p1.operator=(p2); cout<<p1<<endl;
프로젝트과제 3 프로젝트과제 2 에 10-9 절의은행계좌관리과제프로그램의내용을추가하여라. Container 클래스, 대입연산자오버로딩 9 개의파일로분리 (9-6 절 ) 40
Jong Hyuk Park