제12장 다형성과 가상함수 다형성의 개념을 이해한다. 상향 형변환의 개념을 이해한다. 가상 함수의 개념을 이해한다.

Slides:



Advertisements
Similar presentations
7 장 프렌드와 연산자 중복 1 명품 C++. 친구란 ? 2 우리 집 냉장고 내 침대 우리 집 TV 우리 집 식탁 친구 친구 ? 내 가족의 일원은 아니지만 내 가족과 동일한 권한을 가진 일원으로 인정받은 사람.
Advertisements

어서와 Java는 처음이지! 제20장 실전프로젝트 #2.
01_ 가상 함수를 사용한 다형성의 구현 02_ 오버라이딩
명품 C++ 프로그래밍 3장. 클래스와 객체.
ㅎㅎ 구조체 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스 구조체 배열.
ㅎㅎ 구조체 C++ 프로그래밍 기초 : 객체지향의 시작 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스
명품 C++ 8장 상속.
C++ Espresso 제1장 기초 사항.
C++ Espresso 제2장 제어문과 함수.
최윤정 Java 프로그래밍 클래스 상속 최윤정
강좌명 : C++프로그래밍 (C++ Programming)
제6장 객체배열과 벡터 객체 배열을 이해한다. 벡터(vector) 클래스를 사용할 수 있다.
8. 객체와 클래스 (기본).
윤 홍 란 다형성과 가상 함수 윤 홍 란
어서와 Java는 처음이지! 제7장 상속.
C++ Espresso 제9장 다형성.
명품 C++ 9장 가상 함수와 추상 클래스.
제 6장. 생성자와 소멸자 학기 프로그래밍언어및실습 (C++).
C++ Espresso 제6장 생성자와 소멸자.
8.1 인터페이스 개요와 인터페이스 정의 8.2 인터페이스의 사용 8.3 인터페이스의 상속 8.4 인터페이스 참조
상속이란? - 기반클래스로부터 다른 클래스를 파생하는 법 protected란? 가상함수 (virtual function)
제13장 파일처리 스트림의 개념을 이해한다. 객체 지향적인 방법을 사용하여 파일 입출력을 할 수 있다.
제 3장. C보다 나은 C++ II.
다중 상속 - 가상 상속 추상 자료형 순수 가상함수
명품 C++ 7장 프렌드와 연산자 중복.
명품 C++ 7장 프렌드와 연산자 중복.
어서와 Java는 처음이지! 제7장 상속.
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
C ++ 프로그래밍 시작.
정적 멤버 변수/정적 멤버 함수 - friend 함수/클래스 template
C++ Espresso 제12장 템플릿.
명품 C++ 4장. 객체 포인터와 객체 배열, 객체의 동적 생성.
C++ Programming: chapter 7 – inheritence
제4장 클래스와 객체 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
패키지와 접근 제어 패키지에 대하여 접근 제어에 대하여.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
명품 C++ 8장 상속.
스택(Stack) 김진수
14장. 포인터와 함수에 대한 이해.
14. 예외처리.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
[INA470] Java Programming Youn-Hee Han
13. 연산자 오버로딩.
제14장 예외처리와 템플릿 예외 처리의 개요를 학습한다. 예외 처리를 적용할 수 있다. 템플릿의 개념을 이해한다.
어서와 C언어는 처음이지 제14장.
제5장 생성자와 접근제어 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
C++ Espresso 제8장 상속.
어서와 Java는 처음이지! 제9장 인터페이스, 패키지.
명품 C++ 9장 가상 함수와 추상 클래스.
가상함수와 추상 클래스.
제2장 제어구조와 배열 if-else 문에 대하여 학습한다. 중첩 if-else 문에 대하여 학습한다.
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
Power Java 제11장 상속.
C++ Espresso 제11장 예외 처리와 형변환.
멤버함수 중첩( 복사 생성자 ) - 연사자 중첩 - 동적 메모리를 가지는 클래스를 지원 하도록 멤버 함수 작성
제8장 포인터와 동적객체 생성 포인터의 개념을 이해한다. 포인터와 관련된 연산을 이해한다.
JA A V W. 06.
5. 논리적 자료표현 : 구조체.
12. 상속 : 고급.
객체기반 SW설계 팀활동지 4.
제 11장. 템플릿과 STL 학기 프로그래밍언어및실습 (C++).
03. 메모리 관리 C++ 프로그램에서 다룰 수 있는 메모리의 종류
중복 멤버의 처리 조 병 규 한 국 교 통 대 학 교 SQ Lab..
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
3. 모듈 (5장. 모듈).
Static과 const 선언 조 병 규 한 국 교 통 대 학 교 SQ Lab..
29장. 템플릿과 STL 01_ 템플릿 02_ STL.
상속 (Inheritance) private 전용부분 전용부분 공용부분 공용부분 public 기본 클래스
7 생성자 함수.
Presentation transcript:

