다형성 이용의 위한 문법

Download Report

Transcript 다형성 이용의 위한 문법

발표자 : 2학년 이준식
담당교수 : 심재창 교수님
목차!!
목차
1. 다형성의 필요성
2. 다형성의 요점
3. 다형성 이용의 위한 문법
4. 다형성 실제구현
5. 완벽한 다형성 구현
다형성(Polymorphism)은 여러 개의 개별적인 클래
스를 하나의 부모 클래스 객체로 통합 관리하여 그
효율성을 높인것!
과자
(부모객체)
짱구
(자식객체)
쵸코칩
(자식객체)
새우깡
(자식객체)
다형성 필요성!!
다형성 필요성
예) 자료형 과자를 가지고 여러가지 짱구과자도 되
게 할수 있고 쵸코집이 될수도 있고 새우깡이 될수
도 있게 하여 하나의 자료형으로 편하게 사용하자!!
쵸코칩
쵸코칩
과자
(자식객체)
(부모객체)
짱구
과자
(자식객체)
(부모객체)
새우깡
과자
(자식객체)
(부모객체)
짱구
새우깡
그림설명!!
자료형이 3개가 생성이 되었다.
하지만 우리는 그냥 과자 라는
자료형만 표면적으로 나타나게
된다.
하지만 과자라는 객체를 가지고
무슨 자료형의 넣느냐에 따라서
우리는 쵸코칩, 짱구, 새우깡의
기능과 데이터를 모두사용할수
있게된다.
다형성 필요성!!
다형성 필요성
객
체
데이터
기능
(표면적 자료형)
객
체
데이터
기능
(실제자료형)
객
체
데이터
기능
(실제자료형)
여러가지 자료형의 담기위해서는 최소한으로 그 기능을 사용하는
이름은 같아줘야 한다 왜냐하면 기능을 이름이 동일하지 않다면 표
면적 자료형에서 어떻게 필요한 기능을 호출해서 쓸수 있겠는가? 그
릇은 준비되어 있는데 그릇의 사용법을 모르는것과 같은 이치이다.
다형성의 요점!!
다형성의 요점
그릇
::기능정보::
요점 !!
::데이터::
엔진
브레이크
변속기
::기능::
시동걸기
출발
정지
자동차(객체)
그릇은 최소한으로 기능정보를 가지고 여러
가지 다른객체를 관리하면서 이용하기 위해
서는 최소한으로 기능정보를 요구하게 되면
그릇에서 호출되는 기능은 그릇에 담기게 되
는 자료형의 기능과 동일해야 할것이다.
예) 그릇(도형) -> 객체(삼각형, 사각형) 이
런식으로 정의 되어 있다면 아마도 동일한
기능이 구현되게 될것이다.
그리기기능이 그릇에 들어가는 객체에 따라
서 아마 거기에 맞는 도형이 그려지게 될것
이다.
다형성의 요점!!
다형성의 요점
1. 함수 오버라이딩
2. 객체(상속상태) 포인터
3. 객체(상속상태) 레퍼런스
4. Virtual 함수
객체 포인터와 객체 레퍼런스는 실제자료형을 선언할경우 그
값을 넣기위해 변수형이 필요하게된다. 그것에 대한 특징을
학습하게 된다. 그리고 다형성을 기능구현의 위해 함수이름을
같게 선언하게 될것이다 만약 그렇게 된다면 오버라이딩의 특
징이 발현하게 될것이다.그리고 우리는 그릇에 데이터를 넣게
되면 함수 호출 범위를 축소가 일어나게 되므로 가상함수라는
기법을 학습함으로 다형성이라는 기능을 구현하게 될것이다.
다형성이용의 위한 문법!!
다형성 이용의 위한 문법
#include <iostream>
using namespace std;
class CParent{
public:
void Prn(){cout<<"Parent"<<endl;}
};
class CSon : public CParent {
public:
void Prn(){cout<<"Cson"<<endl;}
};
void main(){
CSon b;
b.Prn();
}
다형성이용의 위한 문법!!
함수오버라이딩
CSon b 객체
CParent 객체
함수 -> void Prn()
CSon 객체
함수 -> void Prn()
상속에서 부모객체의
함수와 같은 이름의
자식 객체 함수를 선
언하게 될경우 부모객
체의 함수가 자식의
객체에 의해서 가려지
게 된다.
이것을 가리켜 함수
오버라이딩 이라고 한
다.
CSon 객체에 의해서 CParent객체의 Prn()함수가 가려지게 되었다.
다형성이용의 위한 문법!!
함수오버라이딩
#include <iostream>
using namespace std;
class CParent{
public:
void Prn(){cout<<"Parent"<<endl;}
};
class CSon : public CParent {
public:
void Prn(){cout<<"Son"<<endl;}
};
void main(){
CParent* p1 = new CParent();
CParent* p2 = new CSon();
p1->Prn();
p2->Prn();
CParent* p3 = new CParent();
CSon* p4 = (CSon*)new CParent();
p3->Prn();
p4->Prn();
}
다형성이용의 위한 문법!!
객체 (상속상태) 포인터
void main(){
CParent* p1 = new CParent();
CParent* p2 = new CSon();
p1->Prn();
p2->Prn();
}
CParent
(부모객체)
CParent *p1
CParent *p2
CParent
(부모객체)
CSon
(자식객체)
두개의 결과 값이 모두 “Parent”를 출력하고 있는것으로
보아 포인터의 변화로 범위가 축소가 일어나게 되면 그
축소된 함수가 호출되는것으로 보인다.
다형성이용의 위한 문법!!
객체 (상속상태) 포인터
void main(){
CParent* p3 = new CParent();
CSon* p4 = (CSon*)new CParent();
p3->PrnParent();
p4->PrnParent();
}
CParent
(부모객체)
CParent *p3
CSon *p4
CParent
(부모객체)
두개의 결과 값이“Parent”과 “ Son”를 출력하고 있는것으로 보아 포인
터의 변화로 범위가 확장이가 일어나게 되면 활당된 객체의 함수가 호
출하게 된다. 하지만 이건 캐스팅에 의해 컴파일러에게 캐스팅된 형으
로 인지하게되므로 실행되는것 처럼 보이는 것이다. 하지만 이방법은
메모리값을 잘못된 접근을 야기하게 되므로 절대 이런 실수를 해서는
않되는 것이다.
다형성이용의 위한 문법!!
객체 (상속상태) 포인터
포인터에 의한 범위 축소인 경우에는 축소된 객체의
함수까지만 호출이 가능하다.
포인터에 의한 범위 확장은 확장된 함수도 호출한다.
- 하지만 이건 잘못된 메모리접근을 하므로 절대로 해
서는 않될 방법이다.
다형성이용의 위한 문법!!
객체 (상속상태) 포인터
CParent p3;
CParent p4;
#include <iostream>
using namespace std;
class CParent{
public:
void Prn(){cout<<"Parent"<<endl;}
};
class CSon : public CParent {
public:
void Prn(){cout<<"Son"<<endl;}
};
void main(){
CParent p1;
CSon p2;
CParent& ref_p1 = p1;
CParent& ref_p2 = p2;
ref_p1.Prn();
ref_p2.Prn();
CParent& ref_p3 = p3;
//CSon& ref_p4 = p4;
ref_p3.Prn();
//ref_p4.Prn();
}
다형성이용의 위한 문법!!
객체 (상속상태) 레퍼런스
void main(){
CParent p1;
CSon p2;
CParent& ref_p1 = p1;
CParent& ref_p2 = p2;
ref_p1.Prn();
ref_p2.Prn();
}
CParent
(부모객체)
CParent& ref_p1
Cparent& ref_p2
CParent
(부모객체)
CSon
(자식객체)
두개의 결과 값이 모두 “Parent”를 출력하고 있는것
으로 보아 레퍼런스 범위가 축소가 일어나게 되면
그 축소된 함수가 호출되는것으로 보인다.
다형성이용의 위한 문법!!
객체 (상속상태) 레퍼런스
void main(){
CParent p3;
CParent p4;
CParent& ref_p3 = p3;
//CSon& ref_p4 = p4;
CParent
(부모객체)
ref_p3.Prn();
//ref_p4.Prn();
}
CParent *p3
CSon *p4
CParent
(부모객체)
한 개의 결과 값만 “Parent”출력하고 한 개는 컴파일에러
가 발생하게된다. 이 결과로 확인 해볼때 레퍼런스의 범위
확대는 일어 날수 없다고 볼 수 있다.
다형성이용의 위한 문법!!
객체 (상속상태) 레퍼런스
레퍼런스에 의한 범위 확장은 레퍼런스에 값을 넣을수
없으며 확장자체가 일어나지 못한다.
레퍼런스에 의한 범위 축소인 경우에는 축소된 객체의
함수까지만 호출이 가능하다.
다형성이용의 위한 문법!!
객체 (상속상태) 레퍼런스
#include <iostream>
using namespace std;
class CParent{
public:
virtual void Prn(){cout<<"Parent"<<
endl;}
};
class CSon : public CParent {
public:
void Prn(){cout<<"Son"<<endl;}
};
void main(){
CParent *p = new CSon();
p->Prn();
}
다형성이용의 위한 문법!!
Virtual 함수
void main(){
CParent *p = new CSon();
Cson* CParent*
p->Prn();
}
CParent *p
CParent
CSon
Cson의 객체의 Prn()호출
포인터의 객체 범위 축소에 의해서 분명히 Parent가 출
력되어야 하나 가상함수가 선언되어 있기 때문에 Son이
출력되었다. 이결과를 보면 virtual선언으로 인해서 Cso
n의 객체함수가 호출 되었다.
다형성이용의 위한 문법!!
Virtual 함수
#include <iostream>
using namespace std;
class AAA{
public:
virtual void Prn(){cout<<"AAA"<<endl;}
};
class BBB : public AAA {
public:
void Prn(){cout<<"BBB"<<endl;}
};
class CCC : public BBB {
public:
void Prn(){cout<<"CCC"<<endl;}
};
void main(){
CCC p;
p.Prn();
AAA& ref_p = p;
ref_p.Prn();
}
다형성이용의 위한 문법!!
Virtual 함수
void main(){
CCC p;
p.Prn();
AAA& ref_p = p;
ref_p.Prn();
}
AAA& ref_p
AAA 객체
virtual void Prn();
BBB 객체
virtual void Prn();
호
출
호
출
CCC 객체
virtual void Prn();
Virtual은 분명히 최상위 클래스 한번만 선언하였지만 상
속하면 vitual 특성까지 상속되는 모습을 보여주고 있다.
그러므로 최종적으로 오버라이딩한 함수를 제외한 나머
지 함수는 가려지게된다.
다형성이용의 위한 문법!!
Virtual 함수
일단 구현으로는 담을 그릇으로 동물이라는 객체를 가지며 거기에는
개, 고양이, 돼지등의 자료형을 넣어서 사용하여 구현하는 다형성을 만
들어 보겠습니다.
1. 구현은 구현하게될 CAnimal(동물)이라는 객체를 생성하고 거기에
다 필요한 비슷하게 연관이 있는 객체를 상속 하게 됩니다.
자식 객체로는 CDog(개), CCat(고양이), CPig() (돼지)등을 생성해
서 상속 처리 하게 됩니다.
부모
CAnimal
(동물)
상속
자식
CDog
(개)
상속
상속
자식
자식
CCat
(고양이)
CPig
(돼지)
다형성 실제구현!!
다형성 실제구현
2. 상속으로 구현하게 되면 CAnimal(동물)포인터나 레퍼런스에 객체
를 넣게 되면 범위의 축소가 일어나게 됩니다. 만약 그렇게 되면함
수 호출이 불가능하게 될것입니다.
그것을 막기 위해 Virtual함수를 이용해서 자식 객체함수를 호출
할수 있도록 처리 해야 할것입니다.
함수호출 범위
CAnimal* or CAnimal&
CAnimal
부모객체
자식객체
기
능
호
출
다형성 실제구현!!
다형성 실제구현
#include <iostream>
using namespace std;
class CAnimal
{
public:
virtual void Prn(){ }
};
void main(){
CAnimal* p1 = new CDog();
CAnimal* p2 = new CCat();
CAnimal* p3 = new CPig();
cout<<"포인터 이용!!"<<endl;
p1->Prn();
p2->Prn();
p3->Prn();
class CDog : public CAnimal
{
public:
void Prn(){ cout<<"멍멍!!"<<endl; }
};
class CCat : public CAnimal
{
public:
void Prn(){ cout<<"야옹!!"<<endl; }
};
CAnimal& ref_p1 = *p1;
CAnimal& ref_p2 = *p2;
CAnimal& ref_p3 = *p3;
cout<<"레퍼런스 이용!!"<<endl;
ref_p1.Prn();
ref_p2.Prn();
ref_p3.Prn();
}
class CPig : public CAnimal
{
public:
void Prn(){ cout<<"꿀꿀!!"<<endl; }
};
다형성 실제구현!!
다형성 실제구현
void main(){
CAnimal* p1 = new CDog();
CAnimal* p2 = new CCat();
CAnimal* p3 = new CPig();
cout<<"포인터 이용!!"<<endl;
p1->Prn();
p2->Prn();
p3->Prn();
CAnimal에 들어가 있는 자료
형에 따라서 적절한 기능
을 호출 하고 있음!!
CAnimal& ref_p1 = *p1;
CAnimal& ref_p2 = *p2;
CAnimal& ref_p3 = *p3;
cout<<"레퍼런스 이용!!"<<endl;
ref_p1.Prn();
ref_p2.Prn();
ref_p3.Prn();
}
포인터인가 레퍼런스인가
의 차이일뿐 동일한 역할
을 하고 있음!!
다형성 실제구현!!
다형성 실제구현
다형성 만든 클래스에 아직까지 약간의 문제점이 있다.
1. CAnimal객체의 prn은 호출이 될필요가 없다.
그리고 CAnimal은 혼자서 객체화 되지 않아도
된다.
2. 자식클래스의 소멸자가 호출되어야 한다.
(동적메모리 활당 및 해체, 객체 소멸시 처리
를 위하여)
다형성 완벽한 실제구현!!
다형성 완벽한 구현
문제1 해결방안
class CAnimal
{
public:
virtual void Prn(){ }
};
class CAnimal
{
public:
virtual void Prn() = 0;
};
위의 코드 = 0; 의 의미는 순수가상함수의 의미이다.
하나이상의 순수가상함수를 선언한 클래스를 가리켜
추상(abstract) 클래스라고 하며 이클래스의 특징은 객
체화하지 못한다. 함수의 정의가 생략되어 있으므로
완전한 클래스가 아니므로 생성을 방지하는것이다.
CAnimal은 객체화 될 필요없는 클래스이므로 객체화 된다면
프로그래머의 실수이다.
다형성 완벽한 실제구현!!
다형성 완벽한 구현
문제2 해결방안
#include <iostream>
using namespace std;
class CAnimal
{
public:
virtual void Prn() = 0;
~CAnimal(){
cout<<"CAnimal소멸자 호출 !!"<<endl; }
};
class CDog : public CAnimal
{
public:
void Prn(){ cout<<"멍멍!!"<<endl; }
~CDog(){
cout<<"CDog소멸자 호출 !!"<<endl; }
};
void main(){
CAnimal* p1 = new CDog();
delete p1;
}
문제점
현재 생성은 CDog자료형
의 객체화 하였는데 현재
소멸자는 CAnimal만 호출
되고 있다 이렇게되면 CD
og는 적절한 소멸자 해체
가 않되어 동적메모리활당
등 객체가 소멸시 필요한
처리를 못해주게 되는 문
제점이 발생하게 된다.
다형성 완벽한 실제구현!!
다형성 완벽한 구현
#include <iostream>
using namespace std;
class CAnimal
{
public:
virtual void Prn() = 0;
virtual ~CAnimal(){
cout<<"CAnimal소멸자 호출 !!"<<endl; }
};
class CDog : public CAnimal
{
public:
void Prn(){ cout<<"멍멍!!"<<endl; }
~CDog(){
cout<<"CDog소멸자 호출 !!"<<endl; }
};
void main(){
CAnimal* p1 = new CDog();
delete p1;
}
문제점 해결
CDog의 객체소멸자와
CAnimal의 객체소멸자
를 잘호출 해주고 있는
것으로 보인다.
다형성 완벽한 실제구현!!
다형성 완벽한 구현
다형성 실제구현!!
다형성 완벽한 구현
오류 소스코드
CAnimal*
호출끝
객체소멸
수정 소스코드
~CAnimal()
(CAnimal객체)
vitual ~CAnimal()
~CDog()
(CDog객체)
(CAnimal객체)
호출
호출끝
~CDog()
(CDog객체)
대
신
호
출
감사합니다!!