윤성우의 열혈 TCP/IP 소켓 프로그래밍

Save this PDF as:
 WORD  PNG  TXT  JPG

Size: px
Start display at page:

Download "윤성우의 열혈 TCP/IP 소켓 프로그래밍"

Transcription

1 상속과다형성 박종혁교수 UCS Lab Tel:

2 객체포인터의참조관계

3 3 상속된객체와포인터관계 AAA 클래스 저장 주소 객체포인터 저장 객체의주소값을저장할수있는포인터 AAA 클래스의포인터는 BBB 클래스 주소 AAA 객체의주소뿐만아니라 AAA 클래스를상속하는 Derived 클래스의객체의주소값도저장가능 AAA 클래스의참조자는 AAA 객체뿐만아니라 AAA 클 래스를상속하는 Derived 클래스의객체도참조가능

4 4 상속된객체의포인터, 참조자 AAA 클래스 멤버 객체포인터의권한접근 포인터를통해서접근할수접근 BBB 클래스멤버있는객체멤버의영역 AAA 클래스의객체포인터는 AAA 클래스의멤버와 AAA 클래스가상속받은 Base 클래스의멤버만접근가능 AAA 클래스의참조자는 AAA 클래스의멤버와 AAA 클래스가상속받은 Base 클래스의멤버만접근가능

5 5 상속된객체와참조관계 객체의레퍼런스 객체를참조할수있는레퍼런스 클래스포인터의특성과일치 객체레퍼런스의권한 객체를참조하는레퍼런스의권한 클래스포인터의권한과일치 5

6 6 객체의주소값을저장하는객체포인터변수 C++ 에서, AAA 형포인터변수는 AAA 객체또는 AAA 를직접혹은간접적으로상속하는모든객 체를가리킬수있다 ( 객체의주소값을저장할수있다 ). Person * ptr=new Student(); Person * ptr=new PartTimeStudent(); Student * ptr=new PartTimeStudent();

7 7 Ex) ObejctPointer.cpp #include <iostream> using namespace std; class Person void Sleep() cout<<"sleep"<<endl; ; class Student : public Person void Study() cout<<"study"<<endl; ; class PartTimeStudent : public Student void Work() cout<<"work"<<endl; ; int main(void) Person * ptr1=new Student(); Person * ptr2=new PartTimeStudent(); Student * ptr3=new PartTimeStudent(); ptr1->sleep(); ptr2->sleep(); ptr3->study(); delete ptr1; delete ptr2; delete ptr3; return 0;

8 8 유도클래스의객체도가리키는포인터! IS-A 관계 유도클래스객체를기초클래스객체로바라볼수있는근거

9 9 문제의제시를위한시나리오의도입 프로그램전체기능의처리를, 프로그램의흐름을담당하는클래스를가리켜컨트롤클래스라한다. EmployeeHandler의경우컨트롤클래스에해당한다. 신규직원등록시 전체급여정보출력 급여합계정보출력 PermanentWorker 는정규직을표현해놓 은클래스이다.

10 10 오렌지미디어급여관리확장성문제 1 차해결 모든클래스의객체를 Employee 클래스의객체 로간주 ( 처리 ) 할수있는기반을마련. 컨트롤클래스입장에서는모든객체를 Employee 객체로간주해도문제가되지않는다!

11 11 EmployeeHandler 의첫번째수정 class EmployeeHandler private: Employee* emplist[50]; int empnum; EmployeeHandler() : empnum(0) void AddEmployee(Employee* emp) emplist[empnum++]=emp; void ShowAllSalaryInfo() const /* for(int i=0; i<empnum; i++) emplist[i]->showsalaryinfo(); */ void ShowTotalSalary() const int sum=0; /* for(int i=0; i<empnum; i++) sum+=emplist[i]->getpay(); */ cout<<"salary sum: "<<sum<<endl; ~EmployeeHandler() for(int i=0; i<empnum; i++) delete emplist[i]; ; 왼쪽의 EmployeeHandler 클래스는 Employee 객체를처리 하는컨트롤클래스로변경되었다.

