명품 C++ 8장 상속.

Slides:



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

어서와 Java는 처음이지! 제3장선택과 반복.
3. C++와 객체지향 C++ 코딩 방법 객체 단위로 2 개의 파일 인터페이스 파일 구현파일
Vision System Lab, Sang-Hun Han
명품 C++ 프로그래밍 3장. 클래스와 객체.
명품 C++ 4장. 객체 포인터와 객체 배열, 객체의 동적 생성.
Power C++ 제6장 포인터와 문자열.
C++ Espresso 제3장 배열과 포인터.
C++ Espresso 제3장 배열과 포인터.
C++ Espresso 제1장 기초 사항.
C++ Espresso 제2장 제어문과 함수.
강좌명 : C++프로그래밍 (C++ Programming)
실전 프로젝트 2 : 숫자야구 숫자 야구를 구현해보자.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
제6장 객체배열과 벡터 객체 배열을 이해한다. 벡터(vector) 클래스를 사용할 수 있다.
명품 C++ 13장 예외 처리와 C 언어와의 링크 지정.
C++ Exspresso 제5장 클래스의 기초.
8. 객체와 클래스 (기본).
명품 JAVA Programming.
명품 JAVA Programming 제 4 장 클래스와 객체.
C++ Espresso 제9장 다형성.
10장 템플릿과 표준 템플릿 라이브러리(STL)
배열, 포인터, 참조 배열은 같은 형을 가지는 변수들의 묶음이다..
명품 C++ 8장 상속.
자바 5.0 프로그래밍.
명품 C++ 9장 가상 함수와 추상 클래스.
C++ Espresso 제6장 생성자와 소멸자.
명품 JAVA Essential.
명품 Java Programming.
상속이란? - 기반클래스로부터 다른 클래스를 파생하는 법 protected란? 가상함수 (virtual function)
7장 클래스.
명품 C++ 7장 프렌드와 연산자 중복.
18장. 헤더 파일과 구현 파일 01_ 헤더 파일과 구현 파일의 사용.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
Chapter 05. 클래스 완성. chapter 05. 클래스 완성 01. 복사 생성자 복사 생성(Copy Construction) 생성될 때 자신과 같은 타입의 객체를 변수로 받아, 이 객체와 같은 값을 갖는 새로운 객체를 생성하는 것 명시적인 생성 과정뿐만.
C ++ 프로그래밍 시작.
정적 멤버 변수/정적 멤버 함수 - friend 함수/클래스 template
C++ Programming: chapter 7 – inheritence
주소록 프로그램.
명품 C++ 8장 상속.
스택(Stack) 김진수
17장. 문자열 01_ 문자열 사용의 기본 02_ 문자열의 사용.
명품 C++ 프로그래밍 1장. C++ 시작.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
13. 연산자 오버로딩.
제5장 생성자와 접근제어 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
컴퓨터의 기초 제 2강 - 변수와 자료형 , 연산자 2006년 3월 27일.
03. 안드로이드를 위한 Java 문법 제목. 03. 안드로이드를 위한 Java 문법 제목.
Ch.1 Iterator Pattern <<interface>> Aggregate +iterator
명품 C++ 9장 가상 함수와 추상 클래스.
가상함수와 추상 클래스.
제2장 제어구조와 배열 if-else 문에 대하여 학습한다. 중첩 if-else 문에 대하여 학습한다.
제 12장. 사용자 정의형으로서의 클래스 학기 프로그래밍언어및실습 (C++).
4. 고급변수 사용 : 포인터와 관련하여 메모리 바라보기
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
Java Chapter 4 ~ 주차.
자바 5.0 프로그래밍.
루프와 카운트 Looping and counting
멤버 함수인 operator+()가 실행, 또는 전역 함수인 operator+()가 실행 Point p3 = p1+p2; 에서
제8장 포인터와 동적객체 생성 포인터의 개념을 이해한다. 포인터와 관련된 연산을 이해한다.
5. 논리적 자료표현 : 구조체.
[ 단원 06 ] 상속과 다형성.
제 11장. 템플릿과 STL 학기 프로그래밍언어및실습 (C++).
3장,4장 발표 서정우.
03. 메모리 관리 C++ 프로그램에서 다룰 수 있는 메모리의 종류
자바 5.0 프로그래밍.
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
10장 템플릿과 표준 템플릿 라이브러리(STL)
실습과제 1번 /* 1. 멤버 변수로 반경 radius를 갖고, 그 값을 모니터에 출력하는
C++ 언어의 특징
Presentation transcript:

명품 C++ 8장 상속

유전적 상속과 객체 지향 상속 유산 상속 유전적 상속 : 객체 지향 상속 생물 동물 식물 사람 어류 나무 풀 그래요 우리를 꼭 닮았어요 아빠의 유산이다. 나를 꼭 닮았군 유산 상속 유전적 상속 : 객체 지향 상속 생물 동물 식물 사람 어류 나무 풀 상속받음 유전적 상속과 관계된 생물 분류

C++에서의 상속(Inheritance) 클래스 사이에서 상속관계 정의 객체 사이에는 상속 관계 없음 기본 클래스의 속성과 기능을 파생 클래스에 물려주는 것 기본 클래스(base class) - 상속해주는 클래스. 부모 클래스 파생 클래스(derived class) – 상속받는 클래스. 자식 클래스 기본 클래스의 속성과 기능을 물려받고 자신 만의 속성과 기능을 추가하여 작성 기본 클래스에서 파생 클래스로 갈수록 클래스의 개념이 구체화 다중 상속을 통한 클래스의 재활용성 높임

상속의 표현

상속의 목적 및 장점 1. 간결한 클래스 작성 2. 클래스 간의 계층적 분류 및 관리의 용이함 기본 클래스의 기능을 물려받아 파생 클래스는 간결하게 작성 2. 클래스 간의 계층적 분류 및 관리의 용이함 상속은 클래스들의 구조적 관계 파악 용이 3. 클래스 재사용과 확장을 통한 소프트웨어 생산성 향상 빠른 소프트웨어 생산 필요 기존에 작성한 클래스의 재사용 – 상속 상속받아 새로운 기능을 확장 앞으로 있을 상속에 대비한 클래스의 객체 지향적 설계 필요

상속 관계로 클래스의 간결화 사례 기능이 중복된 4 개의 클래스 멤버변경시 일관성 유지가 용이함 상속 관계로 클래스의 간결화

상속 선언 상속 선언 Student 클래스는 Person 클래스의 멤버를 물려받는다. StudentWorker 클래스는 Student의 멤버를 물려받는다. Student가 물려받은 Person의 멤버도 함께 물려받는다. 상속 접근 지정. private, protected도 가능 파생클래스명 기본클래스명 class Student : public Person { // Person을 상속받는 Student 선언 ..... }; class StudentWorker : public Student { // Student를 상속받는 StudentWorker 선언

예제 8-1 Point 클래스를 상속받는 ColorPoint 클래스 만들기 #include <iostream> #include <string> using namespace std; // 2차원 평면에서 한 점을 표현하는 클래스 Point 선언 class Point { int x, y; //한 점 (x,y) 좌표값 public: void set(int x, int y) { this->x = x; this->y = y; } void showPoint() { cout << "(" << x << "," << y << ")" << endl; } }; class ColorPoint : public Point { // 2차원 평면에서 컬러 점을 표현하는 클래스 ColorPoint. Point를 상속받음 string color;// 점의 색 표현 public: void setColor(string color) { this->color = color; } void showColorPoint(); }; void ColorPoint::showColorPoint() { cout << color << ":"; showPoint(); // Point의 showPoint() 호출 } int main() { Point p; // 기본 클래스의 객체 생성 ColorPoint cp; // 파생 클래스의 객체 생성 cp.set(3,4); // 기본 클래스의 멤버 호출 cp.setColor("Red"); // 파생 클래스의 멤버 호출 cp.showColorPoint(); // 파생 클래스의 멤버 호출 Red:(3,4)

파생 클래스의 객체 구성 Point p; ColorPoint cp; class Point { int x, y; // 한 점 (x,y) 좌표 값 public: void set(int x, int y); void showPoint(); }; class ColorPoint : public Point { // Point를 상속받음 string color; // 점의 색 표현 public: void setColor(string color); void showColorPoint(); }; Point p; ColorPoint cp; 파생 클래스의 객체는 기본 클래스의 멤버 포함 int x int x int y int y 기본클래스 멤버 void set() {...} void set() {...} void showPoint() {...} void showPoint() {...} string color void setColor () {...} 파생클래스 멤버 void showColorPoint() { ... }

파생 클래스에서 기본 클래스 멤버 접근 x y void set(int x, int y) { this->x= x; this->y=y; } Point 멤버 void showPoint() { cout << x << y; } 파생클래스에서 기본 클래스 멤버 호출 color void setColor ( ) { ... } void showColorPoint() { cout << color << “:”; showPoint(); } ColorPoint 멤버 ColorPoint cp 객체

외부에서 파생 클래스 객체에 대한 접근 x 3 y 4 void set(int x, int y) { x, y는 Point 클래스에 private이므로 set(), showPoint()에서만 접근 가능 x 3 y 4 void set(int x, int y) { this->x= x; this->y=y; } void showPoint() { cout << x << y; } 기본클래스 멤버 호출 color “Red” void setColor (string color) { this->color = color; } 파생클래스 멤버 호출 ColorPoint cp; cp.set(3, 4); cp.setColor(“Red”); cp.showColorPoint(); void showColorPoint() { cout << color << “:”; showPoint(); } 파생클래스 멤버 호출 main() ColorPoint cp 객체

상속과 객체 포인터 – 업 캐스팅 업 캐스팅(up-casting) 파생 클래스 포인터가 기본 클래스 포인터에 치환되는 것 예) 사람을 동물로 봄 pBase 포인터로 기본 클래스의 public 멤버만 접근 가능 pDer  pBase  pDer 포인터로 객체 cp의 모든 public 멤버 접근 가능 int x 3 int y int main() { ColorPoint cp; ColorPoint *pDer = &cp; Point* pBase = pDer; // 업캐스팅 pDer->set(3,4); pBase->showPoint(); pDer->setColor(“Red”); pDer->showColorPoint(); pBase->showColorPoint(); // 컴파일 오류 } 4 기본클래스 멤버 void set() {...} void showPoint() {...} string color void setColor () {...} 파생클래스 멤버 void showColorPoint() { ... } cp (3,4) Red(3,4)

업 캐스팅 생물을 가리키는 손가락으로 컵을 가리키면 오류

상속과 객체 포인터 – 다운 캐스팅 다운 캐스팅(down-casting) 기본 클래스의 포인터가 파생 클래스의 포인터에 치환되는 것 pBase 포인터로 기본 클래스의 public 멤버만 접근 가능 pDer  pBase  pDer 포인터로 객체 cp의 모든 public 멤버 접근 가능 int x 3 int y int main() { ColorPoint cp; ColorPoint *pDer; Point* pBase = &cp; // 업캐스팅 pBase->set(3,4); pBase->showPoint(); pDer = (ColorPoint *)pBase; // 다운캐스팅 pDer->setColor(“Red”); // 정상 컴파일 pDer->showColorPoint(); // 정상 컴파일 } 4 기본클래스 멤버 void set() {...} void showPoint() {...} 강제 타입 변환 반드시 필요 string color void setColor () {...} 파생클래스 멤버 void showColorPoint() { ... } cp (3,4) Red(3,4)

protected 접근 지정 접근 지정자 private 멤버 public 멤버 protected 멤버 선언된 클래스 내에서만 접근 가능 파생 클래스에서도 기본 클래스의 private 멤버 직접 접근 불가 public 멤버 선언된 클래스나 외부 어떤 클래스, 모든 외부 함수에 접근 허용 파생 클래스에서 기본 클래스의 public 멤버 접근 가능 protected 멤버 선언된 클래스에서 접근 가능 파생 클래스에서만 접근 허용 파생 클래스가 아닌 다른 클래스나 외부 함수에서는 protected 멤버를 접근할 수 없다.

멤버의 접근 지정에 따른 접근성 외부 함수 기본 클래스 다른 클래스 void function() { } class A { private: private 멤버 protected: protected 멤버 public: public 멤버 }; class C { }; class B : public A { }; protected 멤버는 파생 클래스에 접근이 허용된다. 파생 클래스

예제 8-2 protected 멤버에 대한 접근 #include <iostream> #include <string> using namespace std; class Point { protected: int x, y; //한 점 (x,y) 좌표값 public: void set(int x, int y); void showPoint(); }; void Point::set(int x, int y) { this->x = x; this->y = y; } void Point::showPoint() { cout << "(" << x << "," << y << ")" << endl; class ColorPoint : public Point { string color; void setColor(string color); void showColorPoint(); bool equals(ColorPoint p); void ColorPoint::setColor(string color) { this->color = color; void ColorPoint::showColorPoint() { cout << color << ":"; showPoint(); // Point 클래스의 showPoint() 호출 } bool ColorPoint::equals(ColorPoint p) { if(x == p.x && y == p.y && color == p.color) // ① return true; else return false; int main() { Point p; // 기본 클래스의 객체 생성 p.set(2,3); // ② p.x = 5; // ③ p.y = 5; // ④ p.showPoint(); ColorPoint cp; // 파생 클래스의 객체 생성 cp.x = 10; // ⑤ cp.y = 10; // ⑥ cp.set(3,4); cp.setColor("Red"); cp.showColorPoint(); ColorPoint cp2; cp2.set(3,4); cp2.setColor("Red"); cout << ((cp.equals(cp2))?"true":"false"); // ⑦ 오류 오류 오류 오류

상속 관계의 생성자와 소멸자 실행 질문 1 파생 클래스의 객체가 생성될 때 파생 클래스의 생성자와 기본 클래스의 생성자가 모두 실행되는가? 아니면 파생 클래스의 생 성자만 실행되는가? 답 - 둘 다 실행된다. 질문 2 파생 클래스의 생성자와 기본 클래스의 생성자 중에서 어떤 생성 자가 먼저 실행되는가? 답 - 기본 클래스의 생성자가 먼저 실행된 후 파생 클래스의 생성자 가 실행된다.

생성자 호출 관계 및 실행 순서 class A { public: A() { cout << "생성자 A" << endl; } ~A() { cout << "소멸자 A" << endl; } }; A() 실행  A() 호출  리턴 class B : public A { public: B() { cout << "생성자 B" << endl; } ~B() { cout << "소멸자 B" << endl; } }; B() 실행  B() 호출  리턴 생성자 A 생성자 B 생성자 C 소멸자 C 소멸자 B 소멸자 A int main() { C c; // c 생성 return 0; // c 소멸 } class C : public B { public: C() { cout << "생성자 C" << endl; } ~C() { cout << "소멸자 C"<< endl; } }; C() 호출  C() 실행  컴파일러는 C() 생성자 실행 코드를 만들때, 생성자 B()를 호출하는 코드 삽입

소멸자의 실행 순서 파생 클래스의 객체가 소멸될 때 파생 클래스의 소멸자가 먼저 실행되고 기본 클래스의 소멸자가 나중에 실행

컴파일러에 의해 묵시적으로 기본 클래스의 생성자를 선택하는 경우 파생 클래스의 생성자에서 기본 클래스의 기본 생성자 호출 class A { public: A() { cout << "생성자 A" << endl; } A(int x) { cout << "매개변수생성자 A" << x << endl; } }; 컴파일러는 묵시적으로 기본 클래스의 기본 생성자를 호출하도록 컴파일함 class B : public A { public: B() { // A() 호출하도록 컴파일됨 cout << "생성자 B" << endl; } }; int main() { B b; } 생성자 A 생성자 B

기본 클래스에 기본 생성자가 없는 경우 class A { public: A(int x) { cout << "매개변수생성자 A" << x << endl; } }; 컴파일러가 B()에 대한 짝으로 A()를 찾을 수 없음 컴파일 오류 발생 !!! class B : public A { public: B() { // A() 호출하도록 컴파일됨 cout << "생성자 B" << endl; } }; error C2512: ‘A' : 사용할 수 있는 적절한 기본 생성자가 없습니다. int main() { B b; }

매개 변수를 가진 파생 클래스의 생성자는 묵시적으로 기본 클래스의 기본 생성자 선택 파생 클래스의 매개 변수를 가진 생성자가 기본 클래스의 기본 생성자 호출 class A { public: A() { cout << "생성자 A" << endl; } A(int x) { cout << "매개변수생성자 A" << x << endl; } }; 컴파일러는 묵시적으로 기본 클래스의 기본 생성자를 호출하도록 컴파일함 class B : public A { public: B() { // A() 호출하도록 컴파일됨 cout << "생성자 B" << endl; } B(int x) { // A() 호출하도록 컴파일됨 cout << “매개변수생성자 B" << x << endl; }; int main() { B b(5); } 생성자 A 매개변수생성자 B5

파생 클래스의 생성자에서 명시적으로 기본 클래스의 생성자 선택 class A { public: A() { cout << "생성자 A" << endl; } A(int x) { cout << "매개변수생성자 A" << x << endl; } }; 파생 클래스의 생성자가 명시적으로 기본 클래스의 생성자를 선택 호출함 class B : public A { public: B() { // A() 호출하도록 컴파일됨 cout << "생성자 B" << endl; } B(int x) : A(x+3) { cout << “매개변수생성자 B" << x << endl; }; A(8) 호출 B(5) 호출 int main() { B b(5); } 매개변수생성자 A8 매개변수생성자 B5

컴파일러의 기본 생성자 호출 코드 삽입 class B { B() : A() { 컴파일러가 묵시적으로 삽입한 코드 class B { B() : A() { cout << "생성자 B" << endll; } B(int x) : A() { cout << "매개변수생성자 B" << x << endll; }; 컴파일러가 묵시적으로 삽입한 코드

예제 8-3 TV, WideTV, SmartTV 생성자 매개 변수 전달 #include <iostream> #include <string> using namespace std; class TV { int size; // 스크린 크기 public: TV() { size = 20; } TV(int size) { this->size = size; } int getSize() { return size; } }; class WideTV : public TV { // TV를 상속받는 WideTV bool videoIn; WideTV(int size, bool videoIn) : TV(size) { this->videoIn = videoIn; } bool getVideoIn() { return videoIn; } class SmartTV : public WideTV { // WideTV를 상속받는 SmartTV string ipAddr; // 인터넷 주소 SmartTV(string ipAddr, int size) : WideTV(size, true) { this->ipAddr = ipAddr; string getIpAddr() { return ipAddr; } int main() { // 32 인치 크기에 "192.0.0.1"의 인터넷 주소를 가지는 스마트 TV 객체 생성 SmartTV htv("192.0.0.1", 32); cout << "size=" << htv.getSize() << endl; cout << "videoIn=" << boolalpha << htv.getVideoIn() << endl; cout << "IP=“<<htv.getIpAddr() << endl; } 32 boolalpha는 불린 값을 true, false로 출력되게 하는 조작자 size=32 videoIn=true IP=192.0.0.1 32 true int size 32 TV영역 bool videoIn true WideTV영역 32 string ipAddr “192.0.0.1” SmartTV영역 “192.0.0.1” htv

상속 지정 상속 지정 상속 선언 시 public, private, protected의 3가지 중 하나 지정 기본 클래스의 멤버의 접근 속성을 어떻게 계승할지 지정 public – 기본 클래스의 protected, public 멤버 속성을 그대로 계승 private – 기본 클래스의 protected, public 멤버를 private으로 계승 protected – 기본 클래스의 protected, public 멤버를 protected로 계승

상속 시 접근 지정에 따른 멤버의 접근 지정 속성 변화 상속 후 Derived class Base { private: int a; protected: int b; public: int c; }; public 상속 class Derived : public Base { .... // Derived 멤버 }; protected: int b; public: int c; .... // Derived 멤버 Base 영역 Derived 영역 상속 후 Derived class Base { private: int a; protected: int b; public: int c; }; protected 상속 class Derived : protected Base { .... // Derived 멤버 }; protected: int b; int c; .... // Derived 멤버 Base 영역 Derived 영역 class Base { private: int a; protected: int b; public: int c; }; private 상속 class Derived : private Base { .... // Derived 멤버 }; 상속 후 Derived private: int b; int c; .... // Derived 멤버 Base 영역 Derived 영역

예제 8-4 private 상속 사례 다음에서 컴파일 오류가 발생하는 부분을 찾아라. #include <iostream> using namespace std; class Base { int a; protected: void setA(int a) { this->a = a; } public: void showA() { cout << a; } }; class Derived : private Base { int b; void setB(int b) { this->b = b; } void showB() { cout << b; } int main() { Derived x; x.a = 5; // ① x.setA(10); // ② x.showA(); // ③ x.b = 10; // ④ x.setB(10); // ⑤ x.showB(); // ⑥ } 컴파일 오류 ①, ②, ③, ④, ⑤

예제 8-5 protected 상속 사례 다음에서 컴파일 오류가 발생하는 부분을 찾아라. #include <iostream> using namespace std; class Base { int a; protected: void setA(int a) { this->a = a; } public: void showA() { cout << a; } }; class Derived : protected Base { int b; void setB(int b) { this->b = b; } void showB() { cout << b; } int main() { Derived x; x.a = 5; // ① x.setA(10); // ② x.showA(); // ③ x.b = 10; // ④ x.setB(10); // ⑤ x.showB(); // ⑥ } 컴파일 오류 ①, ②, ③, ④, ⑤

예제 8-6 상속이 중첩될 때 접근 지정 사례 다음에서 컴파일 오류가 발생하는 부분을 찾아라. #include <iostream> using namespace std; class Base { int a; protected: void setA(int a) { this->a = a; } public: void showA() { cout << a; } }; class Derived : private Base { int b; void setB(int b) { this->b = b; } void showB() { setA(5); // ① showA(); // ② cout << b; } class GrandDerived : private Derived { int c; protected: void setAB(int x) { setA(x); // ③ showA(); // ④ setB(x); // ⑤ } }; 컴파일 오류 ③, ④

class TextEditorInterpreter class Interpreter 컨버전스 다중상속 class TextEditorInterpreter

다중 상속 선언 및 멤버 호출 다중 상속 선언 다중 상속 활용 다중 상속 활용 class MP3 { public: void play(); void stop(); }; class MobilePhone { bool sendCall(); bool receiveCall(); bool sendSMS(); bool receiveSMS(); class MusicPhone : public MP3, public MobilePhone { // 다중 상속 선언 void dial(); 상속받고자 하는 기본 클래스를 나열한다. 다중 상속 선언 다중 상속 활용 void MusicPhone::dial() { play(); // mp3 음악을 연주시키고 sendCall(); // 전화를 건다. } MP3::play() 호출 MobilePhone::sendCall() 호출 int main() { MusicPhone hanPhone; hanPhone.play(); // MP3의 멤버 play() 호출 hanPhone.sendSMS(); // MobilePhone의 멤버 sendSMS() 호출 } 다중 상속 활용

예제 8-7 Adder와 Subtractor를 다중 상속 받는 Calculator 클래스 작성 // 다중 상속 class Calculator : public Adder, public Subtractor { public: int calc(char op, int a, int b); }; int Calculator::calc(char op, int a, int b) { int res=0; switch(op) { case '+' : res = add(a, b); break; case '-' : res = minus(a, b); break; } return res; #include <iostream> using namespace std; class Adder { protected: int add(int a, int b) { return a+b; } }; class Subtractor { int minus(int a, int b) { return a-b; } int main() { Calculator handCalculator; cout << "2 + 4 = " << handCalculator.calc('+', 2, 4) << endl; cout << "100 - 8 = " << handCalculator.calc('-', 100, 8) << endl; } 2 + 4 = 6 100 – 8 = 92

다중 상속의 문제점 - 기본 클래스 멤버의 중복 상속 다중 상속의 문제점 - 기본 클래스 멤버의 중복 상속 Base의 멤버가 이중으로 객체에 삽입되는 문제점. 동일한 x를 접근하는 프로그램이 서로 다른 x에 접근하는 결과를 낳게되어 잘못된 실행 오류가 발생된다.

가상 상속 다중 상속으로 인한 기본 클래스 멤버의 중복 상속 해결 가상 상속 파생 클래스의 선언문에서 기본 클래스 앞에 virtual로 선언 파생 클래스의 객체가 생성될 때 기본 클래스의 멤버는 오직 한 번만 생성 기본 클래스의 멤버가 중복하여 생성되는 것을 방지 class In : virtual public BaseIO { // In 클래스는 BaseIO 클래스를 가상 상속함 ... }; class Out : virtual public BaseIO { // Out 클래스는 BaseIO 클래스를 가상 상속함

가상 상속으로 다중 상속의 모호성 해결 가상 상속

실습문제 1. p. 408 문제 1-2. 원을 추상화한 Circle 클래스이다. class Circle { int radius; public: Circle(int radius=0) { this->radius = radius; } int getRadius() { return radius; } void setRadius(int radius) { this->radius = radius; } double getArea() { return 3.14*radius*radius; }; };

문제 1. 다음 코드가 실행되도록 Circle 클래스를 상속 받은 NamedCircle 클래스를 작성하고 전체 프 로그램을 완성하라. int main() { NamedCircle waffle(3, "waffle"); // 반지름이 3이고 이름이 waffle인 원 waffle.show(); } // NamedCircle 생성자에서 Circle 생성자호출!

문제 2. 다음과 같이 배열을 선언하여 다음 실행 결과 가 나오도록 Circle을 상속받는 NamedCircle 클래스와 main 함수 등 필요한 함수를 작성하 라.

int main() { NamedCircle c[5]; cout << "5 개의 정수 반지름과 원의 이름을 입력하세요" << endl; for(int i=0; i<5; i++) { int r; string name; cout << i+1 << ">> "; cin >> r; getline(cin, name); if(r <= 0) { cout << "다시 입력하세요" << endl; --; continue; } c[i].set(r, name); cout << "가장 면적이 큰 피자는 " << biggest(c, 5) << "입니다" << endl;

실습문제 : 8-9 비행기 항공권 예약 프로그램 - 메뉴 : 예약, 취소, 보기, 끝내기 - 스케듈 : 7시, 12시, 17시 - 좌석은 각 8개

AirlineBook.h class AirlineBook{ string name; // 예약 시스템 이름 int nSchedules; // 스케쥴 개수 Schedule *sche; // 스케쥴 배열 void book(); void cancel(); void view(); void view(int s); public: AirlineBook(string name, int nSchedules, string scheduleTime []); ~AirlineBook(); void run(); // 예약 시스템을 작동시키는 함수 };

Schedule.h class Seat; class Schedule{ string time; // 스케쥴 타임 Seat* seat; public: Schedule(); ~Schedule(); void book(int no, string name); void cancel(int no, string name); void view(); void setTime(string time); };

Seat.h class Seat{ string name; public: Seat(); void book(string name); bool isBooked(); void cancel(string name); void view(); };

Console.h class Console{ public: static int getMainMenu(); static int getScheduleMenu(); static string getName(); static int getSeatNo(); static void print(string); };

main.cpp #include <string> using namespace std; #include "AirlineBook.h" int main(){ string sheduleTime[] = {"7시", "12시", "17시"}; AirlineBook *p = new AirlineBook("한성항공", 3, sheduleTime); p->run(); delete p; }

AirlineBook.cpp #include <iostream> using namespace std; #include <string> #include "AirlineBook.h" #include "Schedule.h" #include "Console.h" // 생성자 AirlineBook::AirlineBook(string name, int nSchedules, string scheduleTime[]){ this->name = name; // 예약 시스템 이름 this->nSchedules = nSchedules; // 스케쥴 개수 sche = new Schedule[nSchedules]; // 3 개의 스케쥴 객체 생성 // 각 스케쥴에 해당 시간 설정 for(int i=0; i<nSchedules; i++) sche[i].setTime(scheduleTime[i]); } // 소멸자 AirlineBook::~AirlineBook(){ if(sche) delete [] sche;

AirlineBook.cpp // 예약 시스템을 시작하는 함수 void AirlineBook::run(){ cout << "*** " << name << "에 오신것을 환영합니다." << " ***" << endl; cout << endl; while(true){ int menu = Console::getMainMenu(); // 메인 메뉴 입력 switch(menu){ case 1: book(); // 예약 break; case 2: cancel(); // 예약 case 3: view(); // 예약 보기 case 4: cout << "예약 시스템을 종료합니다.\n"<<endl; return; default: cout << "잘못입력하였습니다.\n"<<endl; }

AirlineBook.cpp // 스케쥴을 예약한다. void AirlineBook::book(){ int s; string bookName; int seatNo; s = Console::getScheduleMenu(); // 사용자가 선택한 스케쥴을 입력 받는다. view(s); // 스케쥴 s의 예약 상황을 출력한다. seatNo = Console::getSeatNo(); // 좌석 번호를 입력받는다. bookName = Console::getName(); // 예약자의 이름을 입력받는다. sche[s-1].book(seatNo, bookName); // 해당 스케쥴 예약 }

AirlineBook.cpp // 스케쥴을 취소한다. void AirlineBook::cancel(){ int s; string bookName; int seatNo; s = Console::getScheduleMenu(); // 사용자가 선택한 스케쥴을 입력. view(s); // 스케쥴 s의 예약 상황을 출력한다. seatNo = Console::getSeatNo(); // 좌석 번호를 입력받는다. bookName = Console::getName(); // 예약자의 이름을 입력받는다. sche[s-1].cancel(seatNo, bookName); // 해당 스케쥴 취소 }

AirlineBook.cpp // 현재 모든 스케쥴의 예약 상황을 출력한다. void AirlineBook::view(){ for(int i=0;i<3;i++){ sche[i].view(); } cout << endl; // 스케쥴 s의 좌석 예약 상황을 출력한다. s는 1,2,3 void AirlineBook::view(int s){ sche[s-1].view(); //배열의 인덱스는 0부터 시작

Console.cpp #include <iostream> using namespace std; #include <string> #include <cstring> #include "Console.h" int Console::getMainMenu(){ cout << "예약:1, 취소:2, 보기:3, 끝내기:4 >>" ; int menu; cin >> menu; return menu; } int Console::getScheduleMenu(){ cout << "7시:1, 12시:2, 17시:3 >>" ;

Console.cpp string Console::getName(){ cout << "이름 입력 >>"; string name; cin >> name; return name; } int Console::getSeatNo(){ cout << "좌석 번호 >>" ; int no; cin >> no; return no; void Console::print(string msg) { cout << msg;