상속 및 동적바인딩 사용하기 USING INHERITANCE AND DYNAMIC BINDING

Slides:



Advertisements
Similar presentations
01_ 가상 함수를 사용한 다형성의 구현 02_ 오버라이딩
Advertisements

ㅎㅎ 구조체 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스 구조체 배열.
ㅎㅎ 구조체 C++ 프로그래밍 기초 : 객체지향의 시작 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express Slide 1 (of 27)
제 9 장 포인터.
클래스 class, 객체 object 생성자 constructor 접근 access 제어 이벤트 event 처리.
Chap07 상속 Section 1 : 상속의 개요 Section 2 : 멤버 변수의 상속
제14장 동적 메모리.
최윤정 Java 프로그래밍 클래스 상속 최윤정
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
Report #2 - Solution 문제 #1: 다음과 같이 프로그램을 작성하라.
11장 구조체와 열거형 구조체의 정의 구조체 변수의 선언 구조체 초기화 및 사용 구조체 재정의 포인터를 이용해서 구조체 사용
제12장 다형성과 가상함수 다형성의 개념을 이해한다. 상향 형변환의 개념을 이해한다. 가상 함수의 개념을 이해한다.
자료 구조: Chapter 3 (2)구조체, 포인터
윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 12. 포인터의 이해.
명품 C++ 9장 가상 함수와 추상 클래스.
제 6장. 생성자와 소멸자 학기 프로그래밍언어및실습 (C++).
8.1 인터페이스 개요와 인터페이스 정의 8.2 인터페이스의 사용 8.3 인터페이스의 상속 8.4 인터페이스 참조
5장. 참조 타입.
제 3장. C보다 나은 C++ II.
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
SqlParameter 클래스 선문 비트 18기 발표자 : 박성한.
정적 멤버 변수/정적 멤버 함수 - friend 함수/클래스 template
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
명품 C++ 8장 상속.
컴퓨터 프로그래밍 실습 #6 제 4 장 클래스 작성.
프로그램과 데이터의 구조화 Organizing programs and data
14. 예외처리.
10장. 예외처리.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
C#.
13. 연산자 오버로딩.
7장 인터페이스와 추상 클래스.
Method & library.
명품 C++ 9장 가상 함수와 추상 클래스.
24장. 파일 입출력.
Lesson 2. 기본 데이터형.
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
20장. 객체지향 프로그래밍 01_ 객체지향 프로그래밍의 시작.
Lab 8 Guide: 멀티스레딩 예제 2 * Critical Section을 이용한 멀티스레딩 동기화 (교재 15장, 쪽)
Power Java 제11장 상속.
5강. 배열 배열이란? 배열의 문법 변수와 같이 이해하는 배열의 메모리 구조의 이해 레퍼런스의 이해 다차원 배열
C++ Espresso 제11장 예외 처리와 형변환.
JA A V W. 06.
CHAP 21. 전화, SMS, 주소록.
12. 상속 : 고급.
객체기반 SW설계 팀활동지 4.
클래스 : 기능 CHAPTER 7 Section 1 생성자(Constructor)
중복 멤버의 처리 조 병 규 한 국 교 통 대 학 교 SQ Lab..
7주차: Functions and Arrays
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
Lecture 04 객체지향 페러다임 Kwang-Man Ko
3. 모듈 (5장. 모듈).
함수, 모듈.
서브클래스 조 병 규 한 국 교 통 대 학 교 SQ Lab..
컴퓨터 프로그래밍 기초 - 9th : 배열 / 포인터 -
구조체(struct)와 공용체(union)
새로운 타입 정의하기 Defining new types
Static과 const 선언 조 병 규 한 국 교 통 대 학 교 SQ Lab..
실습 UBLAB.
2.가상머신의 탐험 도구, Oolong에 대하여 ps lab 김윤경.
윤성우의 열혈 C++ 프로그래밍 윤성우 저 열혈강의 C++ 프로그래밍 개정판 Chapter 05. 복사 생성자.
윤성우의 열혈 C++ 프로그래밍 윤성우 저 열혈강의 C++ 프로그래밍 개정판 Chapter 07. 상속의 이해.
29장. 템플릿과 STL 01_ 템플릿 02_ STL.
OOP Practices OOP presentation 6 작성자 Kimjinsik 소속 Mobile computing Lab
상속 (Inheritance) private 전용부분 전용부분 공용부분 공용부분 public 기본 클래스
C++ Espresso 제15장 STL 알고리즘.
7 생성자 함수.
6 객체.
Presentation transcript:

상속 및 동적바인딩 사용하기 USING INHERITANCE AND DYNAMIC BINDING Chapter 13 상속 및 동적바인딩 사용하기 USING INHERITANCE AND DYNAMIC BINDING