12 12 Ex) EmployeeManager2.cpp #include <iostream> #include <cstring> using namespace std; class Employee private: char name[100]; Employee(char * name) strcpy(this->name, name); void ShowYourName() const cout<<"name: "<<name<<endl; ; class PermanentWorker : public Employee private: int salary; PermanentWorker(char* name, int money) : Employee(name), salary(money) int GetPay() const return salary; void ShowSalaryInfo() const ShowYourName(); cout<<"salary: "<<GetPay()<<endl<<endl; ; class EmployeeHandler private: Employee* emplist[50]; int empnum; EmployeeHandler() : empnum(0) void AddEmployee(Employee* emp) emplist[empnum++]=emp; void ShowAllSalaryInfo() const /* for(int i=0; i<empnum; i++) emplist[i]->showsalaryinfo(); */ void ShowTotalSalary() const int sum=0; /* for(int i=0; i<empnum; i++) sum+=emplist[i]->getpay(); */ cout<<"salary sum: "<<sum<<endl; ~EmployeeHandler() for(int i=0; i<empnum; i++) delete emplist[i]; ; int main(void) EmployeeHandler handler; // 직원등록 handler.addemployee(new PermanentWorker("KIM", 1000)); handler.addemployee(new PermanentWorker("LEE", 1500)); handler.addemployee(new PermanentWorker("JUN", 2000)); handler.showallsalaryinfo(); handler.showtotalsalary(); return 0;

13 임시직 : TemporaryWorker 13

14 14 영업직 : SalesWorker PermanentWorker 클래스의 GetPay 함수를오버라이딩! PermanentWorker 클래스의 ShowSalaryInfo 함수오버라이딩!

15 15 함수오버라이딩 (Function Overriding) 어! PermanentWorker 클래스에도 GetPay 함수와 ShowSalaryInfo 함수가있는데, 유도클래스인 SalewWorker 클래스에서도동일한이름과형태로두함수를정의하였네. 함수오버라이딩 (function overriding) 기초클래스에서정의한함수를유도클래스에서동일한이름과 형태로함수를정의하여사용 주의 : 함수오버로딩과혼동금지 함수오버라이딩되면, 오버라이딩된기초클래스의함수는오버 라이딩을한유도클래스의함수에가려짐 위의 SalesWorker 클래스내에서 GetPay 함수를호출하면 SalesWorker 클래스에정의된 GetPay 함수가호출됨

16 16 함수오버라이딩 vs 함수오버로딩 기초클래스와동일한이름의함수를유도클래스에서정의한다고해서무조건함수오버라이딩이되는것은아님. 함수오버로딩 매개변수의자료형및개수가다를경우 전달되는인자에따라서호출되는함수가결정 함수오버로딩은상속의관계어서도구성가능

17 17 오버라이딩 (overriding) 오버라이딩 (Overriding) 의이해 Base 클래스에선언된멤버와같은형태의멤버를 Derived 클래스에서선언 Base 클래스의멤버를가리는효과! 보는시야 (Pointer) 에따라서달라지는효과! Overriding1.cpp, Overriding2.cpp

18 18 오버라이딩 (overriding) 베이스클래스에서선언된함수를파생클래스에서다시선언 Overriding1.cpp #include <iostream> using std::endl; using std::cout; class AAA void fct() cout<<"aaa"<<endl; ; int main(void) BBB b; b.fct(); return 0; class BBB : public AAA void fct() cout<<"bbb"<<endl; ; BBB

19 19 오버라이딩예 Overriding2.cpp #include <iostream> using std::endl; using std::cout; class AAA void fct() cout<<"aaa"<<endl; ; class BBB : public AAA void fct() cout<<"bbb"<<endl; ; int main(void) BBB AAA BBB* b=new BBB; b->fct(); AAA* a=b; a->fct(); delete b; return 0;

20 20 Ex) EmployeeManager3.cpp #include <iostream> #include <cstring> using namespace std; class Employee private: char name[100]; Employee(char * name) strcpy(this->name, name); void ShowYourName() const cout<<"name: "<<name<<endl; ; class PermanentWorker : public Employee private: int salary; PermanentWorker(char * name, int money) : Employee(name), salary(money) int GetPay() const return salary; void ShowSalaryInfo() const ShowYourName(); cout<<"salary: "<<GetPay()<<endl<<endl; ; class TemporaryWorker : public Employee private: int worktime; int payperhour; TemporaryWorker(char * name, int pay) : Employee(name), worktime(0), payperhour(pay) void AddWorkTime(int time) worktime+=time; int GetPay() const return worktime*payperhour; void ShowSalaryInfo() const ShowYourName(); cout<<"salary: "<<GetPay()<<endl<<endl; ;