제12장 다형성과 가상함수 다형성의 개념을 이해한다. 상향 형변환의 개념을 이해한다. 가상 함수의 개념을 이해한다. 다형성을 실제로 적용할 수 있다.

이번 장에서 만들어 볼 프로그램

다형성이란?

실행시간 다형성 “실행 시간 다형성”이란 객체들의 타입이 다르면 똑같은 메시지가 전달되더라도 서로 다른 동작을 하는 것을 말한 다.

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

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

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

상향 형변환 #include <iostream> using namespace std; class Animal { public: void speak() { cout << "Animal speak()" << endl; } }; class Dog : public Animal int age; void speak() { cout << "멍멍" << endl; } class Cat : public Animal void speak() { cout << "야옹" << endl; }

상향 형변환 int main() { Animal *a1 = new Dog(); a1->speak(); Animal *a2 = new Cat(); a2->speak(); //a1->age = 10; // 오류!! return 0; }

가상함수 Animal 포인터를 통하여 객체의 멤버 함수를 호출하더라 도 객체의 종류에 따라서 서로 다른 speak()가 호출된다 면 상당히 유용할 것이다.

에제 class Animal { public: virtual void speak() { cout << "Animal speak()" << endl; } }; class Dog : public Animal int age; void speak() { cout << "멍멍" << endl; } class Cat : public Animal void speak() { cout << "야옹" << endl; }

에제 int main() { Animal *a1 = new Dog(); a1->speak(); Animal *a2 = new Cat(); a2->speak(); return 0; }

동적바인딩 vs 정적바인딩

도형 예제 #1

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

에제 class Rect: public Shape { private: int width, height; public: Rect(int x, int y, int w, int h) : Shape(x, y), width(w), height(h) { } void draw() { cout << "Rectangle Draw" << endl; };

예제 int main() { Shape *ps = new Rect(0, 0, 100, 100); // OK! ps->draw(); delete ps; return 0; }

도형 예제 #2

에제 class Shape { protected: int x, y; public: Shape(int x, int y) : x(x), y(y) { } virtual void draw() { cout << "Shape Draw" << endl; } }; class Rect : public Shape { private: int width, height; Rect(int x, int y, int w, int h) : Shape(x, y), width(w), height(h) { } void draw() { HDC hdc = GetWindowDC(GetForegroundWindow()); Rectangle(hdc, x, y, x + width, y + height);

에제 class Circle : public Shape { private: int radius; public: Circle(int x, int y, int r) : Shape(x, y), radius(r) { } void draw() { HDC hdc = GetWindowDC(GetForegroundWindow()); Ellipse(hdc, x - radius, y - radius, x + radius, y + radius); } }; int main() { Shape *shapes[3]; shapes[0] = new Rect(rand() % 600, rand() % 300, rand() % 100, rand() % 100); shapes[1] = new Circle(rand() % 600, rand() % 300, rand() % 100); shapes[2] = new Circle(rand() % 600, rand() % 300, rand() % 100); for (int i = 0; i < 3; i++) { shapes[i]->draw(); 에제

에제

참조자와 가상함수 참조자도 포인터와 마찬가지로 모든 것이 동일하게 적용 된다. 즉 부모 클래스의 참조자로 자식 클래스를 가리킬 수 있으며 가상 함수의 동작도 동일하다.

가상소멸자 다형성을 사용하는 과정에서 소멸자를 virtual로 해주지 않으면 문제가 발생한다. #include <iostream> using namespace std; class Parent { public: ~Parent() { cout << "Parent 소멸자" << endl; } };

가상소멸자 class Child : public Parent { public: ~Child() { cout << "Child 소멸자" << endl; } }; int main() Parent* p = new Child(); // 상향 형변환 delete p; }

해결책 class Parent { public: virtual ~Parent() { cout << "Parent 소멸자" << endl; } };

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

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

Lab: 동물 예제

Solution 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;

Lab: 인터페이스

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

Lab: 던전 게임

Solution class Sprite { protected: int x, y; // 현재 위치 char shape; public: Sprite(int x, int y, char shape) : x{ x }, y{ y }, shape{ shape } { } virtual ~Sprite() { } virtual void move(char d) = 0; char getShape() { return shape; } int getX() { return x; } int getY() { return y; } bool checkCollision(Sprite *other) { if (x == other->getX() && y == other->getY()) return true; else } };

Solution // 주인공 스프라이트를 나타낸다. class Hero : public Sprite { public: Hero(int x, int y) : Sprite(x, y, 'H') { } void draw() { cout << 'H'; } void move(char d) { if (d == 'a') { x -= 1; } else if (d == 'w') { y -= 1; } else if (d == 's') { y += 1; } else if (d == 'd') { x += 1; } } }; // 보물을 나타내는 클래스이다. class Treasure : public Sprite { Treasure(int x, int y) : Sprite(x, y, 'T') { }

Solution class Enemy : public Sprite { public: Enemy(int x, int y) : Sprite(x, y, 'E') { } void move(char d) { } }; // 게임 보드를 표시한다. class Board { char *board; int width, height; Board(int w, int h) : width{ w }, height{ h } { board = new char[width*height]; clearBoard(); } ~Board() { delete board;

Solution void setValue(int r, int c, char shape) { board[r*width + c] = shape; } void printBoard() { for (int i = 0; i < height; i++) { cout << "\t"; for (int j = 0; j < width; j++) cout << board[i*width + j]; cout << endl; void clearBoard() { for (int i = 0; i < height; i++) board[i*width + j] = '.'; }; void drawLine(char x) { for (int i = 0; i < 100; i++) cout << x; Solution

Solution int main() { // 벡터를 사용하여 게임에서 나타나는 모든 스프라이트들을 저장한다. // 다형성을 사용해야 하므로 포인터를 벡터에 저장한다. // 다형성은 포인터를 이용해야 사용할 수 있음을 잊지 말자. vector<Sprite *> list; int width, height; cout << "보드의 크기를 입력하시오[최대 10X10]: " << endl; cout << "가로: "; cin >> width; cout << "세로: "; cin >> height; Board board(height, width); list.push_back(new Hero(0, 0)); list.push_back(new Treasure(height - 1, width - 1)); list.push_back(new Enemy(3, 3)); Solution

Solution // 게임 루프이다. while (true) { // 보드를 다시 그린다. board.clearBoard(); for (auto& e : list) board.setValue(e->getY(), e->getX(), e- >getShape()); board.printBoard(); // 사용자의 입력을 받는다. char direction; cout << "어디로 움직일까요(a, s, w, d): "; cin >> direction; // 모든 스프라이트를 이동시킨다. e->move(direction); drawLine('-'); } Solution

Solution // 벡터 안의 모든 동적 할당을 해제한다. for (auto& e : list) delete e; list.clear(); return 0; }

Q & A