SeoulTech 2011-2 nd 프로그래밍입문 (2) Chapter 14. 상속 박종혁교수 (http://www.parkjonghyuk.net) Tel: 970-6702 Email: jhpark1@snut.ac.kr
Learning Objectives 상속의기본 파생클래스와생성자 protected: 제한자 멤버함수의재정의 상속되지않는함수들 상속을이용한프로그래밍 할당연산자와복사생성자 파생클래스에서의소멸자 다중상속 12-2
상속개요 객체지향프로그래밍 강력한프로그래밍기법 상속 (inheritance) 이라는추상화를위한새로운차원의기법을제공 일반화된형태의클래스가먼저정의 일반화된클래스를상속받아특성화된버전이정의됨 이때, 상속받은속성들을적절하게수정할수있음 12-3
상속의기본 새로운클래스는다른클래스로부터상속이가능 기반클래스 (Base Class) 다른클래스가상속받는일반클래스 파생클래스 (Derived class) 새로운클래스 자동으로기반클래스의멤버변수와함수를소유 멤버변수와함수의추가가능 12-4
파생클래스 (1/2) 예 : 직원 (Employees) 클래스 다음으로구성 : 봉급제직원 (Salaried employee) 시간제직원 (Hourly employee) 각각은직원의부분집합 전체직원은시간제급여를받는직원들과매주또는매달고정급여를받는직원들로구성 12-5
파생클래스 (2/2) 일반적인직원 (Employee) 의형이아니다 어느누구도단순하게 직원 인것은아니다 직원의일반화된개념을만들고접근 모든직원은이름을가짐 모든직원은사회보장번호 ( 주민등록번호 ) 를가짐 이와관련된함수는모든직원에적용 일반화된클래스는모든직원이공통적으로공유하는속성을가짐 12-6
Employee 클래스 (1/2) Employee 클래스의멤버변수와함수는모는형태의직원에적용 accessor 함수 mutator 함수 데이터속성 : SSN Name Pay 이클래스의객체를직접사용하는예는없음 12-7
Employee 클래스 (2/2) printcheck() 함수 : (Display 14.2) 항상하위 ( 파생 ) 클래스에서재정의됨 직원타입에따라다른결과를출력 구분되지않는 직원을위한출력은있을수없다 따라서, Employee 클래스의 printcheck() 이부분이출력되어서는안됨 에러메시지출력, 시스템종료부분추가 12-8
Employee 클래스로부터의파생 파생클래스 : 자동으로모든기반클래스의멤버변수와함수를가짐 파생클래스는기반클래스멤버를상속 멤버의재정의와새로운멤버의추가가능 12-9
디스플레이 14.3 파생클래스 HourlyEmployee 의인터페이스 (1/2) 4-10
디스플레이 14.3 파생클래스 HourlyEmployee 의인터페이스 (2/2) 4-11
HourlyEmployee 클래스인터페이스 다른클래스와유사함 #ifndef 구조 필요라이브러리 include include employee.h! 클래스헤더부 : class HourlyEmployee : public Employee { Employee 클래스로부터 public 상속을받았음을명시 12-12
HourlyEmployee 클래스추가사항 파생클래스의인터페이스에서는새로운멤버를추가하거나재정의하는부분만추가됨 모든상속받은부분은정의되어있음 ssn, name, HourlyEmployee 추가부분 : 생성자 멤버변수 : wagerate, hours 멤버함수 : setrate(), getrate(), sethours(), gethours() 12-13
HourlyEmployee 클래스재정의 HourlyEmployee 재정의 : (Display 14.5) printcheck() 멤버함수 Employee 클래스로부터상속받은 printcheck() function 구현을오버라이딩 (overriding) 이함수의정의부분은 HourlyEmployee 클래스의구현부에있어야함 12-14
상속 (Inheritance) 용어 일반적으로가족 ( 부모와자식사이 ) 간의관계를표현 부모클래스 (parent class) 기반클래스 자식클래스 (child class) 파생클래스 조상클래스 (ancestor class) 부모의부모 자손클래스 (descendant class) 자식의자식 12-15
파생클래스생성자 기반클래스의생성자는상속되지않음! 기반클래스의생성자는파생클래스의생성자내에서호출가능 필요함! 기반클래스생성자는기반클래스멤버변수를초기화해야함 따라서파생클래스생성자에서호출하여기반클래스멤버를초기화 첫번째파생클래스생성자 12-16
파생클래스생성자예 HourlyEmployee 생성자 : HourlyEmployee::HourlyEmployee(string thename, string thenumber, double thewagerate, double thehours) : Employee(theName, thenumber), wagerate(thewagerate), hours(thehours) { //Deliberately empty } 초기화섹션에 Employee 클래스의생성자호출 12-17
HourlyEmployee 의다른생성자 두번째생성자 : HourlyEmployee::HourlyEmployee() : Employee(), wagerate(0), hours(0) { //Deliberately empty } 매개변수가없는디폴트버전의기반클래스생성자호출 항상기반클래스의생성자중하나를호출해야함 12-18
기반클래스호출이없는생성자 파생클래스의생성자는항상기반클래스의생성자중하나를호출해야함 하지않으면 : 기반클래스의디폴트생성자가자동으로호출 다음버전에서자동으로호출 : HourlyEmployee::HourlyEmployee() : wagerate(0), hours(0) { } 12-19
함정 : 기반클래스 private 멤버변수 파생클래스는 private 멤버변수를상속함 하지만, 직접적인접근은불가능 파생클래스의멤버함수에서도불가능 private 멤버변수는자신들이정의된클래스의멤버함수를통해서만접근이가능 12-20
함정 : 기반클래스 private 멤버함수 기반클래스의 private 멤버함수도동일한규칙이적용 기반클래스의인터페이스및구현부외부에서의접근이불가능 파생클래스멤버함수에서도불가능 12-21
함정 : 기반클래스 private 멤버함수영향 private 멤버변수 기반클래스의멤버함수를통하여간접적인접근이가능 private 멤버함수 접근이불가능 합리적이유 private 멤버함수는 helper 함수 단지정의된곳에서만사용됨 12-22
protected 제한자 클래스멤버의새로운분류 파생클래스에서직접접근이가능 다른클래스에서접근이불가 private 처럼동작한다 미래의자손들에게접근을허용 일부전문가들은정보은닉의규칙을파괴했다고생각함 12-23
멤버함수의재정의 파생클래스의인터페이스 : 새로운멤버함수선언 또한, 상속받은함수중변경하고자하는함수를선언 상속받은함수중선언을하지않은함수 변경하지않고사용 파생클래스구현파일 : 새로운멤버함수정의 재정의하고자하는기반클래스의멤버함수정의도포함되어야함 12-24
재정의 (Redefining) vs. 오버로딩 (Overloading) 매우다름! 파생클래스에서재정의됨 ( 상속관계에서 ) : 같은매개변수리스트를가짐 같은함수의재작성이필요 오버로딩 : 다른매개변수리스트 새로이정의된함수는다른매개변수를가짐 오버로딩된함수는다른시그니처를가짐 12-25
함수시그니처 함수시그니처 : 함수이름 매개변수리스트 순서, 개수, 타입 시그니처가포함하지않는것 : 리턴타입 const 키워드 & 12-26
재정의된기반클래스함수에대한접근 파생클래스에서재정의되었다고해서기반클래스의함수를상실하는것은아님 재정의된기반클래스함수사용 : Employee JaneE; HourlyEmployee SallyH; JaneE.printCheck(); calls Employee s printcheck function SallyH.printCheck(); calls HourlyEmployee printcheck function SallyH.Employee::printCheck(); Calls Employee s printcheck function! 때때로기반클래스의함수가사용됨 12-27
상속되지않는함수들 예외 : 생성자 소멸자 복사생성자 정의하지않으면 디폴트버전이생성됨 포인터변수를사용하여동적할당을실행할경우 정의해야함 할당연산자 정의하지않으면 디폴트버전 12-28
할당연산자와복사생성자 오버로딩된할당연산자와복사생성자는상속되지않음 하지만파생클래스의정의부분에서사용가능 일반적으로반드시사용하여재정의해야함 파생클래스의생성자에서기반클래스의생성자를사용하는것과유사 12-29
할당연산자예 파생클래스코드 : Derived& Derived::operator =(const Derived & rightside) { Base::operator =(rightside); } 기반클래스의연산자호출 상속된멤버를처리 12-30
복사생성자예 파생클래스코드 : Derived::Derived(const Derived& Object) : Base(Object), { } 기반클래스의복사생성자호출 상속된멤버변수를처리 기반클래스의생성자에넘겨주는객체는파생형 파생형도기반클래스형이므로매개변수로넘겨주는것이가능 12-31
파생클래스에서의소멸자 기반클래스의소멸자가완벽하게정의되어있다면 파생클래스의소멸자정의는쉬움 파생클래스의소멸자가호출되면 : 자동으로기반클래스의소멸자가호출 명시적호출이필요없음 따라서, 파생클래스의소멸자는파생클래스에서정의된변수에대해서만 delete 수행 12-32
소멸자호출순서 다음을고려 : 클래스 B 는클래스 A 에서파생클래스 C 는클래스 B 에서파생 A B C 클래스 C 의객체가소멸되려면 : 클래스 C 의소멸자호출 클래스 B 의소멸자호출 클래스 A 의소멸자호출 생성자호출순서의역순 12-33
"Is a" vs. "Has a" 관계 상속 "Is a" 클래스관계 An HourlyEmployee "is a" Employee A Convertible "is a" Automobile 하나의클래스가다른클래스의객체를멤버로가지고있을경우 "Has a" 클래스관계 One class "has a" object of another class as it s data 12-34
protected 와 private 상속 새로운상속의형태 잘사용되지않음 protected 상속 : class SalariedEmployee : protected Employee { } 기반클래스의 public 멤버는파생클래스에서 protected 멤버로변경됨 private 상속 : class SalariedEmployee : private Employee { } 기반클래스의모든멤버는파생클래스에서 private 멤버로변경됨 Display 14.14 : 상속의종류 12-35
다중상속 파생클래스는하나이상의기반클래스를가질수있음! 구문 : class derivedmulti : public base1, base2 { } 혼동의소지있음! 2 개의기반클래스가동일한이름과매개변수자료형을갖는함수를가지고있다면? 위험한작업! 일부전문가는절대사용해서는안된다고주장 충분히경험을쌓은프로그래머가사용해야함! 12-36
요약 1 상속은코드의재사용을제공 파생클래스에몇가지특성만을추가하여사용 파생클래스객체는기반클래스의멤버를상속 멤버추가 파생클래스에서기반클래스의 private 멤버변수는직접접근이불가 private 멤버함수는상속되지않음 12-37
요약 2 상속된멤버함수의재정의가능 기반클래스에서의동작과다르게정의가능 기반클래스의 protected 멤버 : 파생클래스에서직접접근이가능 오버로딩된할당연산자는상속되지않음 파생클래스에서호출가능 파생클래스할당연산자정의에사용가능 생성자는상속되지않음 파생클래스에서호출가능 파생클래스생성자정의에사용가능 12-38
Q&A 4-39