다중 상속 - 가상 상속 추상 자료형 순수 가상함수 다형성 다중 상속 - 가상 상속 추상 자료형 순수 가상함수
Pegasus class의 지원 표유류 말 새 Pegasus ? 다중 상속 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 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"; Ranch[i]->Fly(); delete Ranch[i]; return 0;
형 변환 하향 (casting down) RTTI ( Run Time Type Identification) 실행 시 형 식별 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 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; } Pegasus *pPeg = dynamic_cast< Pegasus *> (Ranch[i]); if (pPeg) pPeg->Fly(); 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 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! "; } 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; } cout << "\n(1)Bird (2)Pegasus: "; pBird = new Pegasus; pBird = new Bird; Aviary[i] = pBird;
cout << "\n"; for (i=0; i<MagicNumber; i++) { cout << "\nRanch[" << i << "]: " ; Ranch[i]->Whinny(); delete Ranch[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.) (X) (O) (X) 모호성 리스트 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 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.) Animal Horse Bird Pegasus 가상 상속 가상기본클래스 가상상속 가상상속 위의 그림과 같이 단일 공통 클래스 가능해짐 실질적인 변화는 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); case 2: sp = new Rectangle(4,6); case 3: sp = new Square(5); 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 Mammal Dog 순수가상함수의 구현 가능 추상의 복합 계층 추상 자료형의 순수가상함수는 파생 객체에 의해 호출 가능 재정의된 함수들에게 공통 기능 부여를 위해 주로 이용 추상의 복합 계층 하나의 추상자료형에서 다른 추상자료형의 파생 가능 Animal ABT 가상함수 Eat( ), Sleep( ), Move( ), Reproduce( ) Reproduce( ) 재정의 Mammal ABT 가상함수 Eat( ), Sleep( ), Move( ) Eat( ), Sleep( ), Move( ) 재정의 Dog 객체가능
#include <iostream> using namespace std; class Shape { public: 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); case 2: sp = new Rectangle(4,6); case 3: sp = new Square(5); default: cout<<"Please enter a number(0~3)\n” continue; break; } if( !fQuit ) sp->Draw(); delete sp; sp = 0; cout << "\n"; return 0;