21 21 class SalesWorker : public PermanentWorker private: int salesresult; // 월판매실적 double bonusratio; // 상여금비율 SalesWorker(char * name, int money, double ratio) : PermanentWorker(name, money), salesresult(0), bonusratio(ratio) void AddSalesResult(int value) salesresult+=value; int GetPay() const return PermanentWorker::GetPay() // PermanentWorker의 GetPay 함수호출 ; (int)(salesresult*bonusratio); void ShowSalaryInfo() const ShowYourName(); cout<<"salary: "<<GetPay()<<endl<<endl; + class EmployeeHandler private: Employee* emplist[50]; int empnum; EmployeeHandler() : empnum(0) void AddEmployee(Employee* emp) emplist[empnum++]=emp; void ShowAllSalaryInfo() const /* for(int i=0; i<empnum; i++) emplist[i]->showsalaryinfo(); */ void ShowTotalSalary() const int sum=0; /* for(int i=0; i<empnum; i++) sum+=emplist[i]->getpay(); */ cout<<"salary sum: "<<sum<<endl; ~EmployeeHandler() for(int i=0; i<empnum; i++) delete emplist[i]; ;

22 22 int main(void) // 직원관리를목적으로설계된컨트롤클래스의객체생성 EmployeeHandler handler; // 정규직등록 handler.addemployee(new PermanentWorker("KIM", 1000)); handler.addemployee(new PermanentWorker("LEE", 1500)); // 임시직등록 TemporaryWorker * alba=new TemporaryWorker("Jung", 700); alba->addworktime(5); // 5시간일한결과등록 handler.addemployee(alba); // 영업직등록 SalesWorker * seller=new SalesWorker("Hong", 1000, 0.1); seller->addsalesresult(7000); // 영업실적 7000 handler.addemployee(seller); // 이번달에지불해야할급여의정보 handler.showallsalaryinfo(); // 이번달에지불해야할급여의총합 handler.showtotalsalary(); return 0;

23 가상함수 (Virtual Function)

24 24 가상함수 (virtual function) 가상함수는베이스클래스내에서정의된멤버함수를파생클래스에서재정의하고자할때사용 베이스클래스의멤버함수와같은이름을갖는함수를파생클래스에서재정의함으로써각클래스마다고유의기능을갖도록변경할때이용 파생클래스에서재정의되는가상함수는함수중복과달리베이스클래스와함수의반환형, 인수의갯수, 형이같아야함 가상함수를정의하기위해서는가장먼저기술되는상위클래스 ( 베이스클래스 ) 의멤버함수앞에 virtual이라는키워드로기술

25 25 가상함수예 Overriding3.cpp #include <iostream> using std::endl; using std::cout; class AAA virtual void fct() // 가상함수 cout<<"aaa"<<endl; ; class BBB : public AAA void fct() cout<<"bbb"<<endl; ; int main(void) BBB* b=new BBB; b->fct(); BBB BBB AAA* a=b; a->fct(); delete b; return 0;

26 26 가상함수특성상속예 Overriding4.cpp #include <iostream> using std::endl; using std::cout; class AAA virtual void fct() // 가상함수 cout<<"aaa"<<endl; ; class BBB : public AAA void fct() // virtual void fct() cout<<"bbb"<<endl; ; class CCC : public BBB void fct() cout<<"ccc"<<endl; ; int main(void) BBB* b=new BBB; b->fct(); CCC CCC AAA* a=b; a->fct(); delete b; return 0;

27 27 기초클래스의포인터로객체를참조하면, C++ 컴파일러는포인터연산의가능성여부를판단할때, 포인터의자료형을기준으로판단하 지, 실제가리키는객체의자료형을기준으로판단하지않는다.

28 28 앞서한이야기의복습 C++ 컴파일러는포인터를이용한연산의가능성여부를판단할때, 포인터의자료형을기준으로판단하지, 실제가리키는객체의자료형을기준으로판단하지않는다. 따라서포인터형에해당하는클래스의멤버에만접근이가능하다. 예제 EmployeeManager2.cpp 와 EmployeeManager3.cpp 의주석처리부분에서컴파일에러가발생하는이유는?

29 29 함수의오버라이딩과포인터형 실행결과 함수를호출할때사용이된포인터의형에따라서호출되는함수가결정된다! 포인터의형에정의된함수가호출된다.

30 30 가상함수 (Virtual Function) 오버라이딩된함수가 virtual 이면 오버라이딩한함수도자동 virtual 실행결과 포인터의형에상관없이포인 터가가리키는객체의마지막 오버라이딩함수를호출한다. 현상황에서의 EmployeeManager 클래스는모든객체를 Employee 객체로간주한다. 따라서호출하는함수 도 Employee 객체의멤버함수이다! 바로이러한문제의해결책이위의예제에있다!

