C++ Espresso 제10장 프렌드와 연산자 중복.

Slides:



Advertisements
Similar presentations
3. 메소드와 변수 SCJP 자격증 프로젝트 발표자 : 최선웅. 1. 메 소 드 개 념 2. 메 소 드 양 식 3. 메 소 드 변 수 4. 메 소 드 예 제 5. 참 고 문 헌 / 자 료 목 차.
Advertisements

7 장 프렌드와 연산자 중복 1 명품 C++. 친구란 ? 2 우리 집 냉장고 내 침대 우리 집 TV 우리 집 식탁 친구 친구 ? 내 가족의 일원은 아니지만 내 가족과 동일한 권한을 가진 일원으로 인정받은 사람.
01_ 가상 함수를 사용한 다형성의 구현 02_ 오버라이딩
ㅎㅎ 구조체 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스 구조체 배열.
ㅎㅎ 구조체 C++ 프로그래밍 기초 : 객체지향의 시작 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express Slide 1 (of 27)
제 9 장 포인터.
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.
클래스 class, 객체 object 생성자 constructor 접근 access 제어 이벤트 event 처리.
제14장 동적 메모리.
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.
최윤정 Java 프로그래밍 클래스 상속 최윤정
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
컴퓨터 프로그래밍 기초 [Final] 기말고사
C 8장. 포인터 #include <stdio.h> int main(void) { int num;
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 12. 포인터의 이해.
Lesson 5. 레퍼런스 데이터형.
제 6장. 생성자와 소멸자 학기 프로그래밍언어및실습 (C++).
C++ Espresso 제6장 생성자와 소멸자.
5장. 참조 타입.
제 3장. C보다 나은 C++ II.
명품 C++ 7장 프렌드와 연산자 중복.
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
SqlParameter 클래스 선문 비트 18기 발표자 : 박성한.
컴퓨터 프로그래밍 기초 #02 : printf(), scanf()
정적 멤버 변수/정적 멤버 함수 - friend 함수/클래스 template
C++ Espresso 제12장 템플릿.
명품 C++ 4장. 객체 포인터와 객체 배열, 객체의 동적 생성.
14. 예외처리.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
11장. 1차원 배열.
C#.
13. 연산자 오버로딩.
제14장 예외처리와 템플릿 예외 처리의 개요를 학습한다. 예외 처리를 적용할 수 있다. 템플릿의 개념을 이해한다.
JA A V W. 03.
사용자 함수 사용하기 함수 함수 정의 프로그램에서 특정한 기능을 수행하도록 만든 하나의 단위 작업
어서와 C언어는 처음이지 제14장.
13. 포인터와 배열! 함께 이해하기 IT응용시스템공학과 김 형 진 교수.
3장 상수 변수 기본 자료형 키워드와 식별자 상수와 변수 기본 자료형 형변환 자료형의 재정의.
명품 C++ 9장 가상 함수와 추상 클래스.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express Slide 1 (of 22)
19. 함수 포인터와 void 포인터.
3장. 변수와 연산자 교안 : 전자정보통신 홈페이지 / 커뮤니티/ 학술세미나
Lesson 2. 기본 데이터형.
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
2장. 변수와 타입.
컴퓨터 프로그래밍 기초 - 8th : 함수와 변수 / 배열 -
Power Java 제11장 상속.
C++ Espresso 제11장 예외 처리와 형변환.
멤버함수 중첩( 복사 생성자 ) - 연사자 중첩 - 동적 메모리를 가지는 클래스를 지원 하도록 멤버 함수 작성
CHAP 21. 전화, SMS, 주소록.
12. 상속 : 고급.
클래스 : 기능 CHAPTER 7 Section 1 생성자(Constructor)
중복 멤버의 처리 조 병 규 한 국 교 통 대 학 교 SQ Lab..
7주차: Functions and Arrays
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
3. 모듈 (5장. 모듈).
컴퓨터 프로그래밍 기초 - 9th : 배열 / 포인터 -
구조체(struct)와 공용체(union)
Summary of Pointers and Arrays
Static과 const 선언 조 병 규 한 국 교 통 대 학 교 SQ Lab..
윤성우의 열혈 C++ 프로그래밍 윤성우 저 열혈강의 C++ 프로그래밍 개정판 Chapter 05. 복사 생성자.
29장. 템플릿과 STL 01_ 템플릿 02_ STL.
어서와 C언어는 처음이지 제21장.
개정판 누구나 즐기는 C언어 콘서트 제13장 동적 메모리 출처: pixabay.
13. 포인터와 배열! 함께 이해하기.
7 생성자 함수.
6 객체.
Presentation transcript:

C++ Espresso 제10장 프렌드와 연산자 중복