13장에서는… 지금까지는 13장에서는 OOP의 다른 중요한 요소를 공부 자신만의 데이터 타입을 작성하는 방법을 공부 상속 (inheritance) 동적 바인딩 (dynamic binding)

13.1 상속 (inheritance) 이런 문제 시나리오가 발생한다면… 어떻게 할까? 대학원 학생의 성적도 처리하자. 그런데 대학원생은 논문 (thesis) 점수가 있다. (비슷한데 다르다.) 어떻게 할까? 방법1: Grad라는 class를 완전히 새로 작성 방법2: 지금까지 애써 작성해놓은 Student_info가 있으니 그걸 활용 (이 경우 소프트웨어 재사용성(reuse)이 높다고 말한다.) 13장에서는 방법2를 위한 상속을 공부한다.

is-a 관계와 has-a 관계 is-a 관계와 has-a 관계 has-a 관계는 포함 관계 직사각형은 is-a 도형, 잠자리는 is-a 곤충… 의자는 has-a 다리, 선풍기는 has-a 모터, Student는 has-a 중간점수 has-a 관계는 포함 관계 class leg { private: … public: }; // chair는 leg을 포함한다 class chair { private: leg l1, l2, l3, l4; … public: }; 4

상속 is-a 관계는 상속 관계 class diagram { public: … private: }; // rectangle은 diagram이 가진 것을 상속 받는다. class rectangle: public diagram { public: … private: }; 5

학생성적처리에서 상속 관계 Student (Core라 이름을 바꾸자)와 Grad는 is-a 관계 class Core { public: Core(); Core(std::istream&); std::string name() const; std::istream& read(std::istream&); double grade() const; private: std::istream& read_common(std::istream&); std::string n; double midterm, final; std::vector<double> homework; }; Grad는 Core로부터 파생 (derived from) Grad는 Core로부터 상속받음 (inherits from) Grad는 파생 클래스, Core는 기본 클래스 class Grad: public Core { public: Grad(); Grad(std::istream&); double grade() const; std::istream& read(std::istream&); private: double thesis; }; 6

상속받는 것과 재정의 Core의 모든 멤버는 Grade의 멤버가 된다. Grade 클래스는 자신만의 멤버를 추가할 수 있다. Grad는 Core로부터 상속 받았으므로, Core의 모든 멤버는 Grade의 멤버가 된다. 단, 생성자, 대입연산자, 소멸자 등은 제외된다 n, midterm, final, homework도 Grad의 멤버 name()과 read_common()도 Grad의 멤버 Grade 클래스는 자신만의 멤버를 추가할 수 있다. thesis 멤버 기본 클래스의 멤버를 재정의: read()와 grade()는 부모 것을 쓰지 않고 자신의 것을 사용 (왜?) 7

13.1.1 보호정책 다시보기 Grad의 멤버 함수가 Core의 private 멤버에 접근할 수 있는가? NO!! Core의 private 멤버: n, midterm, final, homework, read_common() Grad는 접근해야 한다. 따라서… Core는 Grad (자식)에게는 허용하지만 그 외 class는 여전히 차단해야 한다. protected : 파생 클래스가 기본클래스의 protected 멤버들을 접근할 수 있음 8

protected Core를 다시 써 보면, class Core { public: Core(); Core(std::istream&); std::string name() const; std::istream& read(std::istream&); double grade() const; protected: std::istream& read_common(std::istream&); double midterm, final; std::vector<double> homework; private: std::string n; }; // 이름을 나타내는 n은 왜 여전히 private에 두나? 9

13.1.2 연산 string Core::name() const { return n; } double Core::grade() const { return ::grade(midterm, final, homework); } istream& Core::read_common(istream& in) // 학생의 이름과 성적을 읽어 저장 in >> n >> midterm >> final; return in; istream& Core::read(istream& in) read_common(in); read_hw(in, homework); 10

13.1.2 연산 istream& Grad::read(istream& in) { Core::read_common(in); // 빨간색 부분은 생략해도 좋다. in >> thesis; read_hw(in, Core::homework); return in; } double Grad::grade() const // 대학원생은 계산된 점수와 논문 (thesis) 점수 중 작은 것을 취한다 return min(Core::grade(), thesis); 11

13.1.3 상속과 생성자 파생 타입의 객체를 어떻게 생성할까? 파생 객체는 아래와 같은 과정으로 생성된다 즉 Grad g; 또는 Grad g(cin)과 같이 g라는 객체를 생성할 때 무슨 일이 벌어질까? 자신의 것과 부모 (기본) 클래스 것을 가지게 되는데… 파생 객체는 아래와 같은 과정으로 생성된다 1) 전체 객체 (파생멤버+기본멤버)에 대한 공간 할당 2) 기본 클래스의 생성자 실행: 기본 클래스에 해당하는 부분을 초기화 3) 파생클래스의 생성자 실행: 생성자 초기 설정자(constructor initializer )에 표시된 파생 클래스의 멤버들을 초기화. 만약 있다면, 파생 클래스 생성자의 본체 실행 생성자 초기 설정자: Grad(): thesis(0) { }에서 thesis(0) 부분을 말한다. 12