31 31 급여관리확장성문제의해결과상속의이유 GetPay 함수와 ShowSalaryInfo 함수를 Virtual로선언하였으므로, EmpolyeeHandler가호출하는함수는 Employee 클래스의멤버함수일지라도실제호출되는함수는각포인터가가리키는객체의마지막오버라이딩함수이다! 이렇듯상속은연관된일련의클래스들에대해공통의규약을 적용할수있게해준다!

32 32 순수가상함수 순수가상함수 (pure virtual function) 베이스클래스에서는어떤동작도정의되지않고함수의선언만을하는가상함수 순수가상함수를선언하고파생클래스에서이가상함수를중복정의하지않으면컴파일시에에러가발생 하나이상의멤버가순수가상함수인클래스를추상클래스 (abstract class) 라함 완성된클래스가아니기때문에객체화되지않는클래스 베이스클래스에서다음과같은형식으로선언 virtual 자료형함수명 ( 인수리스트 ) = 0;

33 33 순수가상함수예 (1) #include <iostream> using std::endl; using std::cout; class Date // 베이스클래스 protected:` int year,month,day; Date(int y,int m,int d) year = y; month = m; day = d; virtual void print() = 0; // 순수가상함수 ; class Adate : public Date // 파생클래스 Adate Adate(int y,int m,int d) : Date(y,m,d) /* no operation */ void print() // 가상함수 cout << year << '.' << month << '.' << day << ".\n"; ; class Bdate : public Date // 파생클래스 Bdate Bdate(int y,int m,int d) : Date(y,m,d) /* no operation */ void print(); // 가상함수 ; void Bdate::print() static char *mn[] = "Jan.", "Feb.", "Mar.", "Apr.", "May", "June","July", "Aug.", "Sep.", "Oct.", "Nov.","Dec." ; cout << mn[month-1] << ' ' << day << ' ' << year << '\n'; int main() Adate a(1994,6,1); Bdate b(1945,8,15); Date &r1 = a, &r2 = b; // 참조자 r1.print(); r2.print(); return 0; Aug

34 34 순수가상함수와추상클래스 몸체가정의되지않은함수를가리켜순수가상함수라 하며, 하나이상의순수가상함수를멤버로두어서객체 생성이불가능한클래스를가리켜추상클래스라한다. 오버라이딩의관계를목적으로정의된함수들! 따라서몸체부분의정의는의미가없다! 순수가상함수로대체가능!

35 35 Ex) EmployeeManager5.cpp #include <iostream> #include <cstring> using namespace std; class Employee private: char name[100]; Employee(char * name) strcpy(this->name, name); void ShowYourName() const cout<<"name: "<<name<<endl; virtual int GetPay() const = 0; virtual void ShowSalaryInfo() const = 0; ; class PermanentWorker : public Employee private: int salary; PermanentWorker(char * name, int money) : Employee(name), salary(money) int GetPay() const return salary; void ShowSalaryInfo() const ShowYourName(); cout<<"salary: "<<GetPay()<<endl<<endl; ; class TemporaryWorker : public Employee private: int worktime; int payperhour; TemporaryWorker(char * name, int pay) : Employee(name), worktime(0), payperhour(pay) void AddWorkTime(int time) worktime+=time; int GetPay() const return worktime*payperhour; void ShowSalaryInfo() const ShowYourName(); cout<<"salary: "<<GetPay()<<endl<<endl; ;

36 36 class SalesWorker : public PermanentWorker private: int salesresult; // 월판매실적 double bonusratio; // 상여금비율 SalesWorker(char * name, int money, double ratio) : PermanentWorker(name, money), salesresult(0), bonusratio(ratio) void AddSalesResult(int value) salesresult+=value; int GetPay() const return PermanentWorker::GetPay() + (int)(salesresult*bonusratio); void ShowSalaryInfo() const ShowYourName(); cout<<"salary: "<<GetPay()<<endl<<endl; ; class EmployeeHandler private: Employee* emplist[50]; int empnum; EmployeeHandler() : empnum(0) void AddEmployee(Employee* emp) emplist[empnum++]=emp; void ShowAllSalaryInfo() const for(int i=0; i<empnum; i++) emplist[i]->showsalaryinfo(); void ShowTotalSalary() const int sum=0; for(int i=0; i<empnum; i++) sum+=emplist[i]->getpay(); ; cout<<"salary sum: "<<sum<<endl; ~EmployeeHandler() for(int i=0; i<empnum; i++) delete emplist[i];

