Presentation is loading. Please wait.

Presentation is loading. Please wait.

명품 C++ 9장 가상 함수와 추상 클래스.

Similar presentations


Presentation on theme: "명품 C++ 9장 가상 함수와 추상 클래스."— Presentation transcript:

1 명품 C++ 9장 가상 함수와 추상 클래스

2 예제 9-1 상속 관계에서 함수를 중복하는 경우 #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

3 가상 함수와 오버라이딩 가상 함수(virtual function) 함수 오버라이딩(function overriding)
동적 바인딩 지시어 컴파일러에게 함수에 대한 호출 바인딩을 실행 시간까지 미루도록 지시 함수 오버라이딩(function overriding) 파생 클래스에서 기본 클래스의 가상 함수와 동일한 이름의 함수 선 언 기본 클래스의 가상 함수의 존재감 상실시킴 파생 클래스에서 오버라이딩한 함수가 호출되도록 동적 바인딩 함수 재정의라고도 부름 다형성의 한 종류 class Base { public: virtual void f(); // f()는 가상 함수 };

4 오버라이딩 개념

5 오버로딩과 오버라이딩 사례 비교 오버로딩 오버라이딩 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; 가상 함수 오버라이딩 오버로딩 오버라이딩 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()가 호출됨

6 예제 9–2 오버라이딩과 가상 함수 호출 void f() void f() void f()
존재감 상실 객체 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

7 오버라이딩의 목적 –파생 클래스에서 구현할 함수 인터페이스 제공(파생 클래스의 다형성)
다형성의 실현 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() 호출

8 동적 바인딩 동적 바인딩 파생 클래스에 대해 기본 클래스에 대한 포인터로 가상 함수를 호출하는 경우
객체 내에 오버라이딩한 파생 클래스의 함수를 찾아 실행 실행 중에 이루어짐 실행시간 바인딩, 런타임 바인딩, 늦은 바인딩으로 불림 동적바인딩 function1() virtual function2() ...... Base Base *p= &obj; p->function2(); 상속 실행 function2() ...... Derived obj

9 오버라이딩된 함수를 호출하는 동적 바인딩 void draw() #include <iostream>
using namespace std; class Shape { public: void paint() { draw(); } virtual void draw() { cout << "Shape::draw() called" << endl; }; class Circle : public Shape { cout << "Circle::draw() called" << endl; int main() { Shape *pShape = new Circle(); // 업캐스팅 pShape->paint(); delete pShape; 기본 클래스에서 파생 클래스의 함수를 호출하게 되는 사례 #include <iostream> using namespace std; class Shape { public: void paint() { draw(); } virtual void draw() { cout << "Shape::draw() called" << endl; }; int main() { Shape *pShape = new Shape(); pShape->paint(); delete pShape; Shape::draw() called Circle::draw() called pShape = new Shape(); pShape->paint(); pShape = new Circle(); pShape->paint(); 동적바인딩 pShape void paint() pShape Shape 멤버 void paint() Shape 멤버 void draw() void draw() new Shape() Circle 멤버 void draw() new Circle()

10 C++ 오버라이딩의 특징 오버라이딩의 성공 조건 오버라이딩 시 virtual 지시어 생략 가능 가상 함수의 접근 지정
가상 함수 이름, 매개 변수 타입과 개수, 리턴 타입이 모두 일치 오버라이딩 시 virtual 지시어 생략 가능 가상 함수의 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()와 동일한 선언 생략 가능

11 예제 9-3 상속이 반복되는 경우 가상 함수 호출 Base, Derived, GrandDerived가 상속 관계에 있을 때,
다음 코드를 실행한 결과는 무엇인가? 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(); } 동적 바인딩 bp->f(); Base 멤버 void f() dp->f(); Derived 멤버 void draw() void f() GrandDerived 멤버 gp->f(); void f() GrandDerived g; 동적 바인딩에 의해 모두 GrandDerived의 함수 f() 호출 GrandDerived::f() called

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

13 예제 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--

14 가상 소멸자 가상 소멸자 소멸자를 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() 실행 소멸자가 가상 함수가 아닌 경우 가상 소멸자 경우

15 예제 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;

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

17 가상 함수와 오버라이딩 활용 사례 가상 함수를 가진 기본 클래스의 목적 가상 함수 오버라이딩 동적 바인딩 실행
기본 클래스의 포인터 활용

18 1. 가상 함수를 가진 기본 클래스의 목적 Shape은 상속을 위한 기본 클래스로의 역할
Shape.cpp Shape은 상속을 위한 기본 클래스로의 역할 가상 함수 draw()로 파생 클래스의 인터페이스를 보여줌 Shape 객체를 생성할 목적 아님 파생 클래스에서 draw() 재정의 자신의 도형을 그리도록 유도 #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.h class Shape { Shape* next; protected: virtual void draw(); public: Shape() { next = NULL; } virtual ~Shape() { } void paint(); Shape* add(Shape* p); Shape* getNext() { return next;} }; 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> #include "Shape.h" #include "Circle.h" using namespace std; void Circle::draw() { cout << "Circle" << endl; } #include <iostream> #include "Shape.h" #include "Rect.h" using namespace std; void Rect::draw() { cout << "Rectangle" << endl; } #include <iostream> #include "Shape.h" #include "Line.h" using namespace std; void Line::draw() { cout << "Line" << endl; } Circle.cpp Rect.cpp Line.cpp

19 2. 가상 함수 오버라이딩 파생 클래스마다 다르게 구현하는 다형성 파생 클래스에서 가상 함수 draw()의 재정의
동적 바인딩에 의해 void Circle::draw() { cout << "Circle" << endl; } void Rect::draw() { cout << "Rectangle" << endl; } void Line::draw() { cout << "Line" << endl; }

20 3. 동적 바인딩 실행 : 파생 클래스의 가상 함수실행
#include <iostream> #include "Shape.h" #include "Circle.h" #include "Rect.h" #include "Line.h" using namespace std; int main() { Shape *pStart=NULL; Shape *pLast; pStart = new Circle(); // 처음에 원 도형을 생성한다. pLast = pStart; pLast = pLast->add(new Rect()); // 사각형 객체 생성 pLast = pLast->add(new Circle()); // 원 객체 생성 pLast = pLast->add(new Line()); // 선 객체 생성 // 현재 연결된 모든 도형을 화면에 그린다. Shape* p = pStart; while(p != NULL) { p->paint(); p = p->getNext(); } 다음 페이지 그림 참조 // 현재 연결된 모든 도형을 삭제한다. p = pStart; while(p != NULL) { Shape* q = p->getNext(); // 다음 도형 주소 기억 delete p; // 기본 클래스의 가상 소멸자 호출 p = q; // 다음 도형 주소를 p에 저장 } Circle Rectangle Line

21 main() 함수가 실행될 때 구성된 객체의 연결
pLast p pStart next next next next next .... .... .... .... .... void paint() void paint() void paint() void paint() void paint() void draw() void draw() void draw() void draw() void draw() void draw() void draw() void draw() void draw() Line 객체 void draw() Circle 객체 Circle 객체 Rect 객체 Rect 객체 Shape* p = pStart; while(p != NULL) { p->paint(); p = p->getNext(); }

22 4. 기본 클래스의 포인터 활용 기본 클래스의 포인터로 파생 클래스 접근 pStart, pLast, p의 타입이 Shape*
p->paint()의 간단한 호출로 파생 객체에 오버라이딩된 draw() 함수 호출

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

24 추상 클래스 추상 클래스 : 최소한 하나의 순수 가상 함수를 가진 클래스 추상 클래스의 특징
추상 클래스 : 최소한 하나의 순수 가상 함수를 가진 클래스 추상 클래스의 특징 온전한 클래스가 아니므로 객체 생성 불가능 추상 클래스의 포인터는 선언 가능 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;

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

26 추상 클래스의 상속과 구현 추상 클래스의 상속 추상 클래스의 구현 추상 클래스를 단순 상속하면 자동 추상 클래스
추상 클래스를 상속받아 순수 가상 함수를 오버라이딩 파생 클래스는 추상 클래스가 아님 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은 추상 클래스 아님 순수 가상 함수 오버라이딩 추상 클래스의 단순 상속 추상 클래스의 구현

27 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.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

28 예제 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는 배열의 크기 }; #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; } }; 순수 가상 함수 구현 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

29 예제 9-7(실습) 추상 클래스를 상속받는 파생 클래스 구현 연습
#include <iostream> using namespace std; class Calculator { void input() { cout << "정수 2 개를 입력하세요>> "; cin >> a >> b; } protected: int a, b; virtual int calc(int a, int b) = 0; // 두 정수의 합 리턴 public: void run() { input(); cout << "계산된 값은 " << calc(a, b) << endl; }; int main() { Adder adder; Subtractor subtractor; adder.run(); subtractor.run(); 다음 코드와 실행 결과를 참고하여 추상 클래스 Calculator를 상속받는 Adder와 Subractor 클래스를 구현하라. adder.run()에 의한 실행 결과 정수 2 개를 입력하세요>> 5 3 계산된 값은 8 계산된 값은 2 subtractor.run()에 의한 실행 결과

30 예제 9-7 정답 class Adder : public Calculator { protected:
int calc(int a, int b) { // 순수 가상 함수 구현 return a + b; } }; class Subtractor : public Calculator { return a - b;

31 실습문제 7-8 사각형에 내접하는 도형을 표현하기 위한Shape 클래 스가 다음과 같다. class Shape {
protected: string name; // 도형의 이름 int width, height; // 도형이 내접하는 사각형의 너비와 높이 public: Shape(string n="", int w=0, int h=0) { name = n; width = w; height = h; } virtual double getArea() { return 0; } // dummy 값 리턴 string getName() { return name; } // 이름 리턴 };

32 7. Shape 클래스를 상속받아 타원을 표현하는 Oval, 사각형을 표현 하는 Rect, 삼각형을 표현하는 Triangular 클래스를 작성하라. main 함수를 실행하면 다음과 같은 결과가 되게하라. int main() { Shape *p[3]; p[0] = new Oval("빈대떡", 10, 20); p[1] = new Rect("찰떡", 30, 40); p[2] = new Triangular("토스트", 30, 40); for(int i=0; i<3; i++) cout << p[i]->getName() << " 넓이는 " << p[i]->getArea() << endl; for(int i=0; i<3; i++) delete p[i]; }

33 8. 추상클래스 만들기 문제 7의 Shape 클래스를 추상클래스로 만들 고 문제 7을 다시 작성하라.

34 10. 그래픽편집기 간단한 그래픽 편집기를 콘솔 바탕으로 작성하 자. 기능은 “삽입”, “삭제”, “모두보기”, “종료” 4 가지이다. 실행과정은 다음과 같다.

35 main.cpp int main() { GraphicEditor *g = new GraphicEditor();
g->run(); delete g; }

36 GraphicEditor.h #ifndef GRAPHICEDITOR_H #define GRAPHICEDITOR_H
class Shape; class GraphicEditor { enum {LINE=1, CIRCLE=2, RECT=3}; enum {EDIT=1, REMOVE=2, PAINT=3, EXIT=4}; Shape* pStart; Shape* pLast; void add(Shape* p); protected: void paint(); void edit(); void remove(int shapeIndex); void remove(); public: GraphicEditor(); ~GraphicEditor(); void run(); }; #endif GraphicEditor.h

37 GraphicEditor.cpp #include <iostream> using namespace std;
#include "GraphicEditor.h" #include "Shape.h" #include "UI.h" #include "Line.h" #include "Circle.h" #include "Rect.h“ GraphicEditor::GraphicEditor() { pStart = NULL; pLast = NULL; } GraphicEditor::~GraphicEditor() { // 소멸자 // 현재 생성된 모든 객체를 삭제한다. Shape* p = pStart; while(p != NULL) { Shape* q = p->getNext(); // 다음 객체위치를 저장한다. delete p; // 현재 객체를 삭제한다. p = q; // 다음 객체를 가리킨다. GraphicEditor.cpp

38 void GraphicEditor::paint() {
// 현재 생성된 모든 객체를 그린다. Shape* p = pStart; if(p == NULL) { UI::println("그려진 도형이 없습니다."); return; } int i=0; // 처음부터 끝까지 루프를 따라 그려진 도형을 그린다. while(p != NULL) { UI::print(i); // 인덱스 출력 UI::print(": "); p->paint(); // 도형 그리기 p = p->getNext(); // 다음 도형을 가리킨다. i++;

39 void GraphicEditor::run() { // 그래픽 에디터의 메인 함수
UI::println("그래픽 에디터입니다."); while(true) { int menu = UI::getMainMenu(); switch(menu) { case EDIT: // 삽입 edit(); break; case REMOVE: // 삭제 remove(); break; case PAINT: // 다시 그리기 paint(); break; case EXIT: // 끝내기 return; default: UI::println("명령 선택 오류"); }

40 void GraphicEditor::edit() {
int shapeType = UI::getShapeType(); switch(shapeType) { case LINE: // 라인 add(new Line()); break; case CIRCLE: // 원 add(new Circle()); break; case RECT: // 사각형 add(new Rect()); break; default: UI::println("도형 선택 오류"); }

41 void GraphicEditor::remove() {
int shapeIndex = UI::getShapeIndex(); remove(shapeIndex); }

42 void GraphicEditor::remove(int shapeIndex) { // shapeIndex의 원소를 삭제한다.
if(pLast == NULL) { UI::println("그려진 도형이 없습니다."); return; } int i=0; Shape* p = pStart; Shape* beforeP = pStart; while(i<shapeIndex) { i++; beforeP = p; p = p->getNext(); // 다음 객체를 가리킨다. if(p == NULL) { // shapeIndex가 도형의 개수보다 큼 UI::println("도형의 인덱스가 개수보다 큽니다."); return; } } // p는 삭제할 도형에 대한 포인터 Shape* pNext = beforeP->add(p->getNext()); delete p; if(p == pStart) // 삭제한 도형이 첫 도형인 경우 pStart = pNext; if(p == pLast) { // 삭제한 도형이 마지막 도형인 경우 if(pStart == NULL) // 삭제한 도형이 처음이자 마지막인 경우 pLast = NULL; else pLast = beforeP; }

43 void GraphicEditor::add(Shape* p) {
if(pStart == NULL) { // 처음으로 도형 객체를 생성하였을 때 pStart = p; pLast = p; return; } else { pLast->add(p); // 도형 p를 마지막에 단다. pLast = p; // pLast가 마지막 도형으로 조정한다.

44 UI.h #ifndef UI_H #define UI_H #include <string>
using namespace std; class UI { public: static int getMainMenu(); static int getShapeType(); static int getShapeIndex(); static void println(string); static void print(string); static void print(int); }; #endif

45 UI.cpp #include <iostream> using namespace std; #include "UI.h"
int UI::getMainMenu() { cout << "삽입:1, 삭제:2, 모두보기:3, 종료:4 >> "; int menu; cin >> menu; return menu; } int UI::getShapeType() { cout << "선:1, 원:2, 사각형:3 >> "; int shapeType; cin >> shapeType; return shapeType;

46 int UI::getShapeIndex() {
cout << "삭제하고자 하는 도형의 인덱스 >> "; int shapeIndex; cin >> shapeIndex; return shapeIndex; } void UI::println(string msg) { cout << msg << endl; void UI::print(string msg) { cout << msg; void UI::print(int msg) {

47 shape.h #ifndef SHAPE_H #define SHAPE_H class Shape { Shape* next;
protected: virtual void draw() = 0; public: Shape() { next = NULL; } void paint(); Shape* getNext() { return next; } Shape* add(Shape* p) { next = p; return p; } }; #endif

48 Shape.cpp #include <iostream> using namespace std;
#include "Shape.h" void Shape::paint() { draw(); }


Download ppt "명품 C++ 9장 가상 함수와 추상 클래스."

Similar presentations


Ads by Google