C++의 고급 기능인 프렌드와 연산자 중복을 살펴봅니다. 이번 장에서 학습할 내용 C++의 고급 기능인 프렌드와 연산자 중복을 살펴봅니다. 프렌드 함수 연산자 중복 타입 변환

프렌드 함수 프렌드 함수(friend function): 클래스의 내부 데이터에 접근할 수 있는 특수한 함수

프렌드 함수 선언 방법 프렌드 함수의 원형은 비록 클래스 안에 포함 하지만 멤버 함수는 아니다. 프렌드 함수의 본체는 외부에서 따로 정의 프렌드 함수는 클래스 내부의 모든 멤버 변수를 사용 가능

예제 #include <iostream> #include <string> using namespace std; class Company { private: int sales, profit; // sub()는Company의 전용부분에 접근할 수있다. friend void sub(Company& c); public: Company(): sales(0), profit(0) { } }; void sub(Company& c) cout << c.profit << endl;

예제 int main() { Company c1; sub(c1); return 0; }

프렌드 클래스 클래스도 프렌드로 선언할 수 있다. (예) Manager의 멤버들은 Employee의 전용 멤버를 직접 참조할 수 있다.

프렌드 함수의 용도 두개의 객체를 비교할 때 많이 사용된다. ① 일반 멤버 함수 사용 if( obj1.equals(obj2) ) { ... } ② 프렌드 함수 사용 if( equals(obj1, obj2) ) 이해하기가 쉽다

예제 #include <iostream> using namespace std; class Date { friend bool equals(Date d1, Date d2); private: int year, month, day; public: Date(int y, int m, int d) year = y; month = m; day = d; }

예제 멤버 변수 접근 가능 // 프렌드함수 bool equals(Date d1, Date d2) { return d1.year == d2.year && d1.month == d2.month && d1.day == d2.day; } int main() Date d1(1960, 5, 23), d2(2002, 7, 23); cout << equal_f(d1, d2) << endl; 멤버 변수 접근 가능

예제 #include <iostream> using namespace std; class Complex { public: friend Complex add (Complex, Complex); Complex (double r, double i) {re=r; im=i; } Complex(double r) { re=r; im=0; } Complex () { re = im = 0; } void Output(){ cout << re << " + " << im <<"i" << endl; } private: double re, im; };

예제 Complex add(Complex a1, Complex a2) { return Complex (a1.re+a2.re, a1.im+a2.im); } int main() Complex c1(1,2), c2(3,4); Complex c3 = add(c1, c2); c3.Output(); return 0; 4 + 6i 계속하려면 아무 키나 누르십시오 . . .

중간 점검 문제 1. 프렌드 함수란 무엇인가? 2. 어떤 경우에 프렌드 함수가 유용한가? 3. 두 개의 Vector 객체를 더하는 프렌드 함수를 정의하라.

연산자 중복 일반적으로는 연산자 기호를 사용하는 편이 함수를 사용하는 것보다 이해하기가 쉽다. 다음의 두 가지 문장 중에서 어떤 것이 더 이해하기 쉬운가? sum = x + y + z; sum = add(x, add(y, z));

