C++ Espresso 제9장 다형성.

Slides:



Advertisements
Similar presentations
Kim Yeon Hee 8장. 상속과 다형성 Kim Yeon Hee.
Advertisements

3. C++와 객체지향 C++ 코딩 방법 객체 단위로 2 개의 파일 인터페이스 파일 구현파일
상속에 대해 알아봅니다. 상속과 클래스 계층구조 메소드 오버라이딩
01_ 가상 함수를 사용한 다형성의 구현 02_ 오버라이딩
명품 C++ 프로그래밍 3장. 클래스와 객체.
명품 C++ 8장 상속.
명품 C++ 4장. 객체 포인터와 객체 배열, 객체의 동적 생성.
Power C++ 제6장 포인터와 문자열.
C++ Espresso 제3장 배열과 포인터.
C++ Espresso 제3장 배열과 포인터.
C++ Espresso 제1장 기초 사항.
C++ Espresso 제2장 제어문과 함수.
강좌명 : C++프로그래밍 (C++ Programming)
Chapter 6 구조체.
제6장 객체배열과 벡터 객체 배열을 이해한다. 벡터(vector) 클래스를 사용할 수 있다.
C++ Exspresso 제5장 클래스의 기초.
8. 객체와 클래스 (기본).
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
어서와 Java는 처음이지! 제7장 상속.
제12장 다형성과 가상함수 다형성의 개념을 이해한다. 상향 형변환의 개념을 이해한다. 가상 함수의 개념을 이해한다.
10장 객체-지향 프로그래밍 II ©창병모.
명품 C++ 8장 상속.
C++ Espresso 제6장 생성자와 소멸자.
Game Programming 03 - Tools of trade
명품 JAVA Essential.
윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 02. 프로그램의 기본구성.
상속이란? - 기반클래스로부터 다른 클래스를 파생하는 법 protected란? 가상함수 (virtual function)
다중 상속 - 가상 상속 추상 자료형 순수 가상함수
명품 C++ 7장 프렌드와 연산자 중복.
18장. 헤더 파일과 구현 파일 01_ 헤더 파일과 구현 파일의 사용.
어서와 Java는 처음이지! 제7장 상속.
C ++ 프로그래밍 시작.
C++ Programming: chapter 7 – inheritence
제4장 클래스와 객체 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
C++ 개요 객체지향 윈도우즈 프로그래밍 한국성서대학교 유일선
스택(Stack) 김진수
17장. 문자열 01_ 문자열 사용의 기본 02_ 문자열의 사용.
Visual Studio 2010 프로젝트 생성하기 PC화면에서 Visual Studio 2010 아이콘을 더블클릭 하거나
[INA470] Java Programming Youn-Hee Han
명품 C++ 프로그래밍 1장. C++ 시작.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
Chapter 3 클래스. 최호성.
제5장 생성자와 접근제어 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
어서와 Java는 처음이지! 제9장 인터페이스, 패키지.
03. 안드로이드를 위한 Java 문법 제목. 03. 안드로이드를 위한 Java 문법 제목.
명품 C++ 9장 가상 함수와 추상 클래스.
가상함수와 추상 클래스.
Chapter 1 C와는 다른 C++. 최호성.
C# 09장. 상속성.
제2장 제어구조와 배열 if-else 문에 대하여 학습한다. 중첩 if-else 문에 대하여 학습한다.
제 12장. 사용자 정의형으로서의 클래스 학기 프로그래밍언어및실습 (C++).
4. 고급변수 사용 : 포인터와 관련하여 메모리 바라보기
멤버 함수인 operator+()가 실행, 또는 전역 함수인 operator+()가 실행 Point p3 = p1+p2; 에서
제8장 포인터와 동적객체 생성 포인터의 개념을 이해한다. 포인터와 관련된 연산을 이해한다.
A Basic of C++.
C-언어와 기반구조 정보보호학과 이정수 교수.
5. 논리적 자료표현 : 구조체.
[ 단원 06 ] 상속과 다형성.
12. 상속 : 고급.
제 11장. 템플릿과 STL 학기 프로그래밍언어및실습 (C++).
3장,4장 발표 서정우.
03. 메모리 관리 C++ 프로그램에서 다룰 수 있는 메모리의 종류
C++ Espresso 제13장 입출력과 파일처리.
포인터와 배열 조 병 규 한 국 교 통 대 학 교 SQ Lab..
10장 템플릿과 표준 템플릿 라이브러리(STL)
캡슐화 (Encapsulation) 두원공과대학 소프트웨어개발과 이 원 주.
실습과제 1번 /* 1. 멤버 변수로 반경 radius를 갖고, 그 값을 모니터에 출력하는
C.
C++ 언어의 특징
발 표 자 : 7조 손 창 국 윤 오 성, 박 진 완 객체 지향 프로그래밍 C++
Presentation transcript:

C++ Espresso 제9장 다형성

다형성은 객체들이 동일한 메시지에 대하여 서로 다르게 동작하는 것 입니다. 이번 장에서 학습할 내용 다형성은 객체들이 동일한 메시지에 대하여 서로 다르게 동작하는 것 입니다. 다형성 가상 함수 순수 가상 함수

다형성이란? 다형성(polymorphism)이란 객체들의 타입이 다르면 똑같은 메시지가 전달되더라도 서로 다른 동작을 하는 것 다형성은 객체 지향 기법에서 하나의 코드로 다양한 타입의 객체를 처리하는 중요한 기술이다.

다형성이란?

객체 포인터의 형변환 먼저 객체 포인터의 형변환을 살펴보자. 상향 형변환(upcasting): 자식 클래스 타입을 부모 클래스타입으로 변환 객체 포인터의 형변환 하향 형변환(downcasting): 부모 클래스 타입을 자식 클래스타입으로 변환

Animal 타입 포인터로 Dog 객체를 참조하니 틀린 거 같지만 올바른 문장!! 상속과 객체 포인터 Animal 타입 포인터로 Dog 객체를 참조하니 틀린 거 같지만 올바른 문장!! Animal *pa = new Dog();// OK!

왜 그럴까? 자식 클래스 객체는 부모 클래스 객체를 포함하고 있기 때문이다.

도형 예제 class Shape { protected: int x, y; public:   public: void setOrigin(int x, int y){ this->x = x; this->y = y; } void draw() { cout <<"Shape Draw"; };

도형 예제 class Rectangle : public Shape { private: int width, height; void setWidth(int w) { width = w; } void setHeight(int h) { height = h; void draw() { cout << "Rectangle Draw"; };

상향 형변환 Shape *ps = new Rectangle(); // OK! ps->setOrigin(10, 10); // OK! 상향 형변환

하향 형변환 Shape *ps = new Rectangle(); 여기서 ps를 통하여 Rectangle의 멤버에 접근하려면? 1. Rectangle *pr = (Rectangle *) ps; pr->setWidth(100);   2. ((Rectangle *) ps)->setWidth(100); 하향 형변환

예제 #include <iostream> using namespace std;   class Shape { // 일반적인도형을나타내는부모클래스 protected: int x, y; public: void draw() { cout <<"Shape Draw" << endl; } void setOrigin(int x, int y){ this->x = x; this->y = y; };

예제 class Rectangle : public Shape { private: int width, height; void setWidth(int w) { width = w; } void setHeight(int h) { height = h; void draw() { cout << "Rectangle Draw"<< endl; };  

예제 class Circle : public Shape { private: int radius; public:   public: void setRadius(int r) { radius = r; } void draw() { cout << "Circle Draw"<< endl; };

예제 int main() { Shape *ps = new Rectangle(); // OK! ps->setOrigin(10, 10); ps->draw(); ((Rectangle *)ps)->setWidth(100); // Rectangle의setWidth() 호출 delete ps; } Shape Draw 계속하려면 아무 키나 누르십시오 . . .

함수의 매개 변수 함수의 매개 변수는 자식 클래스보다는 부모 클래스 타입으로 선언하는 것이 좋다. 모든 도형을 받을 수 있다. void move(Shape& s, int sx, int sy) { s.setOrigin(sx, sy); } int main() Rectangle r; move(r, 0, 0);   Circle c; move(c, 10, 10); return 0; 모든 도형을 받을 수 있다.

중간 점검 문제 부모 클래스 포인터 변수는 자식 클래스 객체를 참조할 수 있는가? 역은 성립하는가? 2. 다형성은 어떤 경우에 유용한가? 3. 부모 클래스 포인터로 자식 클래스에만 정의된 함수를 호출할 수 있는가?

가상 함수 단순히 자식 클래스 객체를 부모 클래스 객체로 취급하는 것이 어디에 쓸모가 있을까? 다음과 같은 상속 계층도를 가정하여 보자.

Shape 포인터이기 때문에 Shape의 draw()가 호출 예제 class Shape { ... } class Rectangle : public Shape { int main() { Shape *ps = new Rectangle(); // OK! ps->draw(); // 어떤 draw()가 호출되는가? Shape 포인터이기 때문에 Shape의 draw()가 호출 Shape Draw

가상 함수 만약 Shape 포인터를 통하여 멤버 함수를 호출하더라도 도형의 종류에 따라서 서로 다른 draw()가 호출된다면 상당히 유용할 것이다. 즉 사각형인 경우에는 사각형을 그리는 draw()가 호출되고 원의 경우에는 원을 그리는 draw()가 호출된다면 좋을 것이다. -> draw()를 가상 함수로 작성하면 가능

가상 함수 가상 함수 정의 #include <iostream> #include <string> using namespace std;   class Shape { protected: int x, y; public: void setOrigin(int x, int y){ this->x = x; this->y = y; } virtual void draw() { cout <<"Shape Draw" << endl; }; 가상 함수 정의

가상 함수 재정의 class Rectangle : public Shape { private: int width, height; void setWidth(int w) { width = w; } void setHeight(int h) { height = h; void draw() { cout << "Rectangle Draw" << endl; }; 재정의

가상 함수 재정의 class Circle : public Shape { private: int radius; public: void setRadius(int r) { radius = r; } void draw() { cout << "Circle Draw"<< endl; }; 재정의

예제 int main() { Shape *ps = new Rectangle(); // OK! ps->draw(); delete ps; Shape *ps1 = new Circle(); // OK! ps1->draw(); delete ps1; return 0; } Rectangle Draw Circle Draw 계속하려면 아무 키나 누르십시오 . . .

동적 바인딩 컴파일 단계에서 모든 바인딩이 완료되는 것을 정적 바인딩(static binding)이라고 한다. 반대로 바인딩이 실행 시까지 연기되고 실행 시간에 실제 호출되는 함수를 결정하는 것을 동적 바인딩(dynamic binding), 또는 지연 바인딩(late binding)이라고 한다.

정적 바인딩과 동적 바인딩 바인딩의 종류 특징 속도 대상 정적 바인딩 (dynamic binding) 컴파일 시간에 호출 함수가 결정된다. 빠르다 일반 함수 동적 바인딩 (static binding) 실행 시간에 호출 함수가 결정된다. 늦다 가상 함수

가상 함수의 구현 v-table을 사용한다.

예제 #include <iostream> using namespace std; class Shape {   class Shape { protected: int x, y; public: virtual void draw() { cout <<"Shape Draw"; } void setOrigin(int x, int y){ this->x = x; this->y = y; };

예제 class Rectangle : public Shape { private: int width, height;   public: void setWidth(int w) { width = w; } void setHeight(int h) { height = h; void draw() { cout << "Rectangle Draw" << endl; };

예제 class Circle : public Shape { private: int radius; public: void setRadius(int r) { radius = r; } void draw() { cout << "Circle Draw" << endl; };

예제 class Triangle: public Shape { private: int base, height; public: void draw() { cout << "Triangle Draw" << endl; } };   int main() { Shape *arrayOfShapes[3]; arrayOfShapes[0] = new Rectangle(); arrayOfShapes[1] = new Triangle(); arrayOfShapes[2] = new Circle(); for (int i = 0; i < 3; i++) { arrayOfShapes[i]->draw();

예제 Rectangle Draw Triangle Draw Circle Draw

다형성의 장점 새로운 도형이 추가되어도 main()의 루프는 변경할 필요가 없다. class Parallelogram : Shape { public: void draw(){ cout << "Parallelogram Draw" << endl; } };

예제 #include <iostream> using namespace std; class Animal {   class Animal { public: Animal() { cout <<"Animal 생성자" << endl; } ~Animal() { cout <<"Animal 소멸자" << endl; } virtual void speak() { cout <<"Animal speak()" << endl; } }; class Dog : public Animal Dog() { cout <<"Dog 생성자" << endl; } ~Dog() { cout <<"Dog 소멸자" << endl; } void speak() { cout <<"멍멍" << endl; }

예제 class Cat : public Animal { public: Cat() { cout <<"Cat 생성자" << endl; } ~Cat() { cout <<"Cat 소멸자" << endl; } void speak() { cout <<"야옹" << endl; } };   int main() Animal *a1 = new Dog(); a1->speak(); Animal *a2 = new Cat(); a2->speak(); return 0; }

예제 Animal 생성자 Dog 생성자 멍멍 Animal 소멸자 Cat 생성자 야옹

중간 점검 문제 가상 함수를 사용하면 어떤 장점이 있는가? 2. 동적 바인딩과 정적 바인딩을 비교하라.

참조자와 가상함수 참조자인 경우에는 다형성이 동작될 것인가? 참조자도 포인터와 마찬가지로 모든 것이 동일하게 적용된다.

예제 #include <iostream> using namespace std; class Animal { public: virtual void speak() { cout <<"Animal speak()" << endl; } }; class Dog : public Animal void speak() { cout <<"멍멍" << endl; } class Cat : public Animal void speak() { cout <<"야옹" << endl; }

예제 int main() { Dog d; Animal &a1 = d; a1.speak(); Cat c; Animal &a2 = c; a2.speak(); return 0; } 멍멍 야옹

가상 소멸자 다형성을 사용하는 과정에서 소멸자를 virtual로 해주지 않으면 문제가 발생한다. (예제) String 클래스를 상속받아서 각 줄의 앞에 헤더를 붙이는 MyString 이라는 클래스를 정의하여 보자.

소멸자 문제 #include <iostream> using namespace std; class String { char *s; public: String(char *p){ cout << "String() 생성자" << endl; s = new char[strlen(p)+1]; strcpy(s, p); } ~String(){ cout << "String() 소멸자" << endl; delete[] s; virtual void display() { cout << s; };

소멸자 문제 class MyString : public String { char *header; public: MyString(char *h, char *p) : String(p){ cout << "MyString() 생성자" << endl; header = new char[strlen(h)+1]; strcpy(header, h); } ~MyString(){ cout << "MyString() 소멸자" << endl; delete[] header; void display() { cout << header; // 헤더출력 String::display(); cout << header << endl; // 헤더출력 };

소멸자 문제 int main() { String *p = new MyString("----", "Hello World!"); // OK! p->display(); delete p; return 0; } String() 생성자 MyString() 생성자 ----Hello World!---- String() 소멸자 MyString의 소멸자가 호출되지 않음

가상 소멸자 그렇다면 어떻게 하여야 MyString 소멸자도 호출되게 할 수 있는가? String 클래스의 소멸자를 virtual로 선언하면 된다.

가상 소멸자 class String { char *s; public: String(char *p){ ... // 앞과동일 } virtual ~String(){ cout << "String() 소멸자" << endl; delete[] s; }; class MyString : public String { ...// 앞과동일 int main() { String() 생성자 MyString() 생성자 ----Hello World!---- MyString() 소멸자 String() 소멸자

중간 점검 문제 1. 가상 함수가 필요한 이유는 무엇인가? 2. 어떤 경우에 부모 클래스의 소멸자에 virtual을 붙여야 하는가?

순수 가상 함수 순수 가상 함수(pure virtual function): 함수 헤더만 존재하고 함수의 몸체는 없는 함수 (예) virtual void draw() = 0; 추상 클래스(abstract class): 순수 가상 함수를 하나라도 가지고 있는 클래스 virtual 반환형 함수이름(매개변수 리스트) = 0;

순수 가상 함수의 예 class Shape { protected: int x, y; public: …   public: … virtual void draw() = 0; }; class Rectangle : public Shape { private: int width, height; void draw() { cout << "Rectangle Draw" << endl; }

순수 가상 함수 int main() { Shape *ps = new Rectangle(); // OK! ps->draw(); // Rectangle의draw()가호출된다. delete ps; return 0; } Rectangle Draw

추상 클래스 추상 클래스(abstract class): 순수 가상 함수를 가지고 있는 클래스 추상 클래스는 추상적인 개념을 표현하는데 적당하다.

예제 class Animal { virtual void move() = 0; virtual void eat() = 0; virtual void speak() = 0; }; class Lion : public Animal { void move(){ cout << "사자의 move() << endl; } void eat(){ cout << "사자의 eat() << endl; void speak(){ cout << "사자의 speak() << endl;

추상 클래스를 인터페이스로 추상 클래스는 객체들 사이에 상호 작용하기 위한 인터페이스를 정의하는 용도로 사용할 수 있다.

인터페이스의 예 홈 네트워킹 예제

예제 class RemoteControl { // 순수가상함수정의 virtual void turnON() = 0; // 가전제품을켠다. virtual void turnOFF() = 0; // 가전제품을끈다. }   class Television : public RemoteControl { void turnON() { // 실제로TV의전원을켜기위한코드가들어간다. ... void turnOFF() // 실제로TV의전원을끄기위한코드가들어간다.

예제 int main() { Television *pt = new Television(); pt->turnOn(); pt->turnOff();   Refrigerator *pr = new Refrigerator(); pr->turnOn(); pr->turnOff(); delete pt; delete pr; return 0; }

중간 점검 문제 1. 순수 가상 함수의 용도는? 2. 모든 순수 가상 함수를 구현하여야 하는가?

Q & A