430 likes | 610 Views
다형성. 다중 상속 - 가상 상속 추상 자료형 순수 가상함수. Pegasus class 의 지원. Pegasus class 의 지원 말로 부터 파생 : Fly( ) 함수는 복사 말과 조류의 양쪽 목록에 등록할 수 없음 Fly( ) 함수가 두 군데에 존재 : 유지 보수 어려움. 표유류. 말. 새. Gallop( ) Whinny( ). Fly( ). Pegasus. ?. 다중 상속. 상승 (Percolating Upward). 상승
E N D
다형성 다중 상속 - 가상 상속 추상 자료형 순수 가상함수
Pegasus class의 지원 • Pegasus class의 지원 • 말로 부터 파생 : Fly( ) 함수는 복사 • 말과 조류의 양쪽 목록에 등록할 수 없음 • Fly( ) 함수가 두 군데에 존재 : 유지 보수 어려움 표유류 말 새 Gallop( ) Whinny( ) Fly( ) Pegasus ? 다중 상속
상승 (Percolating Upward) • 상승 • 필요로 하는 함수( Fly( ) )를 한 단계 상위 클래스 계층으로 상승 • 상승 사용시의 원칙 • 공통되는 기능은 상승 • 몇 개의 파생클래스에서만 쓰는 접속 부분은 상승 시키지 않음
#include <iostream> • using namespace std; • class Horse • { • public: • void Gallop(){ cout << "Galloping...\n"; } • virtual void Fly() { cout << "Horses can't fly.\n" ; } • private: • int itsAge; • }; • class Pegasus : public Horse • { • public: • virtual void Fly() • {cout<<"I can fly! I can fly! I can fly!\n";} • }; list 14.1
const int NumberHorses = 5; • int main() • { • Horse* Ranch[NumberHorses]; • Horse* pHorse; • int choice,i; • for (i=0; i<NumberHorses; i++) • { • cout << "(1)Horse (2)Pegasus: "; • cin >> choice; • if (choice == 2) • pHorse = new Pegasus; • else • pHorse = new Horse; • Ranch[i] = pHorse; • } • cout << "\n"; • for (i=0; i<NumberHorses; i++) • { • Ranch[i]->Fly(); • delete Ranch[i]; • } • return 0; • }
형 변환 하향 (casting down) • RTTI ( Run Time Type Identification) • 실행 시 형 식별 • C++에서 공식적으로 사용되는 추세 dynamic_cast < 형 > 변수명 • 변환이 적절한 경우 형변환 • 적절하지 않으면 널포인터로 채움
#include <iostream> • using namespace std; • enum TYPE { HORSE, PEGASUS }; • class Horse • { • public: • virtual void Gallop(){ cout << "Galloping...\n"; } • private: • int itsAge; • }; • class Pegasus : public Horse • { • public: • virtual void Fly() • {cout<<"I can fly! I can fly! I can fly!\n";} • }; list 14.2
const int NumberHorses = 5; • int main() • { • Horse* Ranch[NumberHorses]; • Horse* pHorse; int choice,i; • for (i=0; i<NumberHorses; i++) • { • cout << "(1)Horse (2)Pegasus: "; • cin >> choice; • if (choice == 2) • pHorse = new Pegasus; • else • pHorse = new Horse; • Ranch[i] = pHorse; • } • for (i=0; i<NumberHorses; i++) • { • Pegasus *pPeg = • dynamic_cast< Pegasus *> (Ranch[i]); • if (pPeg) • pPeg->Fly(); • else • cout << "Just a horse\n"; • delete Ranch[i]; • } • return 0; • }
다중 상속 (Multiple Inheritance) • 다중 상속 • 하나 이상의 기본 클래스로부터 파생 클래스를 만드는 것 • 각 기본 클래스를 쉼표로 분리 • 메모리에 만들어질 때 모든 기본 클래스가 파생 클래스를 구성하게 됨 class Pegasus : public Horse, public Bird Horse Bird Pegasus
#include <iostream> • using namespace std; • class Horse • { • public: • Horse() { cout << "Horse constructor... "; } • virtual ~Horse() { cout << "Horse destructor... "; } • virtual void Whinny() const { cout << "Whinny!... "; } • private: • int itsAge; • }; • class Bird • { • public: • Bird() { cout << "Bird constructor... "; } • virtual ~Bird() { cout << "Bird destructor... "; } • virtual void Chirp() const { cout << "Chirp... "; } • virtual void Fly() const • { • cout << "I can fly! I can fly! I can fly! "; • } • private: • int itsWeight; • }; list 14.3
class Pegasus : public Horse, public Bird • { • public: • void Chirp() const { Whinny(); } • Pegasus() { cout << "Pegasus constructor... "; } • ~Pegasus() { cout << "Pegasus destructor... "; } • };
const int MagicNumber = 2; • int main() • { • Horse* Ranch[MagicNumber]; • Bird* Aviary[MagicNumber]; • Horse * pHorse; • Bird * pBird; • int choice,i; • for (i=0; i<MagicNumber; i++){ • cout << "\n(1)Horse (2)Pegasus: "; • cin >> choice; • if (choice == 2) • pHorse = new Pegasus; • else • pHorse = new Horse; • Ranch[i] = pHorse; • } • for (i=0; i<MagicNumber; i++){ • cout << "\n(1)Bird (2)Pegasus: "; • cin >> choice; • if (choice == 2) • pBird = new Pegasus; • else • pBird = new Bird; • Aviary[i] = pBird; • }
cout << "\n"; • for (i=0; i<MagicNumber; i++) • { • cout << "\nRanch[" << i << "]: " ; • Ranch[i]->Whinny(); • delete Ranch[i]; • } • for (i=0; i<MagicNumber; i++) • { • cout << "\nAviary[" << i << "]: " ; • Aviary[i]->Chirp(); • Aviary[i]->Fly(); • delete Aviary[i]; • } • return 0; • }
#include <iostream> • using namespace std; • typedef int HANDS; • enum COLOR { Red, Green, Blue, Yellow, • White, Black, Brown } ; • class Horse • { • public: • Horse(COLOR color, HANDS height); • virtual ~Horse() { cout << "Horse destructor...\n"; } • virtual void Whinny()const { cout << "Whinny!... "; } • virtual HANDS GetHeight() const { return itsHeight; } • virtual COLOR GetColor() const { return itsColor; } • private: • HANDS itsHeight; • COLOR itsColor; • }; • Horse::Horse(COLOR color, HANDS height): • itsColor(color),itsHeight(height) • { • cout << "Horse constructor...\n"; • } list 14.4
class Bird • { • public: • Bird(COLOR color, bool migrates); • virtual ~Bird() {cout << "Bird destructor...\n"; } • virtual void Chirp()const { cout << "Chirp... "; } • virtual void Fly()const • { • cout << "I can fly! I can fly! I can fly! "; • } • virtual COLOR GetColor()const { return itsColor; } • virtual bool GetMigration() const • { return itsMigration; } • private: • COLOR itsColor; • bool itsMigration; • }; • Bird::Bird(COLOR color, bool migrates): • itsColor(color), itsMigration(migrates) • { • cout << "Bird constructor...\n"; • }
class Pegasus : public Horse, public Bird • { • public: • void Chirp()const { Whinny(); } • Pegasus(COLOR, HANDS, bool,long); • ~Pegasus() {cout << "Pegasus destructor...\n";} • virtual long GetNumberBelievers() const • { • return itsNumberBelievers; • } • private: • long itsNumberBelievers; • }; • Pegasus::Pegasus( • COLOR aColor, • HANDS height, • bool migrates, • long NumBelieve): • Horse(aColor, height), • Bird(aColor, migrates), • itsNumberBelievers(NumBelieve) • { • cout << "Pegasus constructor...\n"; • }
int main() • { • Pegasus *pPeg = new Pegasus(Red, 5, true, 10); • pPeg->Fly(); • pPeg->Whinny(); • cout << "\nYour Pegasus is " << pPeg->GetHeight(); • cout << " hands tall and "; • if (pPeg->GetMigration()) • cout << "it does migrate."; • else • cout << "it does not migrate."; • cout << "\nA total of " • << pPeg->GetNumberBelievers(); • cout << " people believe it exists.\n"; • delete pPeg; • return 0; • }
다중 상속 (cont.) • 모호성 • 리스트 14.4에서 Horse와 Bird는 각각 자신만의 고유한 istColor 변수와 GetColor( )를 가짐 • 따라서, 상속 받은 Pegasus는 모호성을 가지게 됨 • 함수나 자료 앞에 기본 클래스 이름을 씀으로써 이를 해결 • Pegasus에서 GetColor( ) 함수를 재생 COLOR currentColor = pPeg->GetColor( ); (X) COLOR currentColor = pPeg->Horse::GetColor( ); (O) virtual COLOR GetColor( ) const { return Horse :: itsColor;} (X)
가상 상속 • 공유된 기본 클래스로부터 상속 • 공유된 기본 클래스(Animal)에서 함수나 자료가 호출될 때 모호성 발생 Animal Animal Horse Bird Pegasus
#include <iostream> • using namespace std; • typedef int HANDS; • enum COLOR { Red, Green, Blue, Yellow, • White, Black, Brown } ; • class Animal • { • public: • Animal(int); • virtual ~Animal() { cout << "Animal destructor...\n"; } • virtual int GetAge() const { return itsAge; } • virtual void SetAge(int age) { itsAge = age; } • private: • int itsAge; • }; • Animal::Animal(int age): • itsAge(age) • { • cout << "Animal constructor...\n"; • } list 14.5
class Horse : public Animal • { • public: • Horse(COLOR color, HANDS height, int age); • virtual ~Horse() { cout << "Horse destructor...\n"; } • virtual void Whinny() const { cout << "Whinny!... "; } • virtual HANDS GetHeight() const { return itsHeight; } • virtual COLOR GetColor() const { return itsColor; } • protected: • HANDS itsHeight; • COLOR itsColor; • }; • Horse::Horse(COLOR color, HANDS height, int age): • Animal(age), • itsColor(color),itsHeight(height) • { • cout << "Horse constructor...\n"; • }
class Bird : public Animal • { • public: • Bird(COLOR color, bool migrates, int age); • virtual ~Bird() {cout << "Bird destructor...\n"; } • virtual void Chirp() const { cout << "Chirp... "; } • virtual void Fly() const • { cout << "I can fly! I can fly! I can fly! "; } • virtual COLOR GetColor() const { return itsColor; } • virtual bool GetMigration() const { return itsMigration; } • protected: • COLOR itsColor; • bool itsMigration; • }; • Bird::Bird(COLOR color, bool migrates, int age): • Animal(age), • itsColor(color), itsMigration(migrates) • { • cout << "Bird constructor...\n"; • }
class Pegasus : public Horse, public Bird • { • public: • void Chirp() const { Whinny(); } • Pegasus(COLOR, HANDS, bool, long, int); • virtual ~Pegasus() • {cout << "Pegasus destructor...\n";} • virtual long GetNumberBelievers() const • { return itsNumberBelievers; } • virtual COLOR GetColor() const • { return Horse::itsColor; } • virtual int GetAge() const { return Horse::GetAge(); } • private: • long itsNumberBelievers; • }; • Pegasus::Pegasus( • COLOR aColor, HANDS height, • bool migrates, long NumBelieve, int age): • Horse(aColor, height,age), • Bird(aColor, migrates,age), • itsNumberBelievers(NumBelieve) • { • cout << "Pegasus constructor...\n"; • }
int main() • { • Pegasus *pPeg = new Pegasus(Red, 5, true, 10, 2); • int age = pPeg->GetAge(); • cout << "This pegasus is " << age << " years old.\n"; • delete pPeg; • return 0; • }
가상 상속 (cont.) • 가상 상속 • 위의 그림과 같이 단일 공통 클래스 가능해짐 • 실질적인 변화는 Pegasus에서 발생 • 가상 기본 클래스를 사용할 때 가장 최근에 파생된 클래스로부터 공통 기본 클래스를 초기화 • Animal은 Horse와 Bird로 초기화되지 않고 Pegasus의 것으로 초기화 가상기본클래스 Animal 가상상속 가상상속 Horse Bird Pegasus
#include <iostream> • using namespace std; • typedef int HANDS; • enum COLOR { Red, Green, Blue, Yellow, • White, Black, Brown } ; • class Animal • { • public: • Animal(int); • virtual ~Animal() { cout << "Animal destructor...\n"; } • virtual int GetAge() const { return itsAge; } • virtual void SetAge(int age) { itsAge = age; } • private: • int itsAge; • }; • Animal::Animal(int age): • itsAge(age) • { • cout << "Animal constructor...\n"; • } list 14.6
class Horse : virtual public Animal • { • public: • Horse(COLOR color, HANDS height, int age); • virtual ~Horse() { cout << "Horse destructor...\n"; } • virtual void Whinny() const { cout << "Whinny!... "; } • virtual HANDS GetHeight() const { return itsHeight; } • virtual COLOR GetColor() const { return itsColor; } • protected: • HANDS itsHeight; • COLOR itsColor; • }; • Horse::Horse(COLOR color, HANDS height, int age): • Animal(age), • itsColor(color),itsHeight(height) • { • cout << "Horse constructor...\n"; • }
class Bird : virtual public Animal • { • public: • Bird(COLOR color, bool migrates, int age); • virtual ~Bird() {cout << "Bird destructor...\n"; } • virtual void Chirp() const { cout << "Chirp... "; } • virtual void Fly() const • { cout << "I can fly! I can fly! I can fly! "; } • virtual COLOR GetColor() const { return itsColor; } • virtual bool GetMigration() const { return itsMigration; } • protected: • COLOR itsColor; • bool itsMigration; • }; • Bird::Bird(COLOR color, bool migrates, int age): • Animal(age), • itsColor(color), itsMigration(migrates) • { • cout << "Bird constructor...\n"; • }
class Pegasus : public Horse, public Bird • { • public: • void Chirp() const { Whinny(); } • Pegasus(COLOR, HANDS, bool, long, int); • virtual ~Pegasus() • {cout << "Pegasus destructor...\n";} • virtual long GetNumberBelievers() const • { return itsNumberBelievers; } • virtual COLOR GetColor() const • { return Horse::itsColor; } • // virtual int GetAge() const { return Horse::GetAge(); } • private: • long itsNumberBelievers; • }; • Pegasus::Pegasus( • COLOR aColor, HANDS height, • bool migrates, long NumBelieve, int age): • Horse(aColor, height,age), • Bird(aColor, migrates,age), • Animal(age*2), • itsNumberBelievers(NumBelieve) • { • cout << "Pegasus constructor...\n"; • }
int main() • { • Pegasus *pPeg = new Pegasus(Red, 5, true, 10, 2); • int age = pPeg->GetAge(); • cout << "This pegasus is " << age << " years old.\n"; • delete pPeg; • return 0; • }
추상 자료형 (Abstract Data Type) • 추상 자료형 • 자신으로부터 파생된 클래스에게 인터페이스만 제공하기 위해 존재 • 객체를 나타내기 보다는 개념을 나타냄 • 항상 다른 클래스에 대한 기본 클래스로 사용 • 추상 자료형의 객체를 만들 수 없음 • 순수가상함수가 하나라도 존재하는 클래스 • 순수가상함수 • 가상함수를 0으로 초기화 • 하나 이상의 순수가상함수를 가진 클래스는 추상 자료형 • 추상자료 형으로부터 파생된 모든 클래스는 순수가상함수를 그대로 상속함. 따라서, 객체를 실체화하는 방법은 오직 순수가상함수의 재생을 통해서만 가능 virtual void Draw( ) = 0; • 순수가상함수를 가진 클래스는 객체를 만들지 말 것 • 순수가상함수는 재생하여 사용할 것
#include <iostream> • using std::cout; • using std::cin; • using std::endl; • class Shape • { • public: • Shape(){} • virtual ~Shape(){} • virtual long GetArea() { return -1; } // error • virtual long GetPerim() { return -1; } • virtual void Draw() {} • private: • }; list 14.7
class Circle : public Shape • { • public: • Circle(int radius):itsRadius(radius){} • ~Circle(){} • long GetArea() { return 3 * itsRadius * itsRadius; } • long GetPerim() { return 6 * itsRadius; } • void Draw(); • private: • int itsRadius; • int itsCircumference; • }; • void Circle::Draw() • { • cout << "Circle drawing routine here!\n"; • }
class Rectangle : public Shape • { • public: • Rectangle(int len, int width): • itsLength(len), itsWidth(width){} • virtual ~Rectangle(){} • virtual long GetArea() { return itsLength * itsWidth; } • virtual long GetPerim() • {return 2*itsLength + 2*itsWidth; } • virtual int GetLength() { return itsLength; } • virtual int GetWidth() { return itsWidth; } • virtual void Draw(); • private: • int itsWidth; • int itsLength; • }; • void Rectangle::Draw() • { • for (int i = 0 ; i<itsLength ; i++) • { • for (int j = 0 ; j<itsWidth ; j++) • cout << "x "; • cout << "\n"; • } • }
class Square : public Rectangle • { • public: • Square(int len); • Square(int len, int width); • ~Square(){ } • long GetPerim() {return 4 * GetLength();} • }; • Square::Square(int len): • Rectangle(len,len) • { } • Square::Square(int len, int width): • Rectangle(len,width) • { • if (GetLength() != GetWidth()) • cout << "Error, not a square... a Rectangle??\n"; • }
int main() • { • int choice; • bool fQuit = false; • Shape * sp; • while ( !fQuit ){ • cout << "(1)Circle (2)Rect (3)Square (0)Quit: "; • cin >> choice; • switch (choice){ • case 0: fQuit = true; • break; • case 1: sp = new Circle(5); • break; • case 2: sp = new Rectangle(4,6); • break; • case 3: sp = new Square(5); • break; • default: cout<<"Please enter a number(0~3)\n” • continue; break; • } • if( !fQuit ) sp->Draw(); • delete sp; sp = 0; cout << "\n"; • } • return 0; • }
class Shape • { • public: • Shape(){} • ~Shape(){} • virtual long GetArea() = 0; // error • virtual long GetPerim()= 0; • virtual void Draw() = 0; • private: • }; list 14.8 세 개의 순수가상함수를 모두 재정의 해야만 객체를 만들 수 있음
기타-순수가상함수 • 순수가상함수의 구현 가능 • 추상 자료형의 순수가상함수는 파생 객체에 의해 호출 가능 • 재정의된 함수들에게 공통 기능 부여를 위해 주로 이용 • 추상의 복합 계층 • 하나의 추상자료형에서 다른 추상자료형의 파생 가능 Animal ABT Eat( ), Sleep( ), Move( ), Reproduce( ) 가상함수 Reproduce( ) 재정의 Mammal ABT Eat( ), Sleep( ), Move( ) 가상함수 Eat( ), Sleep( ), Move( ) 재정의 Dog 객체가능
#include <iostream> • using namespace std; • class Shape • { • public: • Shape(){ } • virtual ~Shape(){ } • virtual long GetArea() = 0; • virtual long GetPerim()= 0; • virtual void Draw() = 0; • private: • }; • void Shape::Draw() • { • cout << "Abstract drawing mechanism!\n"; • } list 14.9
class Circle : public Shape • { • public: • Circle(int radius):itsRadius(radius){ } • virtual ~Circle(){ } • long GetArea() { return 3 * itsRadius * itsRadius; } • long GetPerim() { return 9 * itsRadius; } • void Draw(); • private: • int itsRadius; • int itsCircumference; • }; • void Circle::Draw() • { • cout << "Circle drawing routine here!\n"; • Shape::Draw(); • }
class Rectangle : public Shape • { • public: • Rectangle(int len, int width): • itsLength(len), itsWidth(width){ } • virtual ~Rectangle(){} • long GetArea() { return itsLength * itsWidth; } • long GetPerim() {return 2*itsLength + 2*itsWidth; } • virtual int GetLength() { return itsLength; } • virtual int GetWidth() { return itsWidth; } • void Draw(); • private: • int itsWidth; • int itsLength; • }; • void Rectangle::Draw() • { • for (int i = 0; i<itsLength; i++) • { • for (int j = 0; j<itsWidth; j++) • cout << "x "; • cout << "\n"; • } • Shape::Draw(); • }
class Square : public Rectangle • { • public: • Square(int len); • Square(int len, int width); • virtual ~Square(){ } • long GetPerim() {return 4 * GetLength();} • }; • Square::Square(int len): • Rectangle(len,len) • { } • Square::Square(int len, int width): • Rectangle(len,width) • { • if (GetLength() != GetWidth()) • cout << "Error, not a square... a Rectangle??\n"; • }
int main() • { • int choice; • bool fQuit = false; • Shape * sp; • while ( !fQuit ){ • cout << "(1)Circle (2)Rect (3)Square (0)Quit: "; • cin >> choice; • switch (choice){ • case 0: fQuit = true; • break; • case 1: sp = new Circle(5); • break; • case 2: sp = new Rectangle(4,6); • break; • case 3: sp = new Square(5); • break; • default: cout<<"Please enter a number(0~3)\n” • continue; break; • } • if( !fQuit ) sp->Draw(); • delete sp; sp = 0; cout << "\n"; • } • return 0; • }