13.1.3 상속과 생성자 생성자 함수들 class Core { public: Core(): midterm(0), final(0) { } // 디폴트 생성자 Core(std::istream& is) { read(is); } // 인자가 있는 생성자 … }; class Grad: public Core { Grad(): thesis(0) { } Grad(std::istream& is) { read(is); } 실행되는 생성자는? Grad g; Grad g(cin); 13

13.2 다형성 및 가상 함수 비멤버 함수인 compare()를 생각해 봅시다. 아래와 같이 하면 어떤 일이? Grad g(cin); // Grade 레코드를 읽는다 Grad g2(cin); // ” Core c(cin); // Core 레코드를 읽는다 Core c2(cin); // ” compare(g, g2); // 파생 클래스를 전달 가능한가? compare(c, c2); compare(g, c); // 심지어 파생과 기본이 섞여 있으면? bool compare(const Core& c1, const Core& c2) { return c1.name() < c2.name(); } const Core& c1=g; const Core& c2=g2; const Core& c1=c; const Core& c2=c2; const Core& c1=g; const Core& c2=c; 14

13.2 다형성 및 가상 함수 가능하다. Grad는 Core 파트를 가지고 있으므로, compare()의 레퍼런스 매개변수를 Grad 객체의 Core 파트에 바인딩할 수 있다. (바인딩이란 어떤 것을 다른 것에 연결시키거나 한정시키는 작업) n midterm final homework thesis Core 파트 Grad 객체 15

13.2.1 객체의 타입을 모르는 상태에서 값 얻기 점수로 정렬한다고 하면… 이렇게 하면 될까? 그렇지 않다!! compare()와 엄청난 차이가 있다. Core와 Grad에 모두 grade()함수가 정의되어 있다. Core::grade() Grad::grade() Grad객체에 대해서는 Grad::grade()를 호출하고, Core객체에 대해서는 Core::grade()를 호출해야 한다. bool compare_grades( const Core& c1, const Core& c2) { return c1.grade() < c2.grade(); } 16

virtual 함수 제대로 하려면 가상(virtual) 함수로 해야 한다. 이렇게 하면 Core의 grade()를 쓸 건지, 아니면 Grad의 grade()를 쓸 건지는 실행시간(run time)에 결정: 동적 바인딩 virtual은 기본 클래스의 선언부에서만 한다. class Core{ Public: virtual double grade() const; … }; 17

13.2.2 동적 바인딩 (dynamic binding) 동적 바인딩: 함수가 실행시간에 바인딩 된다 레퍼런스나 포인터를 통해 virtual 함수를 호출하면, 그 함수는 동적 바인딩 된다 정적 바인딩(static binding): 객체 자체에 대한 virtual 함수를 호출하면 정확한 타입이 컴파일 할 때 결정된다 예를 들어, 아래처럼 하면 정적 바인딩이 된다 Grad 객체를 전달할 수는 있는데, 이때 기본 파트만 잘라서 전달 bool compare_grades(const Core c1, const Core c2) { return c1.grade() < c2.grade(); } 18

다형성 (polymorphism) 다형성: 동적인 상황에 따라 여러 모양을 띨 수 있는 성질 보충 설명 하자면, C++는 virtual 함수의 동적 바인딩 속성을 통해 다형성을 지원한다 포인터나 레퍼런스를 통해 virtual 함수를 호출한다는 것은, 다형성을 띤 함수 호출을 수행하는 것이다. Core c; Grad g; Core *p; Core& r=g; c.grade(); // Core::grad()에 정적 바인딩 g.grade(); // Core::grad()에 정적 바인딩 p->grade(); // 동적 바인딩. p가 가르키는 객체의 타입에 따라 결정 // 앞부분에서 p=&c; 또는 p=&g에 따라 다르게 동작 r.grade(); // 동적 바인딩. r이 참조하는 객체의 타입에 따라 결정 19

13.2.3 요약 class Core { public: Core(): midterm(0), final(0) { } 13.2.3 요약 지금까지 한 것을 정리하면… class Core { public: Core(): midterm(0), final(0) { } Core(std::istream& is) { read(is); } std::string name() const; // as defined in 13.1.2 virtual std::istream& read(std::istream&); virtual double grade() const; protected: // accessible to derived classes std::istream& read_common(std::istream&); double midterm, final; std::vector<double> homework; private: // accessible only to Core std::string n; }; 20

13.2.3 요약 class Grad: public Core { public: Grad(): thesis(0) { } Grad(std::istream& is) { read(is); } // as defined in 13.1.2 // Note: grade and read are virtual by inheritance double grade() const; std::istream& read(std::istream&); private: double thesis; }; bool compare(const Core&, const Core&); 21

13.3 상속을 통해 문제 해결하기 main()을 아래와 같이 작성하면… 대학원생은? int main() { vector<Core> students; // read and process Core records Core record; string::size_type maxlen = 0; // read and store the data while (record.read(cin)) { // Core에서 읽어들인다. maxlen = max(maxlen, record.name().size()); students.push_back(record); } sort(students.begin(), students.end(), compare); for (vector<Core>::size_type i=0; i!=students.size(); ++i) { cout << students[i].name() <<string(maxlen+1-students[i].name().size(), ' '); try { double final_grade = students[i].grade(); // Core의 성적계산 streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error e) { cout << e.what() << endl; return 0; 22

그렇다고 아래와 같이 작성하면… 학부생은? int main() { vector<Grad> students; // read and process Core records Grad record; string::size_type maxlen = 0; // read and store the data while (record.read(cin)) { // Grad에서 읽어들인다. maxlen = max(maxlen, record.name().size()); students.push_back(record); } sort(students.begin(), students.end(), compare); for (vector<Core>::size_type i=0; i!=students.size(); ++i) { cout << students[i].name() <<string(maxlen+1-students[i].name().size(), ' '); try { double final_grade = students[i].grade(); // Grad의 성적 계산 streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error e) { cout << e.what() << endl; return 0; 23

13.3.1 알지 못하는 타입에 대한 컨테이너 학부생과 대학원생이 섞여 있을 때는 아래와 같이 하면 될까? 안된다! 왜? 13.3.1 알지 못하는 타입에 대한 컨테이너 학부생과 대학원생이 섞여 있을 때는 아래와 같이 하면 될까? int main() { vector<Core*> students; // virtual을 쓰기 위해 포인터로 한다. Core* record; string::size_type maxlen = 0; // read and store the data while(record->read(cin)) { // 타입에 따라 Core 또는 Grad에서.. 제대로 될까?? // 비정상적 종료! maxlen = max(maxlen, record->name().size()); students.push_back(record); } … 안된다! 왜? 24

포인터의 벡터를 정렬 Core 객체를 가리키는 두 포인터들을 취하는 새로운 비교 함수 bool compare_Core_ptrs(const Core* cp1, const Core* cp2) { return compare(*cp1, *cp2); }

가리키는 객체에 따라 적절한 함수 호출 다음과 같이 해야 한다. int main() { vector<Core*> students; // 객체가 아닌 포인터를 저장 Core* record; // 임시 변수도 포인터 char ch; string::size_type maxlen = 0; // 데이터를 읽고 저장 while (cin >> ch) { if (ch == 'U') record = new Core; // Core 객체 할당 else record = new Grad; // Grad 객체 할당 record->read(cin); // virtual 함수 호출 maxlen = max(maxlen, record->name().size()); students.push_back(record); } // 포인터에 대해 작동하는 compare 전달 sort(students.begin(), students.end(), compare_Core_ptrs); 26

객체 해제할 때, 파생클래스의 소멸자 호출? // 이름과 성적을 출력 for (vector<Core*>::size_type i = 0; i != students.size(); ++i) { // students[i]는 포인터 cout << students[i]->name() << string(maxlen + 1 - students[i]->name().size(), ' '); try { double final_grade = students[i]->grade(); streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error e) { cout << e.what() << endl; } delete students[i]; // 읽을 때 할당된 객체를 해제 (문제 없나?) return 0; 27

13.3.2 가상 소멸자(virtual destructor) 객체를 할당할 때, Grad와 Core 객체 모두에 대해 공간을 할당했다. 이 객체들의 포인터는 Core* 이다 따라서, delete를 실행하면, 포인터가 Grad의 객체를 가리키고 있다고 해도, Core에 대한 포인터를 해제시킨다.  문제 발생 포인터에 대해 delete를 호출하면, 자동으로 만들어진 소멸자가 실행되고, 그 객체가 사용한 공간을 반환한다. 이때, 시스템은 어떤 소멸자를 실행해야 할까요? Grad의 멤버를 소멸시켜야 할까요? Core의 멤버를 소멸시켜야 할 까요? 실제로 포인터가 가리키고 있는 타입에 따라 소멸해야 한다!!  virtual 소멸자 class Core { public: virtual ~Core() { } // 이전과 동일 …