37 37 int main(void) // 직원관리를목적으로설계된컨트롤클래스의객체생성 EmployeeHandler handler; // 정규직등록 handler.addemployee(new PermanentWorker("KIM", 1000)); handler.addemployee(new PermanentWorker("LEE", 1500)); // 임시직등록 TemporaryWorker * alba=new TemporaryWorker("Jung", 700); alba->addworktime(5); // 5시간일한결과등록 handler.addemployee(alba); // 영업직등록 SalesWorker * seller=new SalesWorker("Hong", 1000, 0.1); seller->addsalesresult(7000); // 영업실적 7000 handler.addemployee(seller); // 이번달에지불해야할급여의정보 handler.showallsalaryinfo(); // 이번달에지불해야할급여의총합 handler.showtotalsalary(); return 0;

38 38 바인딩 (binding) 과다형성 바인딩 정적바인딩 (static binding) 컴파일시 (compile-time) 호출되는함수를결정 동적바인딩 (dynamic binding) 실행시 (run-time) 호출되는함수를결정 다형성 (polymorphism) 같은모습의형태가다른특성 a->fct() 예 a 라는포인터 ( 모습 ) 가가리키는대상에따라호출되는함수 ( 형태 ) 가다름 함수오버로딩, 동적바인딩등이다형성의예

39 39 다형성 (Polymorphism) 지금까지공부한가상함수와관련된내용을 가리켜 다형성 이라한다! 다형성은동질이상의의미를갖는다. 모습은같은데형태는다르다. 문장은같은데결과는다르다! ptr->simplefunc 함수의호출이다형성의예!

40 가상소멸자와참조자의참조가능성

41 41 Virtual 소멸자의필요성 상속하고있는클래스객체소멸문제점

42 42 Virtual 소멸자의필요성 virtual 소멸자 virtual ~AAA() cout<<"~aaa() call!"<<endl; delete []str1;

43 43 virtual 소멸자 파생클래스를가리키는베이스클래스의포인터가가리키는객체의소멸시에는파생클래스의소멸자를호출하지않음 virtual 소멸자 객체소멸시베이스클래스뿐만아니라파생클래스의소멸자도호출 소멸자앞에 virtual 키워드

44 44 virtual 소멸자필요성예 #include <iostream> using std::endl; using std::cout; class AAA char* str1; AAA(char* _str1) str1= new char[strlen(_str1)+1]; strcpy(str1, _str1); ~AAA() cout<<"~aaa() call!"<<endl; delete []str1; virtual void ShowString() cout<<str1<<' '; ; class BBB : public AAA char* str2; BBB(char* _str1, char* _str2) : AAA(_str1) str2= new char[strlen(_str2)+1]; strcpy(str2, _str2); ; ~BBB() cout<<"~bbb() call!"<<endl; delete []str2; virtual void ShowString() AAA::ShowString(); cout<<str2<<endl; int main() AAA * a=new BBB("Good", "evening"); BBB * b=new BBB("Good", "morning"); a->showstring(); b->showstring(); cout<<"----- 객체소멸직전 ----"<<endl; delete a; // AAA 소멸자만호출 delete b; // BBB,AAA 소멸자호출 return 0; Good evening Good morning 객체소멸직전 ---- ~AAA() call! ~BBB() call! ~AAA() call!

45 45 virtual 소멸자예 #include <iostream> using std::endl; using std::cout; class AAA char* str1; AAA(char* _str1) str1= new char[strlen(_str1)+1]; strcpy(str1, _str1); virtual ~AAA() cout<<"~aaa() call!"<<endl; delete []str1; virtual void ShowString() cout<<str1<<' '; ; class BBB : public AAA char* str2; BBB(char* _str1, char* _str2) : AAA(_str1) str2= new char[strlen(_str2)+1]; strcpy(str2, _str2); ; ~BBB() cout<<"~bbb() call!"<<endl; delete []str2; virtual void ShowString() AAA::ShowString(); cout<<str2<<endl; int main() AAA * a=new BBB("Good", "evening"); BBB * b=new BBB("Good", "morning"); a->showstring(); b->showstring(); cout<<"----- 객체소멸직전 ----"<<endl; delete a; // BBB, AAA 소멸자만호출 delete b; // BBB,AAA 소멸자호출 return 0; Good evening Good morning 객체소멸직전 ---- ~BBB() call! ~AAA() call! ~BBB() call! ~AAA() call!

46 46 가상소멸자 (Virtual Destructor) 소멸자를가상으로선언함으로써각각의생성자내에서할당한메모리공간을효율적으로 해제할수있다.

47 47 참조자의참조가능성 실행결과

48 Q & A