390 likes | 560 Views
상속. 상속이란 ? - 기반클래스로부터 다른 클래스를 파생하는 법 protected 란 ? 가상함수 (virtual function). 상속이란 ?. 상속 각 개념들간의 계층 구조에서 상위 개념 ( 표유류 ) 의 일반적인 특성을 하위 개념 ( 개 ) 이 이어 받는 것 계층 구조는 “한 종류”라는 식으로 표현 : 도요타는 차의 한 종류 파생
E N D
상속 상속이란? - 기반클래스로부터 다른 클래스를 파생하는 법 protected란? 가상함수 (virtual function)
상속이란? • 상속 • 각 개념들간의 계층 구조에서 상위 개념(표유류)의 일반적인 특성을 하위 개념(개)이 이어 받는 것 • 계층 구조는 “한 종류”라는 식으로 표현 : 도요타는 차의 한 종류 • 파생 • 상위 클래스(기반/기본 클래스, 부모 클래스, base class)에서 새로운 특성을 추가하여 새로운 클래스(파생 클래스, derived class, child class)를 만드는 것 Animal Mammal Reptile Horse Dog
파생 구문 • 파생 클래스가 어디로부터 파생하였는지를 표시 • 기반 클래스는 이전에 선언되어 있어야 함 • 파생 클래스는 기반 클래스의 생성자, 소멸자, friend 함수를 제외한 모든 것을 상속 class 파생클래스명 : 파생의형 기반클래스명 class Dog : public Mammal
#include <iostream> • using namespace std; • enum BREED { GOLDEN, CAIRN, DANDIE}; • class Mammal • { • public: • Mammal(); • ~Mammal(); • int GetAge() const; • void SetAge(int); • int GetWeight() const; • void SetWeight(); • void Speak() const; • void Sleep() const; • protected: • int itsAge; • int itsWeight; • }; list 12.1
class Dog : public Mammal • { • public: • Dog(); • ~Dog(); • BREED GetBreed() const; • void SetBreed(BREED); • WagTail(); • BegForFood(); • protected: • BREED itsBreed; • };
전용(private) vs. 보호(protected) • (기반 클래스) public • 파생된 클래스 : 접근 가능 • 기반 & 파생 클래스 외부 : 접근 가능 • (기반 클래스) private • 파생된 클래스 : 접근 불능 • 기반 & 파생 클래스 외부 : 접근 불능 • (기반 클래스) protected • 파생된 클래스 : 접근 가능 • 기반 & 파생 클래스 외부 : 접근 불능
#include <iostream> • using std::cout; • enum BREED { GOLDEN, CAIRN, DANDIE}; • class Mammal • { • public: • Mammal():itsAge(2), itsWeight(5){} • ~Mammal(){} • int GetAge() const { return itsAge; } • void SetAge(int age) { itsAge = age; } • int GetWeight() const { return itsWeight; } • void SetWeight(int weight) { itsWeight = weight; } • void Speak()const { cout << "Mammal sound!\n"; } • void Sleep()const { cout << "shhh. I'm sleeping.\n"; } • protected: • int itsAge; • int itsWeight; • }; list 12.2
class Dog : public Mammal • { • public: • Dog():itsBreed(GOLDEN){} • ~Dog(){} • BREED GetBreed() const { return itsBreed; } • void SetBreed(BREED breed) { itsBreed = breed; } • void WagTail() const { cout << "Tail wagging...\n"; } • void BegForFood() const • { cout << "Begging for food...\n"; } • private: • BREED itsBreed; • }; • int main() • { • Dog fido; • fido.Speak(); • fido.WagTail(); • cout << "Fido is " << fido.GetAge() << " years old\n"; • return 0; • }
class Parent • { • public: • int b; • void f(){a=1;} • private: • int a; • }; • class Child : public Parent • { • public: • void g(){ • a=1; // (1) • b=1; // (2) • f(); // (3) • } • private: • int c; • }; • int main() • { • Child Tom; • Tom.b = 3; // (4) • Tom.a = 4; // (5) • Tom.c = 5; // (6) • }
class Parent • { • public: • int b; • void f(){a=1;} • protected: • int a; • }; • class Child : public Parent • { • public: • void g(){ • a=1; // (1) • b=1; // (2) • f(); // (3) • } • private: • int c; • }; • int main() • { • Child Tom; • Tom.b = 3; // (4) • Tom.a = 4; // (5) • Tom.c = 5; // (6) • }
상속에서의 생성자와 소멸자 • 파생 클래스의 객체 생성 시 : 생성자 • 기반 클래스의 생성자 호출 • 파생 클래스의 생성자 호출 • 파생 클래스의 객체 소멸 시 : 소멸자 • 파생 클래스의 소멸자 호출 • 기반 클래스의 소멸자 호출 • 각각의 부분을 생성하고 소멸 시킴 • 기반 클래스의 생성자에게 인자 전달 • 기반 클래스의 생성자가 중첩되어 있는 경우 • 파생 클래스의 생성자 함수에서 기반 클래스의 생성자 함수 호출 • 기본 생성자 이외의 기반 클래스 생성자 실행 가능
#include <iostream> • using namespace std; • enum BREED { GOLDEN, CAIRN, DANDIE}; • class Mammal • { • public: • Mammal(); • Mammal(int age); • ~Mammal(); • int GetAge() const { return itsAge; } • void SetAge(int age) { itsAge = age; } • int GetWeight() const { return itsWeight; } • void SetWeight(int weight) { itsWeight = weight; } • void Speak() const { cout << "Mammal sound!\n"; } • void Sleep() const { cout << "shhh. I'm sleeping.\n"; } • protected: • int itsAge; • int itsWeight; • }; list 12.4
class Dog : public Mammal • { • public: • Dog(); • Dog(int age); • Dog(int age, int weight); • Dog(int age, BREED breed); • Dog(int age, int weight, BREED breed); • ~Dog(); • BREED GetBreed() const { return itsBreed; } • void SetBreed(BREED breed) { itsBreed = breed; } • void WagTail() const { cout << "Tail wagging...\n"; } • void BegForFood() const • { cout << "Begging for food...\n"; } • private: • BREED itsBreed; • };
Mammal::Mammal(): itsAge(1), itsWeight(5) • { • cout << "Mammal constructor...\n"; • } • Mammal::Mammal(int age): itsAge(age), itsWeight(5) • { • cout << "Mammal(int) constructor...\n"; • } • Mammal::~Mammal() • { • cout << "Mammal destructor...\n"; • }
Dog::Dog(): Mammal(), itsBreed(GOLDEN) • { • cout << "Dog constructor...\n"; • } • Dog::Dog(int age): Mammal(age), itsBreed(GOLDEN) • { • cout << "Dog(int) constructor...\n"; • } • Dog::Dog(int age, int weight): • Mammal(age), itsBreed(GOLDEN) • { • itsWeight = weight; • cout << "Dog(int, int) constructor...\n"; • } • Dog::Dog(int age, int weight, BREED breed): • Mammal(age), itsBreed(breed) • { • itsWeight = weight; • cout << "Dog(int, int, BREED) constructor...\n"; • } ,itsWeight(weight) (X)
Dog::Dog(int age, BREED breed): • Mammal(age), itsBreed(breed) • { • cout << "Dog(int, BREED) constructor...\n"; • } • Dog::~Dog() • { • cout << "Dog destructor...\n"; • } • int main() • { • Dog fido; • Dog rover(5); • Dog buster(6,8); • Dog yorkie (3,GOLDEN); • Dog dobbie (4,20,DOBERMAN); • fido.Speak(); • rover.WagTail(); • cout << "Yorkie is " << yorkie.GetAge() • << " years old\n"; • cout << "Dobbie weighs "; • cout << dobbie.GetWeight() << " pounds\n"; • return 0; • }
함수 재정의/재생 (Overriding Function) • 함수 재정의 • 파생 클래스에서 기반 클래스의 함수 구현부를 새로이 만드는 것 • 함수의 반환 형, 원형부가 일치해야 함 • 함수 반환형 • 매개 변수의 목록 • 상수형 함수 표시 • 기반 클래스의 하나의 함수를 재정의하면 동일한 이름을 가진 모든 기반 클래스의 함수(중첩된 모든 기반 클래스의 함수)를 은폐 시키게 됨 • 기반 클래스의 함수가 재정의 되었더라도 함수의 이름을 완전하게 다 써주면 호출할 수 있음 파생클래스의객체명.기반클래스명::함수명( ) 중첩, 다중정의 (Overloading) vs. 재정의, 재생(Overriding)
#include <iostream> • using namespace std; • class Mammal • { • public: • void Move() const • { cout << "Mammal move one step\n"; } • void Move(int distance) const • { • cout << "Mammal move " << distance; • cout << " steps.\n"; • } • protected: • int itsAge; • int itsWeight; • }; list 12.7
class Dog : public Mammal • { • public: • void Move() const; • }; • void Dog::Move() const • { • cout << "In dog move...\n"; • Mammal::Move(3); • } • int main() • { • Mammal bigAnimal; • Dog fido; • bigAnimal.Move(); • bigAnimal.Move(2); • fido.Move( ); • fido.Move(6); • fido.Mammal::Move(6); • fido.Mammal::Move( ); • return 0; • }
가상 메소드/함수 (Virtual Method) • 기반클래스를 가리키는 포인터에 파생 클래스의 포인터를 대입하는 다형성(polymorphism) 지원 • Dog는 Mammal의 한 종류이므로 가능 • 반대는 불가능 • pMammal 포인터를 이용해 Mammal의 멤버 함수 호출 가능 • Dog의 멤버 함수를 호출하려면? Mammal *pMammal = new Dog 가상 함수 기반 클래스의 함수를 가상함수로 만듦 virtual 반환형 함수명( 매개변수 리스트 )
#include <iostream> • using std::cout; • class Mammal • { • public: • Mammal():itsAge(1) • { cout << "Mammal constructor...\n"; } • virtual ~Mammal() • { cout << "Mammal destructor...\n"; } • void Move() const • { cout << "Mammal move one step\n"; } • virtual void Speak() const • { cout << "Mammal speak!\n"; } • protected: • int itsAge; • }; list 12.8
class Dog : public Mammal • { • public: • Dog() { cout << "Dog Constructor...\n"; } • virtual ~Dog() { cout << "Dog destructor...\n"; } • void WagTail() { cout << "Wagging Tail...\n"; } • void Speak() const • { cout << "Woof!\n"; } • void Move() const • { cout << "Dog moves 5 steps...\n"; } • }; • int main() • { • Mammal *pDog = new Dog; • pDog->Move(); • pDog->Speak(); • pDog->WagTail(); • Dog *ptemp = new Mammal; • return 0; • }
#include <iostream> • using namespace std; • class Mammal • { • public: • Mammal():itsAge(1) { } • virtual ~Mammal() { } • virtual void Speak() const • { cout << "Mammal speak!\n"; } • protected: • int itsAge; • }; list 12.9
class Dog : public Mammal • { • public: • void Speak() const { cout << "Woof!\n"; } • }; • class Cat : public Mammal • { • public: • void Speak() const { cout << "Meow!\n"; } • }; • class Horse : public Mammal • { • public: • void Speak() const { cout << "Winnie!\n"; } • }; • class Pig : public Mammal • { • public: • void Speak() const { cout << "Oink!\n"; } • };
int main() • { • Mammal* theArray[5]; • Mammal* ptr; • int choice, i; • for ( i = 0 ; i<5 ; i++ ) • { • cout << "(1)dog (2)cat (3)horse (4)pig: "; • cin >> choice; • switch (choice) • { • case 1: ptr = new Dog; • break; • case 2: ptr = new Cat; • break; • case 3: ptr = new Horse; • break; • case 4: ptr = new Pig; • break; • default: ptr = new Mammal; • } • theArray[i] = ptr; • } • for ( i=0 ; i<5 ; i++ ) • theArray[i]->Speak(); • return 0; • }
다형성(polymorphism) • 다형성 (Polymorphism) • 함수 중첩 • 기반 클래스의 포인터에 파생 클래스의 포인터 대입 가능 • 기본 클래스에서 멤버 함수를 가상으로 만들었을 경우 파생 클래스에서도 가상으로 하여야 하는가? • 역시 가상으로 되어 있지만 • 하는 것이 이해하기 좋음 하나의 이름을 두 개 또는 그 이상의 관련된 목적에 사용할 수 있도록 하는 성질
가상함수의 동작 원리 • 가상함수를 위해서는 동적 바인딩 필요 • 가상함수가 존재하는 class의 객체가 만들어지면 객체는 그 함수를 추적해야 함 • 컴파일러는 가상함수테이블(virtual function table, v-table)을 만듦 • 각각의 파생 객체는 가상 테이블의 포인터 (vptr)를 유지하여야 함 동적 바인딩(dynamic binding) 실행 바인딩(run-time binding) 정적(static binding) 컴파일 바인딩(compile binding)
가상함수의 동작원리 (cont.) • Mammal의 v-table • Dog의 v-table VPTR &Move( ) &Speak( ) Mammal VPTR Mammal &Mammal:Move( ) &Dog:Speak( ) Dog Mammal을 가리키는 포인터가 사용되더라도 vptr은 객체의 실제형에 대한 함수를 가리키고 있음
기타 • 포인터와 참조자를 사용하는 경우 이러한 동작 가능 • 객체를 값으로 전달 시 가상함수 호출 되게 할 수 없음
#include <iostream> • class Mammal • { • public: • Mammal():itsAge(1) { } • virtual ~Mammal() { } • virtual void Speak() const • { std::cout << "Mammal speak!\n"; } • protected: • int itsAge; • }; • class Dog : public Mammal • { • public: • void Speak() const { std::cout << "Woof!\n"; } • }; • class Cat : public Mammal • { • public: • void Speak() const { std::cout << "Meow!\n"; } • }; list 12.10
void ValueFunction (Mammal MammalValue) { MammalValue.Speak(); } void PtrFunction (Mammal * pMammal) { pMammal->Speak(); } void RefFunction (Mammal & rMammal) { rMammal.Speak(); }
int main() • { • Mammal* ptr=0; • int choice; • ptr = new Cat; • PtrFunction(ptr); • RefFunction(*ptr); • ValueFunction(*ptr); • delete ptr; • ptr = new Dog; • PtrFunction(ptr); • RefFunction(*ptr); • ValueFunction(*ptr); • delete ptr; • return 0; • }
가상 소멸자(virtual destructor) • 기본클래스에서 가상인 함수가 있으면 그 소멸자도 가상이어야 한다 • 기본클래스의 소멸자가 가상이면 파생클래스의 소멸자가 호출
가상 복사 생성자(Virtual Copy Constructor) • 생성자는 가상이 될 수 없으므로 가상 복사 생성자는 없음 • 실질적인 복사를 수행한 후 복사된 객체에 대한 포인터를 반환 • 기반 클래스에서 Clone( ) 메소드를 가상으로 만듦
#include <iostream> • using namespace std; • class Mammal • { • public: • Mammal():itsAge(1) • { cout << "Mammal constructor...\n"; } • virtual ~Mammal() • { cout << "Mammal destructor...\n"; } • Mammal (const Mammal & rhs); • virtual void Speak() const • { cout << "Mammal speak!\n"; } • virtual Mammal* Clone() • { return new Mammal(*this); } • int GetAge() const • { return itsAge; } • protected: • int itsAge; • }; • Mammal::Mammal (const Mammal & rhs): • itsAge(rhs.GetAge()) • { • cout << "Mammal Copy Constructor...\n"; • } list 12.11
class Dog : public Mammal • { • public: • Dog() { cout << "Dog constructor...\n"; } • virtual ~Dog() { cout << "Dog destructor...\n"; } • Dog (const Dog & rhs); • void Speak()const { cout << "Woof!\n"; } • virtual Mammal* Clone() { return new Dog(*this); } • }; • Dog::Dog(const Dog & rhs): • Mammal(rhs) • { • cout << "Dog copy constructor...\n"; • }
class Cat : public Mammal • { • public: • Cat() { cout << "Cat constructor...\n"; } • ~Cat() { cout << "Cat destructor...\n"; } • Cat (const Cat &); • void Speak()const { cout << "Meow!\n"; } • virtual Mammal* Clone() { return new Cat(*this); } • }; • Cat::Cat(const Cat & rhs): • Mammal(rhs) • { • cout << "Cat copy constructor...\n"; • }
enum ANIMALS { MAMMAL, DOG, CAT}; • const int NumAnimalTypes = 3; • int main() • { • Mammal *theArray[NumAnimalTypes]; • Mammal* ptr; • int choice, i; • for ( i = 0; i<NumAnimalTypes; i++) • { • cout << "(1)dog (2)cat (3)Mammal: "; • cin >> choice; • switch (choice) • { • case DOG: ptr = new Dog; • break; • case CAT: ptr = new Cat; • break; • default: ptr = new Mammal; • break; • } • theArray[i] = ptr; • }
Mammal *OtherArray[NumAnimalTypes]; • for (i=0;i<NumAnimalTypes;i++) • { • theArray[i]->Speak(); • OtherArray[i] = theArray[i]->Clone(); • } • for (i=0;i<NumAnimalTypes;i++) • OtherArray[i]->Speak(); • return 0; • }