15 장기타주제들 auto_ptr 변환함수 cast 연산자에의한명시적형변환실행시간타입정보알아내기 (RTTI) C++ 프로그래밍입문
1. auto_ptr 다음프로그램의문제점은무엇인가? void func(void) int *p = new int; cout << " 양수입력 : "; cin >> *p; if (*p <= 0) cout << " 양수를입력해야합니다 " << endl; return; 동적할당메모리를해제하지않고리턴 cout << " 입력값 : " << *p << endl; delete p; for (int i = 0; i < 10; i++) func(); int *p = new int; 변수 p 가사라지는경우동적으로할당받은메모리도헤제할수있는방법은없을까??? 15 장기타주제들 1
1. auto_ptr 자동으로해제가능한포인터클래스만들기 template <typename T> class AutoPtr private : T *ptr; 내부적으로포인터를가지고있음 AutoPtr(T *p) : ptr(p) T &operator*() return (*ptr); ~AutoPtr() delete ptr; ; // 새로할당한메모리를 ptr에대입 // 역참조연산자 // 소멸자를통해 delete 수행 AutoPtr<int> p(new int); *p = 5; cout << *p << endl; // 동적할당및 AutoPtr 객체생성 함수가끝날때 à 지역변수 p 해제 à 소멸자에의해동적할당메모리해제! 15 장기타주제들 2
1. auto_ptr 표준 C++ : auto_ptr 클래스템플릿제공 <memory> 헤더파일포함 배열에대한동적생성및해제자동화불가 #include <iostream> #include <memory> using namespace std; auto_ptr<int> p(new int); *p = 5; cout << *p << endl; 15 장기타주제들 3
2. 변환함수 상속관계에있는객체들사이의대입관련복습 (9.2절) base 클래스객체 = derived 클래스객체 : 대입가능 그외는불가능다음과같은대입이가능하도록만들려면어떻게해야할까? class base... ; class derived : public base... ; class another... ; base b; derived d; another a; int i; b = d; d = b; a = b; b = i; i = b; // 1 O, base 객체 = derived 객체 // 2 X, derived 객체 = base 객체 // 3 X, another 객체 = base 객체 // 4 X, base 객체 = int 변수 // 5 X, int 변수 = base 객체 1. 자동으로가능한경우는? 2. 대입연산자오버로딩으로가능한경우는? 3. 지금까지배운것만으로는불가능한경우는? 15 장기타주제들 4
2. 변환함수 대입연산자오버로딩을사용한대입해결 : 2, 3, 4 class base int x; int 값이 base 객체로형변환된후대입됨 ; base(int a = 0) x = a; // 4의해결, int à base 형변환 void show(void) cout << "base : " << x << endl; class derived : public base int y; ; derived(int a = 0, int b = 0) : base(a) y = b; void show(void) base::show(); cout << "derived : " << y << endl; void operator=(const base &b) // 2의해결, 대입연산자오버로딩 x = b.x; y = b.x; 15 장기타주제들 5
2. 변환함수 대입연산자오버로딩을사용한대입해결 : 2, 3, 4 ( 계속 ) class another double z; ; another(double c = 0) z = c; void show(void) cout << "another : " << z << endl; void operator=(const base &b) // 3의해결, 대입연산자오버로딩 z = b.x; base b; derived d; another a; int i = 1; b = d; // 1 O, base 객체 = derived 객체 d = b; // 2 O, derived 객체 = base 객체 a = b; // 3 O, another 객체 = base 객체 b = i; // 4 O, base 객체 = int 변수 //i = b; // 5 X, int 변수 = base 객체 불가능? 해결방법은? à 변환함수! 15 장기타주제들 6
2. 변환함수 변환함수를이용한 5(int 변수 = base 객체 ) 의해결 변환함수문법 : operator int() ; return int 값 ; class base int x; ; base(int a = 0) x = a; void show(void) cout << "base : " << x << endl; operator int(); // return (x * x); // 5 의해결, 변환함수 base::operator int() // 외부정의 return (x * x); 2, 3 의경우대입연산자오버로딩을사용하지않고변환함수로해결가능 à 연습문제 15.3 15 장기타주제들 7
3. cast 연산자에의한명시적형변환 C 스타일의명시적형변환 ( 타입명 ) 변수명 ; 형변환예 class Base ; class Derived : public Base ; class Another ; int i; int *p; double d; Base *b; Derived *d; Another *a; i = (int) d; // 1 가능, 묵시적형변환가능 p = (int *) &d; // 2 가능 p = (int *) b; // 3 가능현재 b가 derived 객체를가리킨다면? Ok! b = (Base *) d; // 4 가능, 묵시적 base 형변환객체를가리킨다면가능? 논리적오류가능! d = (Derived *) b; // 5 가능 b = (Base *) a; // 6 가능 진짜원한것인가? C++ : C 스타일사용가능 다양한형변환을구별하기위한 4개의명시적형변환연산자제공 dynamic_cast, const_cast, static_cast, reinterpret_cast 15 장기타주제들 8
3. cast 연산자에의한명시적형변환 dynamic_cast 상속관계인클래스객체포인터또는참조에대해적용가능 가상함수를포함하고있어야함 VC++ 6.0의경우컴파일옵션으로 class Base /GR 추가 int b; virtual void func() cout << "Base" << endl; ; ; class Derived : public Base int d; void func() cout << "Derived" << endl; ; Base *b = new Derived(); //Base *b = new Base(); // 바꾸어수행해보라. Derived *d = dynamic_cast<derived *> (b); // b 가가리키는주소대입 if (d == NULL) cout << " 형변환실패 " << endl; else cout << " 형변환성공 " << endl; b 가 Derived 객체를가리키고있다면 à 성공 Base 객체를가리키고있다면 ànull 15 장기타주제들 9
3. cast 연산자에의한명시적형변환 static_cast 상속관계인클래스객체포인터또는참조에대해적용가능 앞의예에서 Base *b = new Base(); 인경우에도형변환성공 const_cast 포인터변수값을 const 형에서일반형으로, 일반형에서 const 형으로변환 const 를제외하면동일한포인터타입인경우형변환가능 const double *pi = new double(3.14); double *pi2 = const_cast<double *> (pi); *pi2 = 3.14159; cout << *pi << endl; cout << *pi2 << endl; 15 장기타주제들 10
3. cast 연산자에의한명시적형변환 reinterpret_cast 서로무관한타입사이의형변환가능 int형과포인터형 무관한클래스포인터사이의형변환 Derived 클래스와는무관한 Another 클래스가있을경우 Base *b = new Base(); Another *a = reinterpret_cast<another *> (b); // 형변환가능 C++ 명시적형변환연산자의역할 안전한형변환제공 가독성증가 : 상황을보다쉽게파악할수있음 15 장기타주제들 11
4. 실행시간타입정보알아내기 (RTTI) 다음과같이실행도중에 base 포인터가가리키고있는객체의타입을알수있을까? void main(base *bp) if (bp가가리키는객체의타입이 base이면 ) bp->func1(); else (bp가가리키는객체의타입이 derived이면 ) derived *dp = (derived *) bp; dp->onlyderivedfunc(); derived 객체인경우 derived 객체에만있는멤버함수호출을원함 15 장기타주제들 12
4. 실행시간타입정보알아내기 (RTTI) dynamic_cast 를이용한간접적해결 class Base int b; virtual void func() cout << "Base" << endl; ; ; class Derived : public Base int d; void func() cout << "Derived" << endl; void func2() cout << "func2" << endl; ; Base *b = new Derived(); Derived *d = dynamic_cast<derived *> (b); // 가능하다면 Derived 로변환 if (d == NULL) // Base 객체임 cout << " 형변환실패 " << endl; else // Derived 객체임 d->func2(); 15 장기타주제들 13
4. 실행시간타입정보알아내기 (RTTI) RTTI(RunTime Type Information) 변수, 포인터, 타입에대한정보를알아낼수있는방법제공 typeid 연산자 à type_info 클래스객체의참조반환 int a, b; cout << typeid(a).name() << endl; // 변수가올수도있다. cout << typeid(int).name() << endl; // 타입이올수도있다. if (typeid(a) == typeid(b))... // 두변수의타입이같은지비교할수있다. if (typeid(a) == typeid(int))... // 변수의타입이 int 인지알아낼수있다. Base *b = new Derived(); Derived *d; <typeinfo> 헤더파일포함 VC++ 6.0 의경우컴파일옵션으로 /GR 추가 if (typeid(*b) == typeid(derived)) // b 객체가 Derived 객체인지검사 d = (Derived *) b; cout << typeid(*d).name() << endl; d->func2(); else cout << "Derived 객체가아닙니다 " << endl; 15 장기타주제들 14