12. 상속 : 고급
차례 상속에서 멤버 함수 재정의 추상 클래스 동적 형 변환 다중 상속
함수 오라이딩/동적결합/다형성/가상함수 1 함수 오버라이딩 (Function Overriding) 기반 클래스의 멤버 함수를 파생 클래스에서 다시 정의하는 것 동적 결합 (Dynamic Binding) 실행 시 호출될 함수를 결정하는 것으로 이는 하나의 함수가 여러 클래스에서 오버라이딩되었을때 사용
함수 오라이딩/동적결합/다형성/가상함수 2 다형성(Polymorphism) 하나의 함수가 여러 구현 형태로 정의되는 것을 다형성이라 함 다형성에 의해 함수 재정의시 요구조건 기반 클래스의 멤버 함수가 가상함수로 선언되어야 함 함수에서 매개변수로 전달된 변수는 객체의 주소를 포함해야 함
함수 오라이딩/동적결합/다형성/가상함수 3 함수 오버라이딩을 목적으로 기반 클래스의 함수 함수 선언시 virtual 키워드를 표시함 virtual 함수리턴형 함수이름( ) ;
소스 12-2 (ch12_02.cpp) – 동적결합이 안된 경우 #include <iostream> using namespace std; class A { public: string ClassMessage() return "class A"; } }; class B : public A return "class B"; void TestFunction1(A x) { cout << x.ClassMessage().data() << endl; } int main() A a; B b; TestFunction1(a); TestFunction1(b); return 0; 예상 실행 결과 : class A class B 실제 실행 결과 : class A
소스 12-3 (ch12_03.cpp) – 동적결합 #include <iostream> using namespace std; class A { public: string ClassMessage() return "class A"; } }; class B : public A return "class B"; #include <iostream> using namespace std; class A { public: virtual string ClassMessage() return "class A"; } }; class B : public A string ClassMessage() return "class B";
소스 12-2 (ch12_03.cpp) – 동적결합 실행 결과 : class A 실행 결과 : class A class B void TestFunction1(A x) { cout << x.ClassMessage().data() << endl; } int main() A a; B b; TestFunction1(a); TestFunction1(b); return 0; void TestFunction1(A *x) { cout << x->ClassMessage().data() << endl; } int main() A a; B b; TestFunction1(&a); TestFunction1(&b); return 0; 실행 결과 : class A 실행 결과 : class A class B
추상 클래스 순수 가상 함수 (Pure Virtual Function) 추상 클래스 (Abstract Class) 함수 내용을 정의하지 않고 파생 클래스에서 함수 오버라이딩에 의해 내용이 결정되는 형태의 함수 추상 클래스 (Abstract Class) 객체 생성이 목적이 아닌 클래스 상속에서 기반 클래스 역할을 담당 순수 가상 함수를 포함 virtual 반환형 함수이름( ) =0;
추상 클래스 AbstractClass는 객체를 생성하지 못함!!! Error!!! 소스 12-5 ( ch12_04.cpp) #include <iostream> #include <string> using namespace std; class AbstractClass { public: virtual string SampleFunction()=0; }; class TestClass : public AbstractClass string SampleFunction() return "SampleFunction"; } int main() { AbstractClass obj1; cout << obj1.SampleFunction() << endl; return 0; } 추상 클래스 AbstractClass는 객체를 생성하지 못함!!! Error!!!
소스 12-5 ( ch12_04.cpp) 파생 클래스 TestClass로 객체 생성!!! #include <iostream> #include <string> using namespace std; class AbstractClass { public: virtual string SampleFunction()=0; }; class TestClass : public AbstractClass string SampleFunction() return "SampleFunction"; } int main() { TestClass obj1; cout << obj1.SampleFunction() << endl; return 0; } 파생 클래스 TestClass로 객체 생성!!!
실습 1-1 다음의 클래스를 정의하자. 클래스 이름: GeometricObject 멤버 변수: 두 개의 선(line1, line2)으로 구성된 배정도형 자료를 다루며, 클래스 상속 시 파생 클래스에서 참조케 함 멤버 함수 생성자: 매개변수 없이 멤버 변수를 0으로 초기화 생성자: 두 개의 멤버 변숫값을 매개변수로 전달하여 초기화 각각의 멤버 변숫값을 매개변수로 전달하여 초기화 각각의 멤버 변숫값을 객체 외부로 전달 멤버 변수를 이용하여 도형의 면적을 계산하는 순수 가상 함수(AreaCalculation) 멤버 변수를 이용하여 도형의 둘레를 계산하는 순수 가상 함수(RoundCalculation)
실습 1-2 클래스 이름: Isosceles GeometricObject를 기반 클래스로 하는 파생 클래스 멤버 변수: 이등변 삼각형의 밑면, 높이, 면적(area)과 등변(side)으로 구성되며 밑변과 높이는 기반 클래스의 멤버 변수 line1과 line2로 사용함 멤버 함수 생성자: 매개변수 없이 멤버 변수를 0으로 초기화 생성자: 밑변과 높이의 값을 매개변수로 전달하여 초기화하고 나머지 멤버 변수는 0으로 초기화 기반 클래스의 AddCalculation( )을 면적 계산 함수로 함수 오버라이딩 기반 클래스의 Compute( )을 등변 계산 함수로 함수 오버라이딩 멤버 변수인 면적과 등변을 각각 객체 외부로 전달
실습 1-3 클래스 이름: Rectangle GeometricObject를 기반 클래스로 하는 파생 클래스 멤버 변수: 사각형의 가로와 세로, 면적(area)과 둘레(round)로 구성됨, 가로와 세로는 기반 클래스의 멤버 변수 line1과 line2로 사용함 멤버 함수 생성자: 매개변수 없이 멤버 변수를 0으로 초기화 생성자: 가로와 세로의 값을 매개변수로 전달하여 초기화하고 나머지 멤버 변수는 0으로 초기화 기반 클래스의 AddCalculation( )을 면적 계산 함수로 함수 오버라이딩 기반 클래스의 Compute( )을 사각형 둘레 계산 함수로 함수 오버라이딩 멤버 변수인 넓이와 둘레를 각각 객체 외부로 전달
객체포인터1 = dynamic_cast <클래스이름*> (객체 포인터2) 동적 형 변환 동적 형 변환 클래스 상속에서 파생 클래스의 객체를 기반 클래스 형으로 변환(업캐스팅;Upcasting) 것 또는 기반 클래스의 객체를 파생 클래스 형으로 변환(다운캐스팅;Downcasting)하는 것 객체의 포인터를 변환을 원하는 클래스의 포인터로 할당 객체포인터1 = dynamic_cast <클래스이름*> (객체 포인터2)
업 캐스팅 예제 – 소스 12-11(ch12_05.cpp) 업캐스팅은 자동으로 형변환이 실행됨 (기반 파생) #include "ch12_GeometricObject.h" int main() { GeometricObject *p1 = new Isosceles(9,15); Isosceles *p2 = new Isosceles(5,6); cout << "p1 : " << p1->GetLine1() << endl; cout << "p2 : " << p2->GetLine1() << endl; return 0; }
다운 캐스팅 예제 – 소스 12-12(ch12_06.cpp) 다운캐스팅은 dynamic_cast 연산자가 명시되어야 함 (파생 기반) #include "ch12_GeometricObject.h" void DisplayGeometricObject(GeometricObject &object) { cout << "line1 : " << object.GetLine1() << endl; cout << "line2 : " << object.GetLine2() << endl; GeometricObject *p=&object; Isosceles *p1 = dynamic_cast<Isosceles*>(p); //다운 캐스팅 Rectangle *p2 = dynamic_cast<Rectangle*>(p); //다운 캐스팅 if (p1 != NULL) p1->AreaCalculation(); p1->Compute(); cout << "이등변 삼각형의 넓이 : " << p1->GetArea() << endl; cout << "이등변 삼각형의 등변 : " << p1->GetSide() << endl; } 매개변수로 전달받은 GeometricObject 객체 포인터 주소를 저장
if (p2 != NULL) { p2->AreaCalculation(); p2->Compute(); cout << "사각형의 넓이 : " << p2->GetArea() << endl; cout << "사각형의 둘레 : " << p2->GetRound() << endl; } int main() Isosceles p1(9, 15); Rectangle p2(10, 12); DisplayGeometricObject(p1); cout << "****************************" << endl; DisplayGeometricObject(p2); return 0;
소스 12-12 설명 36번 라인 DisplayGeometricObject(Isosceles p1); 이 호출되면 함수에서 p1은 정상적인 주소의 객체, p2는 NULL이 할당되며 여러 번 동적 형 변환이 발생함!! 37번 라인 DisplayGeometricObject(Rectangle p2); 이 호출되면 함수에서 p1은 NULL이 할당되고 , p2는 정상적인 주소의 객체가 할당되고 여러 번 동적 변환이 발생함
다중 상속 클래스 상속의 형태 기반 클래스 기반 클래스 파생 클래스 파생 클래스1 파생 클래스2 기반 클래스1 기반 클래스2
소스 12-13~소스 12-17 (ch12_multi.h, ch12_multi.cpp, ch12_07.cpp) class ScoreSource { ……………………….. }; class RankGrade class SungJuk : public ScoreSource, public RankGrade