원점 벡터 예제 class Vector { private: double x, y; public: Vector(double x, int double){ this->x = x; this->y = y; }

벡터간의 연산을 연산자로 표기 Vector v1, v2, v3; v3 = v1 + v2;

연산자 중복 연산자 중복(operator overloading): 여러 가지 연산자들을 클래스 객체에 대해서도 적용하는 것 C++에서 연산자는 함수로 정의 반환형 operator연산자(매개 변수 목록) { ....// 연산 수행 } (예) Vector operator+(const Vector&, const Vector&);

연산자 중복 함수 이름 중복 함수 이름은 operator에 연산자를 붙이고 함수 기호

연산자 중복 구현의 방법

전역 함수로 구현하는 방법

예제 #include <iostream> using namespace std; class Vector { private: double x, y; public: Vector(double x, double y){ this->x = x; this->y = y; } friend Vector operator+(const Vector& v1, const Vector& v2); void display() cout << "(" << x << ", " << y << ")" << endl; };

예제 Vector operator+(const Vector& v1, const Vector& v2) { v.x = v1.x + v2.x; v.y = v1.y + v2.y; return v; } int main() Vector v1(1, 2), v2(3, 4); Vector v3 = v1 + v2; v3.display(); return 0; (4, 6)

멤버 함수로 구현하는 방법

예제 #include <iostream> using namespace std; class Vector { private: double x, y; public: Vector(double x, double y){ this->x = x; this->y = y; } Vector operator+(Vector& v2) Vector v(0.0, 0.0); v.x = this->x + v2.x; v.y = this->y + v2.y; return v;

예제 void display() { cout << "(" << x << ", " << y << ")" << endl; } }; int main() Vector v1(1.0, 2.0), v2(3.0, 4.0); Vector v3 = v1 + v2; v3.display(); return 0; (4, 6)

멤버 함수로만 구현가능한 연산자 아래의 연산자는 항상 멤버 함수 형태로만 중복 정의가 가능하다.

중복이 불가능한 연산자 아래의 연산자는 중복 정의가 불가능하다.

중간 점검 문제 1. 벡터 사이의 뺄셈 연산자 -을 중복하여 보자. 2. 두개의 벡터가 같은지를 검사하는 == 연산자를 중복하라. 3. 문자열을 나타내는 String 클래스를 작성하고 + 연산자를 중복하라.

피연산자 타입이 다른 연산 벡터의 스칼라곱(scalar product)이라고 불리는 연산을 구현 벡터가 (x, y)이고 α가 스칼라일 때에 벡터 스칼라곱은 (αx, αy)

곱셈 연산자 중복 곱셈 연산자를 중복하여 정의한다. 교환 법칙이 성립하여야 함 Vector operator*(Vector& v, double alpha); // v * 2.0 형태 처리 Vector operator*(double alpha, Vector& v); // 2.0 * v 형태 처리

곱셈 연산자 중복

곱셈 연산자 중복

== 연산자 중복 두개의 객체가 동일한 데이터를 가지고 있는지를 체크하는데 사용

== 연산자의 중복

== 연산자의 중복

<< 연산자의 중복

<<과 >> 연산자 중복 연산을 수행한 후에 다시 스트림 객체를 반환하여야 함

주의할 점 전역 함수 형태만 사용 가능: 우리가 ostream 클래스를 다시 정의할 수 없다.

<< 연산자의 중복

<< 연산자의 중복

>> 연산자의 중복 입력 연산자 >>의 중복 오류 처리를 하는 것이 좋음

= 연산자 중복

얕은 대입 문제 동적 할당 공간이 있으면 반드시 = 연산자를 중복 정의하여야 함

얕은 대입 문제 동적 할당 공간이 있으면 반드시 = 연산자를 중복 정의하여야 함

증가/감소 연산자의 중복 ++와 – 연산자의 중복

증가/감소 연산자의 중복

증가/감소 연산자의 중복

전위/후위의 문제 전위와 후위 연산자를 구별하기 위하여 ++가 피연산자 뒤에 오는 경우에는 int형 매개 변수를 추가한다.

전위/후위의 문제

[ ] 연산자의 중복 인덱스 연산자의 중복

인덱스 연산자 중복

인덱스 연산자 중복

인덱스 연산자 중복

인덱스 연산자 중복

인덱스 연산자 중복

포인터 연산자의 중복 간접 참조 연산자 *와 멤버 연산자 ->의 중복 정의

포인터 연산자의 중복

포인터 연산자의 중복

스마트 포인터 포인터 연산 정의를 이용하여서 만들어진 향상된 포인터를 스마트 포인터(smart pointer)라고 한다. 주로 동적 할당된 공간을 반납할 때 사용된다.

함수 호출 연산자 ()의 중복 함수 호출때 사용하는 () 도 중복이 가능하다

함수 호출 연산자 ()의 중복

중간 점검 문제 1. 벡터를 나타내는 Vector 클래스에 - 연산자를 중복하라. 3. 문자열을 나타내는 String 클래스를 작성하고 << 연산자를 중복하라.

타입 변환 클래스의 객체들도 하나의 타입에서 다른 타입으로 자동적인 변환이 가능하다. 이것은 변환 생성자(conversion constructor)와 변환 연산자(conversion operator)에 의하여 가능하다.

변환 생성자와 변환 연산자

변환 생성자 변환 생성자 (int->Book) #include <iostream> #include <string> using namespace std; class Book { private: int isbn; // 책의ISBN string title; // 책의제목 public: Book() { // 생성자 isbn = 0; title = “unknown"; } Book(int isbn) { this->isbn = isbn; this->title = "unknown"; void display() { cout << isbn << ":" << title << endl; }; 변환 생성자 (int->Book)

예제 int main() { Book b1 = 9782001; // int 타입을 Book 타입에 대입 b1.display(); b1 = 9783001; // 가능 return 0; } 9782001:unknown 9783001:unknown 계속하려면 아무 키나 누르십시오 . . . 컴파일러는 변환 생성자를 이용하여서 정수 9782001을 Book 객체로 변환하는 것이다.

버그의 원인 변환 생성자는 버그의 원인이 될 수도 있다. Book b2 = 3.141592; b2.display(); (설명) 실수->정수-> 객체 (해결책)만약 생성자 앞에 explicit를 붙이면 컴파일러가 자동적으로 타입 변환을 하지 못한다.

변환 연산자 중복 정의 operator 데이터_타입() { .... }

변환 연산자의 중복 정의 변환 생성자 (int->Book) 변환 연산자 (Book->int) #include <iostream> #include <string> using namespace std; class Book { private: int isbn; string title; public: Book(int isbn, string& title) { this->isbn = isbn; this->title = title; } Book(int isbn) { this->title = "unknown"; operator int() const return isbn; 변환 생성자 (int->Book) 변환 연산자 (Book->int)

예제 void display() { cout << isbn << ":" << title << endl; } }; bool check(int isbn) { cout << isbn << endl; return true; int main() Book b1 = 9782001; // 변환생성자실행! b1.display(); int isbn = b1; // 변환연산자실행! check(b1); // 변환연산자실행! return 0;

연산자 중복시 주의할 점 새로운 연산자를 만드는 것은 허용되지 않는다. :: 연산자, .* 연산자, . 연산자, ?: 연산자는 중복이 불가능하다. 내장된 int형이나 double형에 대한 연산자의 의미를 변경할 수는 없다. 연산자들의 우선 순위나 결합 법칙은 변경되지 않는다. 만약 + 연산자를 오버로딩하였다면 일관성을 위하여 +=, -= 연산자도 오버로딩하는 것이 좋다. 일반적으로 산술 연산자와 관계 연산자는 비멤버 함수로 정의한다. 반면에 할당 연산자는 멤버 함수로 정의한다.

중간 점검 문제 1. 클래스 Car를 string으로 변환하는 변환 연산자를 작성하시오. 2. 변환 연산자의 위험성은 무엇인가?

MyString #include <iostream> using namespace std; class MyString { private: char *pBuf; //동적으로할당된메모리의주소값저장 public: MyString(const char *s=NULL); MyString(MyString& s); ~MyString(); void print(); // 문자열을화면에출력 int getSize(); // 문자열의길이반환 MyString operator+(MyString& s); // + 연산자중복정의 };

MyString // 생성자 MyString::MyString(const char *s) { if( s == NULL ) pBuf = new char[1]; pBuf[0] = NULL; } else pBuf = new char[::strlen(s)+1]; strcpy(pBuf, s); // 복사생성자 MyString::MyString(MyString &s) pBuf = new char[s.getSize()+1]; strcpy(pBuf, s.pBuf);

MyString MyString::~MyString() { if ( pBuf ) delete [] pBuf; } void MyString::print() cout << pBuf << endl; int MyString::getSize() return strlen(pBuf); MyString MyString::operator+(MyString& s) char *temp = new char[getSize() + s.getSize() + 1]; strcpy(temp, pBuf); strcat(temp, s.pBuf); MyString r(temp); delete [] temp; return r;

MyString int main() { MyString s1("Hello "); MyString s2("World!"); MyString s3 = s1 + s2; s1.print(); s2.print(); s3.print(); return 0; } Hello World! Hello World!

MyArray #include <iostream> #include <assert.h> using namespace std; // 향상된배열을나타낸다. class MyArray { friend ostream& operator<<(ostream &, const MyArray &); // 출력연산자<< private: int *data; // 배열의데이터 int size; // 배열의크기 public: MyArray(int size = 10); // 디폴트생성자 ~MyArray(); // 소멸자 int getSize() const; // 배열의크기를반환 MyArray& operator=(const MyArray &a); // = 연산자중복정의 int& operator[](int i); // [] 연산자중복: 설정자 };

MyArray MyArray::MyArray(int s) { size = (s > 0 ? s : 10); // 디폴트크기를10으로한다. data = new int[size]; // 동적메모리할당 for (int i = 0; i < size; i++) data[i] = 0; // 요소들의초기화 } MyArray::~MyArray() { delete [] data; // 동적메모리반납 data = NULL; MyArray& MyArray::operator=(const MyArray& a) { if (&a != this) { // 자기자신인지를체크 delete [] data; // 동적메모리반납 size = a.size; // 새로운크기를설정 data = new int[size]; // 새로운동적메모리할당 data[i] = a.data[i]; // 데이터복사 return *this; // a = b = c와같은경우를대비

MyArray int MyArray::getSize() const { return size; } int& MyArray::operator[](int index) { assert(0 <= index && index < size); // 인데스가범위에있지않으면중지 return data[index]; // 프렌드함수정의 ostream& operator<<(ostream &output, const MyArray &a) { int i; for (i = 0; i < a.size; i++) { output << a.data[i] << ' '; output << endl; return output; // cout << a1 << a2 << a3와같은경우대비

MyArray int main() { MyArray a1(10); a1[0] = 1; a1[1] = 2; a1[2] = 3; cout << a1 ; return 0; } 1 2 3 4 0 0 0 0 0 0

Q & A