• 검색 결과가 없습니다.

15장 기타 주제들

N/A
N/A
Protected

Academic year: 2022

Share "15장 기타 주제들"

Copied!
15
0
0

로드 중.... (전체 텍스트 보기)

전체 글

(1)

C++ 프로그래밍 입문

15장 기타 주제들

auto_ptr 변환함수

cast 연산자에 의한 명시적 형변환

실행시간 타입 정보 알아내기(RTTI)

(2)

1. auto_ptr

다음 프로그램의 문제점은 무엇인가?

void func(void) {

int *p = new int;

cout << "양수 입력 : ";

cin >> *p;

if (*p <= 0) {

cout << "양수를 입력해야 합니다" << endl;

return;

}

cout << "입력 값 : " << *p << endl;

delete p;

}

int main(void) {

for (int i = 0; i < 10; i++) func();

return 0;

동적 할당 메모리를 해제하지 않고 리턴

int *p = new int;

변수p가 사라지는 경우

동적으로 할당받은 메모리도 헤제할 수 있는 방법은 없을까???

(3)

1. auto_ptr

자동으로 해제 가능한 포인터 클래스 만들기

template <typename T>

class AutoPtr { private :

T *ptr;

public :

AutoPtr(T *p) : ptr(p) { } // 새로 할당한 메모리를 ptr에 대입 T &operator*() { return (*ptr); } // 역참조 연산자

~AutoPtr() { delete ptr; } // 소멸자를 통해 delete 수행 };

int main(void) {

AutoPtr<int> p(new int); // 동적 할당 및 AutoPtr 객체 생성

*p = 5;

cout << *p << endl;

return 0;

}

내부적으로 포인터를 가지고 있음

함수가 끝날 때 à 지역변수 p 해제

à 소멸자에 의해 동적 할당 메모리 해제!

(4)

1. auto_ptr

표준 C++ : auto_ptr 클래스 템플릿 제공

n <memory> 헤더 파일 포함

n 배열에 대한 동적 생성 및 해제 자동화 불가

#include <iostream>

#include <memory>

using namespace std;

int main(void) {

auto_ptr<int> p(new int);

*p = 5;

cout << *p << endl;

return 0;

}

(5)

2. 변환함수

상속 관계에 있는 객체들 사이의 대입 관련 복습 (9.2절)

n base 클래스 객체 = derived 클래스 객체 : 대입 가능

n 그 외는 불가능

다음과 같은 대입이 가능하도록 만들려면 어떻게 해야 할까?

class base { ... };

class derived : public base { ... };

class another { ... };

base b; derived d; another a; int i;

b = d; // ① O, base 객체 = derived 객체 d = b; // ② X, derived 객체 = base 객체 a = b; // ③ X, another 객체 = base 객체 b = i; // ④ X, base 객체 = int 변수 i = b; // ⑤ X, int 변수 = base 객체

1. 자동으로 가능한 경우는?

2. 대입 연산자 오버로딩으로 가능한 경우는?

3. 지금까지 배운 것만으로는 불가능한 경우는?

(6)

2. 변환함수

대입 연산자 오버로딩을 사용한 대입 해결 : ②, ③, ④

class base { public :

int x;

base(int a = 0) { x = a; } // ④의 해결, int à base 형변환 void show(void) { cout << "base : " << x << endl; }

};

class derived : public base { public :

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) { // ②의 해결, 대입 연산자 오버로딩 x = b.x;

y = b.x;

}

int 값이 base 객체로 형변환 된 후 대입됨

(7)

2. 변환함수

대입 연산자 오버로딩을 사용한 대입 해결 : ②, ③, ④ (계속)

class another { public :

double z;

another(double c = 0) { z = c; }

void show(void) { cout << "another : " << z << endl; }

void operator=(const base &b) { // ③의 해결, 대입 연산자 오버로딩 z = b.x;

} };

int main(void) {

base b; derived d; another a; int i = 1;

b = d; // ① O, base 객체 = derived 객체 d = b; // ② O, derived 객체 = base 객체 a = b; // ③ O, another 객체 = base 객체 b = i; // ④ O, base 객체 = int 변수 //i = b; // ⑤ X, int 변수 = base 객체 return 0;

불가능?

해결 방법은? à 변환함수!

(8)

2. 변환함수

변환함수를 이용한 ⑤(int 변수 = base 객체)의 해결

n 변환함수 문법 : operator int() { …; return int값; }

class base { public :

int x;

base(int a = 0) { x = a; }

void show(void) { cout << "base : " << x << endl; }

operator int(); //{ return (x * x); } // ⑤의 해결, 변환함수 };

base::operator int() // 외부 정의 {

return (x * x);

} ②, ③의 경우 대입 연산자 오버로딩을

사용하지 않고 변환함수로 해결 가능 à 연습 문제 15.3

(9)

3. cast 연산자에 의한 명시적 형변환

C 스타일의 명시적 형변환

n (타입명) 변수명;

n 형변환 예

C++ : C 스타일 사용 가능

n 다양한 형변환을 구별하기 위한 4개의 명시적 형변환 연산자 제공

n dynamic_cast, const_cast, static_cast, reinterpret_cast

class Base { };

class Derived : public Base { };

class Another { };

int i; int *p; double d; Base *b; Derived *d; Another *a;

i = (int) d; // ① 가능, 묵시적 형변환 가능

p = (int *) &d; // ② 가능 p = (int *) b; // ③ 가능

b = (Base *) d; // ④ 가능, 묵시적 형변환 가능 d = (Derived *) b; // ⑤ 가능

b = (Base *) a; // ⑥ 가능

현재b가 derived 객체를 가리킨다면? Ok!

base 객체를 가리킨다면? 논리적 오류 가능!

진짜 원한 것인가?

(10)

3. cast 연산자에 의한 명시적 형변환

dynamic_cast

n 상속 관계인 클래스 객체 포인터 또는 참조에 대해 적용 가능

n 가상 함수를 포함하고 있어야 함

class Base { public :

int b;

virtual void func() { cout << "Base" << endl; };

};

class Derived : public Base { public :

int d;

void func() { cout << "Derived" << endl; } };

int main(void)

{ Base *b = new Derived(); //Base *b = new Base(); // 바꾸어 수행해 보라.

Derived *d = dynamic_cast<Derived *> (b); // b가 가리키는 주소 대입 if (d == NULL)

cout << "형변환 실패" << endl;

elsecout << "형변환 성공" << endl;

b가 Derived 객체를 가리키고 있다면à성공 Base 객체를 가리키고 있다면àNULL

VC++ 6.0의 경우 컴파일 옵션으로 /GR 추가

(11)

3. cast 연산자에 의한 명시적 형변환

static_cast

n 상속 관계인 클래스 객체 포인터 또는 참조에 대해 적용 가능

n 앞의 예에서 Base *b = new Base(); 인 경우에도 형변환 성공

const_cast

n 포인터 변수값을 const형에서 일반형으로, 일반형에서 const형으로 변환

n const를 제외하면 동일한 포인터 타입인 경우 형변환 가능

int main(void) {

const double *pi = new double(3.14);

double *pi2 = const_cast<double *> (pi);

*pi2 = 3.14159;

cout << *pi << endl;

cout << *pi2 << endl;

return 0;

}

(12)

3. cast 연산자에 의한 명시적 형변환

reinterpret_cast

n

서로 무관한 타입 사이의 형변환 가능

Ø int형과 포인터형

Ø 무관한 클래스 포인터 사이의 형변환

n

Derived 클래스와는 무관한 Another 클래스가 있을 경우

Ø Base *b = new Base();

Ø Another *a = reinterpret_cast<Another *> (b); // 형변환 가능

C++ 명시적 형변환 연산자의 역할

n

안전한 형변환 제공

n

가독성 증가 : 상황을 보다 쉽게 파악할 수 있음

(13)

4. 실행시간 타입 정보 알아내기 (RTTI)

다음과 같이 실행 도중에 base 포인터가 가리키고 있는 객체의 타입 을 알 수 있을까?

n derived 객체인 경우 derived 객체에만 있는 멤버 함수 호출을 원함

void main(base *bp) {

if (bp가 가리키는 객체의 타입이 base이면) bp->func1();

else (bp가 가리키는 객체의 타입이 derived이면) { derived *dp = (derived *) bp;

dp->onlyDerivedFunc();

} }

(14)

4. 실행시간 타입 정보 알아내기 (RTTI)

dynamic_cast를 이용한 간접적 해결

class Base { public :

int b;

virtual void func() { cout << "Base" << endl; };

};

class Derived : public Base { public :

int d;

void func() { cout << "Derived" << endl; } void func2() { cout << "func2" << endl; } };

int main(void) {

Base *b = new Derived();

Derived *d = dynamic_cast<Derived *> (b); // 가능하다면 Derived로 변환 if (d == NULL) // Base 객체임

cout << "형변환 실패" << endl;

else // Derived 객체임

d->func2();

(15)

4. 실행시간 타입 정보 알아내기 (RTTI)

RTTI(RunTime Type Information)

n 변수, 포인터, 타입에 대한 정보를 알아낼 수 있는 방법 제공

n 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인지 알아낼 수 있다.

int main(void)

{ Base *b = new Derived();

Derived *d;

if (typeid(*b) == typeid(Derived)) { // b 객체가 Derived 객체인지 검사 d = (Derived *) b;

cout << typeid(*d).name() << endl;

d->func2();

}else

cout << "Derived 객체가 아닙니다" << endl;

return 0;

<typeinfo> 헤더 파일 포함

VC++ 6.0의 경우 컴파일 옵션으로 /GR 추가

참조

관련 문서

노르웨이에서는 연간 1 Mt의 이산화탄소를 Sleipner 지역의 대수층에 저장하고 있다... 알려져 있다(IPCC Special Report on Carbon Dioxide

허나 노 르웨이 연구자들에 의해 개발, 상업화된 오염된 물에 가스 하이드레이트를 형성시켜 농축된 오염물질과 공업용수 수준의 물로 회수하는 기술이 나타나면서 점차 대규모

• 이처럼 그래픽 정보를 기반으로 사용자가 프로그램에 명령을 내리거나, 출력 결과를 얻는 것을 GUI(그래픽 유저 인터페이 스)라고 함. 지금까지 배운 프로그래밍 과목에서는

• 조작자가 마치 현장에 있는 것처럼 느끼면서 작업을 제어 현실감(Reality) 또는 원격 현장감(Tele-presence).

이러한 관점에서 자기자본비율규제에 대한 명시적 제재수단으로서 적기시정조치가 도입되는 것이 바람직하다고 본다... 여기서는 대 표적 자기자본비율규제와

타입 매개 변수 사용하지 않는 경우 경고 발생9. Vector&lt;Integer&gt; 로 타입 매개

15장 BOA 웹서버 구동하기 n Makefile에서 CC와 CPP를 arm-linux-gcc로 바꾸어 준다... User nobody

– 윈도우 애플리케이션은 대개 그래픽 사용자 인터페이스 (GUI, Graphical User Interface)를 기반으로 하며, 메시지 구동 방식으로 동작하므로 이를 위한 확장