가상함수와 추상 클래스.

Slides:



Advertisements
Similar presentations
제 5 장 상속과 다형성.
Advertisements

Kim Yeon Hee 8장. 상속과 다형성 Kim Yeon Hee.
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장 제어문과 함수.
Chapter 6 구조체.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
제6장 객체배열과 벡터 객체 배열을 이해한다. 벡터(vector) 클래스를 사용할 수 있다.
명품 C++ 13장 예외 처리와 C 언어와의 링크 지정.
C++ Exspresso 제5장 클래스의 기초.
2주 실습강의 Java의 기본문법(1) 인공지능연구실.
8. 객체와 클래스 (기본).
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
명품 JAVA Programming.
Power Java 제4장 자바 프로그래밍 기초.
제12장 다형성과 가상함수 다형성의 개념을 이해한다. 상향 형변환의 개념을 이해한다. 가상 함수의 개념을 이해한다.
C++ Espresso 제9장 다형성.
10장 객체-지향 프로그래밍 II ©창병모.
10장 템플릿과 표준 템플릿 라이브러리(STL)
배열, 포인터, 참조 배열은 같은 형을 가지는 변수들의 묶음이다..
명품 C++ 8장 상속.
명품 C++ 9장 가상 함수와 추상 클래스.
C++ Espresso 제6장 생성자와 소멸자.
명품 JAVA Essential.
상속이란? - 기반클래스로부터 다른 클래스를 파생하는 법 protected란? 가상함수 (virtual function)
MFC Application Frameworks (AFX)
명품 C++ 7장 프렌드와 연산자 중복.
18장. 헤더 파일과 구현 파일 01_ 헤더 파일과 구현 파일의 사용.
14장. 함수 1 01_ 함수의 기본 02_ 인자의 전달.
Chapter 05. 클래스 완성. chapter 05. 클래스 완성 01. 복사 생성자 복사 생성(Copy Construction) 생성될 때 자신과 같은 타입의 객체를 변수로 받아, 이 객체와 같은 값을 갖는 새로운 객체를 생성하는 것 명시적인 생성 과정뿐만.
C ++ 프로그래밍 시작.
정적 멤버 변수/정적 멤버 함수 - friend 함수/클래스 template
C++ Programming: chapter 7 – inheritence
C++ 개요 객체지향 윈도우즈 프로그래밍 한국성서대학교 유일선
스택(Stack) 김진수
17장. 문자열 01_ 문자열 사용의 기본 02_ 문자열의 사용.
명품 C++ 프로그래밍 1장. C++ 시작.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
Chapter 3 클래스. 최호성.
제5장 생성자와 접근제어 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
명품 C++ 9장 가상 함수와 추상 클래스.
Chapter 1 C와는 다른 C++. 최호성.
제2장 제어구조와 배열 if-else 문에 대하여 학습한다. 중첩 if-else 문에 대하여 학습한다.
제 12장. 사용자 정의형으로서의 클래스 학기 프로그래밍언어및실습 (C++).
4. 고급변수 사용 : 포인터와 관련하여 메모리 바라보기
컴퓨터공학실습(I) 3주 인공지능연구실.
멤버 함수인 operator+()가 실행, 또는 전역 함수인 operator+()가 실행 Point p3 = p1+p2; 에서
제8장 포인터와 동적객체 생성 포인터의 개념을 이해한다. 포인터와 관련된 연산을 이해한다.
5. 논리적 자료표현 : 구조체.
[ 단원 06 ] 상속과 다형성.
12. 상속 : 고급.
제 11장. 템플릿과 STL 학기 프로그래밍언어및실습 (C++).
JVM의 구조와 메모리 모델 JVM의 내부 구조 클래스 파일 클래스 로더 메소드(method) 영역 힙(heap) 영역
03. 메모리 관리 C++ 프로그램에서 다룰 수 있는 메모리의 종류
포인터와 배열 조 병 규 한 국 교 통 대 학 교 SQ Lab..
6장 클래스(상속).
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
10장 템플릿과 표준 템플릿 라이브러리(STL)
캡슐화 (Encapsulation) 두원공과대학 소프트웨어개발과 이 원 주.
실습과제 1번 /* 1. 멤버 변수로 반경 radius를 갖고, 그 값을 모니터에 출력하는
C++ 언어의 특징
발 표 자 : 7조 손 창 국 윤 오 성, 박 진 완 객체 지향 프로그래밍 C++
Presentation transcript:

가상함수와 추상 클래스

정적 바인딩 vs. 동적 바인딩 바인딩 (Binding) 정적 바인딩 (Static Binding) 함수의 호출과 정의를 조합하는 과정 정적 바인딩 (Static Binding) 컴파일 단계에서 수행 (항상 같은 함수 호출) 디폴트 동적 바인딩 (Dynamic Binding) 실행 단계에서 수행

상속 관계에서의 함수 중복 #include <iostream> using namespace std; class Base { public: void f() { cout << "Base::f() called" << endl; } }; class Derived : public Base { void f() { cout << "Derived::f() called" << endl; } void main() { Derived d, *pDer; pDer = &d; pDer->f(); // Derived::f() 호출, 정적 바인딩 Base* pBase; pBase = pDer; // 업캐스팅 pBase->f(); // Base::f() 호출, 정적 바인딩 } 객체 d pBase  void f() Base 멤버 Derived d; pDer  void f() Derived 멤버 함수 중복 객체 d pDer  void f() pDer->f(); void f() 실행 객체 d pBase  void f() 실행 pBase->f(); void f() Derived::f() called Base::f() called

가상 함수 가상 함수(virtual function) virtual 키워드로 선언된 멤버 함수 virtual 키워드의 의미 동적 바인딩 지시어 컴파일러에게 함수에 대한 호출 바인딩을 실행 시간까지 미루도록 지 시 class Base { public: virtual void f(); };

가상 함수 void f() void f() void f() #include <iostream> 존재감 상실 객체 d #include <iostream> using namespace std; class Base { public: virtual void f() { cout << "Base::f() called" << endl; } }; class Derived : public Base { virtual void f() { cout << "Derived::f() called" << endl; } int main() { Derived d, *pDer; pDer = &d; pDer->f(); // Derived::f() 호출, 동적 바인딩 Base * pBase; pBase = pDer; // 업 캐스팅 pBase->f(); // Derived::f() 실행, 동적바인딩 } pBase  void f() Base 멤버 Derived d; pDer 가상 함수 선언  void f() Derived 멤버 객체 d pDer  void f() pDer->f(); void f() 실행 객체 d pBase  void f() 동적바인딩 pBase->f(); void f() 실행 Derived::f() called

가상함수와 오버라이딩 오버라이딩 (Overriding) 오버로딩 (Overloading) void f() class Base { public: void f() { cout << "Base::f() called" << endl; } }; class Derived : public Base { cout << "Derived::f() called" << endl; class Base { public: virtual void f() { cout << "Base::f() called" << endl; } }; class Derived : public Base { cout << "Derived::f() called" << endl; 가상 함수 오버라이딩 오버로딩 (Overloading) 오버라이딩 (Overriding) Derived a; Derived b; 존재감 상실 void f() Base 멤버 void f() Base 멤버 void f() Derived 멤버 void f() Derived 멤버 객체 a 객체 b (a) a 객체에는 동등한 호출 기회를 가진 함수 f()가 두 개 존재 (b) b 객체에는 두 개의 함수 f()가 존재하지만, Base의 f()는 존재감을 잃고, 항상 Derived의 f()가 호출됨

가상 함수와 오버라이딩 함수 오버라이딩 (Overriding) 파생 클래스에서 기본 클래스의 가상 함수와 동일한 이름의 함수 중복 선언 전달인자와 반환형 동일 (함수 재정의) 동적 바인딩 기본 클래스의 가상 함수 대신 파생 클래스의 함수 실행 다형성

오버로딩과 오버라이딩 비교

가상함수와 오버로딩 다형성의 실현 draw() 가상 함수를 가진 기본 클래스 Shape 오버라이딩을 통해 Circle, Rect, Line 클래스에서 자신만의 draw() 구현 class Shape { protected: virtual void draw() { } }; 가상 함수 선언. 파생 클래스에서 재정의할 함수에 대한 인터페이스 역할 class Circle : public Shape { protected: virtual void draw() { // Circle을 그린다. } }; class Rect : public Shape { protected: virtual void draw() { // Rect을 그린다. } }; class Line : public Shape { protected: virtual void draw() { // Line을 그린다. } }; 오버라이딩, 다형성 실현 void paint(Shape* p) { p->draw(); } paint(new Circle()); // Circle을 그린다. paint(new Rect()); // Rect을 그린다. paint(new Line()); // Line을 그린다. p가 가리키는 객체에 오버라이딩된 draw() 호출 Shape* p = new Circle() // 업캐스팅 Shape* p = new Rect() // 업캐스팅 Shape* p = new Line() // 업캐스팅

가상함수와 오버라이딩 오버라이딩 특징 가상 함수 이름, 매개 변수 타입과 개수, 리턴 타입이 모두 일치 오버라이딩 시 virtual 지시어 생략 가능 파생 클래스에서 virtual 생략 가능 가상 함수의 접근 지정 private, protected, public 중 자유롭게 지정 가능 class Base { public: virtual void fail(); virtual void success(); virtual void g(int); }; class Derived : public Base { virtual int fail(); // 오버라이딩 실패. 리턴 타입이 다름 virtual void success(); // 오버라이딩 성공 virtual void g(int, double); // 오버로딩 사례. 정상 컴파일 class Base { public: virtual void f(); }; class Derived : public Base { virtual void f(); // virtual void f()와 동일한 선언 생략 가능

예제 9-3 상속이 반복되는 경우 가상 함수 호출 class Base { public: virtual void f() { cout << "Base::f() called" << endl; } }; class Derived : public Base { void f() { cout << "Derived::f() called" << endl; } class GrandDerived : public Derived { void f() { cout << "GrandDerived::f() called" << endl; } int main() { GrandDerived g; Base *bp; Derived *dp; GrandDerived *gp; bp = dp = gp = &g; bp->f(); dp->f(); gp->f(); } GrandDerived::f() called 동적 바인딩에 의해 모두 GrandDerived의 함수 f() 호출

가상함수와 오버라이딩 범위 지정 연산자(::) 기본클래스::멤버함수() 형태로 기본 클래스의 멤버함수를 정적 바인딩으로 호출 기본클래스::멤버함수() 형태로 기본 클래스의 멤버함수를 정적 바인딩으로 호출 class Shape { public: virtual void draw() { ... } }; class Circle : public Shape { Shape::draw(); // 기본 클래스의 draw()를 실행한다. ....

예제 9-4 범위 지정 연산자(::)를 이용한 기본 클래스의 가상 함수 호출 #include <iostream> using namespace std; class Shape { public: virtual void draw() { cout << "--Shape--"; } }; class Circle : public Shape { Shape::draw(); // 기본 클래스의 draw() 호출 cout << "Circle" << endl; int main() { Circle circle; Shape * pShape = &circle; // 업 캐스팅 pShape->draw(); pShape->Shape::draw(); 정적바인딩 동적바인딩 정적바인딩 --Shape--Circle --Shape--

가상 소멸자 가상 소멸자 소멸자를 virtual 키워드로 선언 소멸자 호출 시 동적 바인딩 발생     class Base { public: ~Base(); }; class Derived: public Base { ~Derived(); class Base { public: virtual ~Base(); }; class Derived: public Base { virtual ~Derived(); 동적 바인딩   파생 클래스의 소멸자가 자신의 코드 실행 후, 기본 클래스의 소멸자를 호출하도록 컴파일됨   ~Base() 소멸자만 실행 int main() { Base *p = new Derived(); delete p; } int main() { Base *p = new Derived(); delete p; }  ~Base() 소멸자 실행 ~Base() 소멸자 호출 ~Derived() 실행  ~Base() 실행 소멸자가 가상 함수가 아닌 경우 가상 소멸자 경우

예제 9-6 소멸자를 가상 함수로 선언 #include <iostream> using namespace std; class Base { public: virtual ~Base() { cout << "~Base()" << endl; } }; class Derived: public Base { virtual ~Derived() { cout << "~Derived()" << endl; } int main() { Derived *dp = new Derived(); Base *bp = new Derived(); delete dp; // Derived의 포인터로 소멸 delete bp; // Base의 포인터로 소멸 } ~Derived() ~Base() delete dp; delete bp;

순수 가상 함수 기본 클래스의 가상 함수 목적 순수 가상 함수 파생 클래스에서 재정의할 함수를 알려주는 역할 실행할 코드를 작성할 목적이 아님 기본 클래스의 가상 함수를 굳이 구현할 필요가 있을까? 순수 가상 함수 pure virtual function 함수의 코드가 없고 선언만 있는 가상 멤버 함수 선언 방법 멤버 함수의 원형=0;으로 선언 class Shape { public: virtual void draw()=0; // 순수 가상 함수 선언 };

추상 클래스 추상 클래스 : 최소한 하나의 순수 가상 함수를 가진 클래스 추상 클래스의 특징 추상 클래스 : 최소한 하나의 순수 가상 함수를 가진 클래스 추상 클래스의 특징 온전한 클래스가 아니므로 객체 생성 불가능 추상 클래스의 포인터는 선언 가능 class Shape { // Shape은 추상 클래스 Shape *next; public: void paint() { draw(); } virtual void draw() = 0; // 순수 가상 함수 }; void Shape::paint() { draw(); // 순수 가상 함수라도 호출은 할 수 있다. Shape shape; // 컴파일 오류 Shape *p = new Shape(); // 컴파일 오류 error C2259: 'Shape' : 추상 클래스를 인스턴스화할 수 없습니다. Shape *p;

추상 클래스 추상 클래스의 목적 추상 클래스의 인스턴스를 생성할 목적 아님 상속에서 기본 클래스의 역할을 하기 위함 순수 가상 함수를 통해 파생 클래스에서 구현할 함수의 형태(원형)을 보여주는 인터페이스 역할 추상 클래스의 모든 멤버 함수를 순수 가상 함수로 선언할 필요 없음

추상 클래스 추상 클래스의 상속 추상 클래스의 구현 추상 클래스를 단순 상속하면 자동 추상 클래스 추상 클래스를 상속받아 순수 가상 함수를 오버라이딩 파생 클래스는 추상 클래스가 아님 Shape은 추상 클래스 class Shape { public: virtual void draw() = 0; }; class Circle : public Shape { string toString() { return "Circle 객체"; } Shape shape; // 객체 생성 오류 Circle waffle; // 객체 생성 오류 class Shape { public: virtual void draw() = 0; }; class Circle : public Shape { virtual void draw() { cout << "Circle"; } string toString() { return "Circle 객체"; } Shape shape; // 객체 생성 오류 Circle waffle; // 정상적인 객체 생성 Shape은 추상 클래스 Circle도 추상 클래스 Circle은 추상 클래스 아님 순수 가상 함수 오버라이딩 추상 클래스의 단순 상속 추상 클래스의 구현

추상 클래스 Shape을 추상 클래스로 수정 Shape.cpp #include <iostream> #include "Shape.h" using namespace std; void Shape::paint() { draw(); } void Shape::draw() { cout << “--Shape--" << endl; Shape* Shape::add(Shape *p) { this->next = p; return p; Shape을 추상 클래스로 수정 Shape.h class Shape { Shape* next; protected: virtual void draw() = 0; public: Shape() { next = NULL; } virtual ~Shape() { } void paint(); Shape* add(Shape* p); Shape* getNext() { return next;} }; Shape은 추상 클래스 Circle.h Rect.h Line.h class Circle : public Shape { protected: virtual void draw(); }; class Rect : public Shape { protected: virtual void draw(); }; class Line : public Shape { protected: virtual void draw(); }; #include <iostream> using namespace std; #include "Shape.h" #include "Circle.h" void Circle::draw() { cout << "Circle" << endl; } #include <iostream> using namespace std; #include "Shape.h" #include "Rect.h" void Rect::draw() { cout << "Rectangle" << endl; } #include <iostream> using namespace std; #include "Shape.h" #include "Line.h“ void Line::draw() { cout << "Line" << endl; } Circle.cpp Rect.cpp Line.cpp

예제 9-6 추상 클래스 구현 연습 다음 추상 클래스 Calculator를 상속받아 GoodCalc 클래스를 구현하라. class Calculator { public: virtual int add(int a, int b) = 0; // 두 정수의 합 리턴 virtual int subtract(int a, int b) = 0; // 두 정수의 차 리턴 virtual double average(int a [], int size) = 0; // 배열 a의 평균 리턴. size는 배열의 크기 }; int main() { int a[] = {1,2,3,4,5}; Calculator *p = new GoodCalc(); cout << p->add(2, 3) << endl; cout << p->subtract(2, 3) << endl; cout << p->average(a, 5) << endl; delete p; } 5 -1 3

22 #include <iostream> using namespace std; // 이 곳에 Calculator 클래스 코드 필요 class GoodCalc : public Calculator { public: int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } double average(int* a, int size) double sum = 0; for(int i=0; i<size; i++) sum += a[i]; return sum/size; } };

프로그래밍 실습

프로그래밍 실습