119
C++ 프프프프프 프 프프 2014. 6. 17 ( 프 ) 프 프 프 1

C++프로그래밍 및 실무_06.17.pptx

  • Upload
    dotuyen

  • View
    230

  • Download
    5

Embed Size (px)

Citation preview

Page 1: C++프로그래밍 및 실무_06.17.pptx

C++ 프로그래밍 및 실무

2014. 6. 17 ( 화 )유 승 현

1

Page 2: C++프로그래밍 및 실무_06.17.pptx

2

강의 계획

• 세션 1– C++ 문법

• 메모리 관련 , 클래스 , 템플릿• STL, 예외처리 , …

• 세션 2– 개발 실무 기초

• 소스코드 형상 관리 (svn, git)• 디버깅 테크닉• 코드 의존성 줄이기 솔직히 다할 수 있을지…

Page 3: C++프로그래밍 및 실무_06.17.pptx

3

Why C++?• 다른 프로그래밍 언어들의 대두

– Java, C#, Python, JavaScript, PHP, Object-C, ...• 웹 , 스마트폰 선호 , 상대적으로 낮아진 일반 application

• Native 언어– 장점 : 빠른 속도 & 완전한 컨트롤– 단점 : 상대적으로 낮은 생산성 ( 귀찮음… ), 이식성 ( 컴파일 다시

해야함 )

• 중요 모듈 및 성능이 중요한 프로젝트는 C++ 로 작성• 계속 진화 중인 언어 표준 C++98 > C++11 > C++14

Page 4: C++프로그래밍 및 실무_06.17.pptx

4

C++ Hello World 프로그램

#include "stdafx.h"#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

cout << "Hello World" << endl;int x;cin >> x;

return 0;}

#include "stdafx.h"#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[]){

printf("Hello World\n");int x;scanf("%d", &x);

return 0;}

C 에서의 구현• 다른점 ? #include <iostream>? using namespace? cout? >>? <<?

Page 5: C++프로그래밍 및 실무_06.17.pptx

5

C++: Multi-paradigm Programming Language

C++ Generic Programmi

ng

TemplateMetaprogramm

ing

Procedural Programming

Object-Oriented

Programming

Functional Programming

Page 6: C++프로그래밍 및 실무_06.17.pptx

6

C++: Procedural Programming• 프로그램의 상태를 직접적으로 변화시키는 명령들로의

구성• 처리해야 할 작업을 순차적으로 나열 – 전통적인 방식

• 특성Direct assignments, Common data structures, Global variables,Local variables, Iteration, Modularization

Page 7: C++프로그래밍 및 실무_06.17.pptx

7

C++: Object-Oriented Programming

• 객체 (Object) = 데이터 ( 특성 ; Attributes) + 코드 ( 행동 양식 ; Behavior)

• 프로그램의 상태를 ‘객체’의 미리 정의된 Behavior 를 통해서만 조작함

• GUI 로 인해 엄청나게 증가한 소프트웨어의 복잡성을 다루기 위해 ‘모듈화’ 또는 ‘재사용성’ 강조

• 특성Objects, Classes, Methods, Message Passing, Information Hiding, Data Abstraction, Encapsulation, Polymorphism, Inheritance, Serialization

Page 8: C++프로그래밍 및 실무_06.17.pptx

8

C++: Functional Programming• 프로그램 내부에 상태 (state) 가 형성되는 것을 피하기

위해 프로그램을 수학적 함수의 결합으로 나타낸다 .• 병렬 처리 / 분산 환경 : 필수적으로 다가온 동시성

다루기 – ‘부작용’이 없어야 함

• 특성Lambda calculus (C++11)Higher order functionsClosuresRecursionNo side effects

Function pointer

Function object

Lambda function

C

C++

C++11

Functional Programming 의 지원

Page 9: C++프로그래밍 및 실무_06.17.pptx

9

C++: Generic Programming• Type 에 관계없이 일반화된 코드를

작성하고 싶은 마음• 가능한 원소 type 마다 고유한 List

Type 을 일일이 만드는 것은 비효율적

Page 10: C++프로그래밍 및 실무_06.17.pptx

10

C++: Template Metaprogramming• 템플릿을 사용하여 컴파일러가 프로그램 코드를 생성• 런타임 시점이 아닌 컴파일 시점에 실행

• 보통은 더 ‘안전’하거나 ‘효율적’인 Generic Programming 을 위해 사용

• traits type 에 따라 다른 처리• 사실 ‘계산’ 목적으로는 잘 쓰지 않음 – 사용자 입력을 못

받음

Page 11: C++프로그래밍 및 실무_06.17.pptx

11

C++: Template Metaprogramming

• C++ 의 template 기능은 또 다른 한 언어로 봐도 무방…

Page 12: C++프로그래밍 및 실무_06.17.pptx

Heap 영역 vs Stack 영역

12

Heap 영역

• 동적으로 메모리 공간을 할당 ( 특정 메모리 공간을 예약 )

• 생명 주기는 프로그래머가 알아서 관리

Stack 영역

• 지역변수 / 매개변수• 함수 호출에 필요한 정보 : Call frame(Return

Address, …)• 생명 주기는 Scope { } 에 의해 결정됨낮은 메모리 주소

높은 메모리 주소

운영체제가 프로세스 (Process) 에 ‘가상메모리’ 영역을 제공각 프로세스는 ‘독립적’ 주소 체계를 가질 수 있음

미사용

Stack영역

Heap 영역

Page 13: C++프로그래밍 및 실무_06.17.pptx

13

지역변수의 생명 주기

function foo 의 scope 시작

Nested scope 의 시작 : Local3, Local4 의 공간 할당

Nested scope 의 끝 Local3, Local4 해제

Local1, Local2, 그리고 arg1, arg2 해제

// for 문에서의 scope 시작

// for 문의 scope 의 끝

• 컴파일러는 scope 안에서 사용될 지역변수의 크기를 알고 있음• ‘ 할당’ / ‘ 해제’라고 표현을 했지만 , Stack Pointer 위치만 바꿔줄 뿐 !• int array[N]; 과 같은 문법이 불가능한 이유임 ( 컴파일러가 크기를

파악할 수 없어 stack 공간에 할당할 수 없음 )

• Scope { } 에 의해 정해짐 . Scope 가 시작될 때 ‘할당’ , 끝날 때 ‘해제’

Page 14: C++프로그래밍 및 실무_06.17.pptx

14

Memory Management in C++• new, delete 연산자의 도입

C 에서의 heap memory 할당 / 해제

C++ 에서는 new, delete 연산자 사용

Page 15: C++프로그래밍 및 실무_06.17.pptx

15

Memory Management in C++• delete vs delete[]

– new / delete– new [] / delete[] 짝을 반드시 맞춰야 함– 메모리 layout 이 다르기 때문 !

header

힙 공간에 대한 정보

주의 ! 마찬가지로 malloc 으로 생성한 것을 delete, new 로 생성한 것을 free 로 해제해서는 안된다 .

Page 16: C++프로그래밍 및 실무_06.17.pptx

16

Memory Management in C++• 언어 차원에서 지원하는 메모리 할당 / 해제

연산자이므로 별도의 include 가 필요없다 .• New/delete 는 객체가 생성 , 소멸할 때 생성자

(constructor; ctor) 와 소멸자 (destructor; dtor) 를 각각 호출한다 .

• 연산자 오버로딩 기능을 사용하면 new 와 delete 를 재정의할 수도 있음– malloc 이나 free 를 재정의하는 것은 사실상 불가능함– Memory Leak 을 추적하기 위해 new 가 불릴 때마다 기록을

하거나– 성능 향상을 위해 프로그래머가 효율적인 메모리 할당 / 해제

알고리즘을 적용할 수도 있음 (Memory Allocator 구현 )

Page 17: C++프로그래밍 및 실무_06.17.pptx

17

Pass-by-value• 함수의 매개변수가 전달될 때 기본적으로 항상 ‘복사’하여

전달한다 . 같은 ‘값’을 전달한다는 의미에서 pass-by-value 라고 함

• 두 변수의 값을 서로 바꾸는 swap 함수 구현

• 그러나 매개변수로 들어온 a, b 는 원래 변수와는 같은 값만을 가질 뿐 사실상 전혀 관계 없는 다른 변수

void swap_fail(int a, int b){

int t = b;b = a;a = t;

}

Page 18: C++프로그래밍 및 실무_06.17.pptx

18

Pass-by-pointer• Pass-by-pointer 는 메모리 주소를 직접 전달한다 .

• 그 결과 함수 안에서 원래 변수의 값을 조작할 수 있게 됨• Swap 함수의 매개변수 a 와 b 은 m 과 n 의 주소를

원하므로 변수의 주소를 알아내는 & 을 변수 앞에 붙여야 함

• 덩치가 큰 변수의 전달 시 ‘복사’에 따른 오버헤드를 없애기 위해

Page 19: C++프로그래밍 및 실무_06.17.pptx

19

Pass-by-reference• Reference 변수를 사용하면 이 과정을 컴파일러가

알아서 해줌

• a 와 b 의 ‘값’을 전달하는 것이 아니라 a 의 주소와 b 의 주소를 전달한다 . 함수 안에서는 일반 변수 다루듯이 사용할 수 있음

• Reference 를 사용하기 위해 반드시 원래 변수가 있어야 함

// 오류 ! 포인터와 달리 Reference 변수는 반드시 한 변수로 초기화되어야 한다 .

Page 20: C++프로그래밍 및 실무_06.17.pptx

20

Pointer vs Reference 비교

• Pass-by-pointer 와 내부적인 동작 차이는 없음• 다만 pass-by-pointe 에서는 0, 즉 null pointer 가

들어갈 수도 있음 . 그러나 pass-by-reference 에서는 허용되지 않음

// 사실 억지로 전달할 수 있긴 함…

// Null pointer 전달 가능

error C2664: 'swap2' : cannot convert parameter 1 from 'int' to 'int &'// 허용되지 않음 ( ‘ 상수’의 주소를 알아올 수 없기 때문 )

Page 21: C++프로그래밍 및 실무_06.17.pptx

21

Const Reference• 배열의 전체 합을 구하는 함수

• 만약 pass-by-value 로 전달한다면 ? • arr 전체가 또 한번 복사 비효율

• Const Modifier 를 쓰지 않았다면 ? • get_sum 함수 내에서 arr 를 건드릴 수 있음 의도치 않은 결과 초래

가능성

Page 22: C++프로그래밍 및 실무_06.17.pptx

22

Const Modifier// compiler error = expression must be a modifiable value

char* str1 = "hello1";str1[0] = 'y'; // access violationstr1 = "world1";

const char* str2 = "hello2";str2[0] = 'y'; // compile errorstr2 = "world2";

char* const str3 = "hello3";str3[0] = 'y';str3 = "world3"; // compile error

const char* const str4 = "hello4";str4[0] = 'y'; // compile errorstr4 = "world4"; // compile error

Page 23: C++프로그래밍 및 실무_06.17.pptx

23

OOP Keywords• Encapsulation• Information Hiding• Inheritance• Polymorphism

Page 24: C++프로그래밍 및 실무_06.17.pptx

24

Encapsulation• 객체의 속성 (Data fields) 와 행위 (Methods) 를 하나로 묶음

• 프로그램이란 ?– 결국 데이터를 특정한 방식에 의해 처리하는 것을 의미– 객체에는 데이터와 행동 양식이 묶여 있음– 즉 , 하나의 부품으로 활용될 수 있음

그림 출처 http://java-answers.blogspot.kr/2012/01/oops-and-its-concepts-or-properties-in_06.html

Page 25: C++프로그래밍 및 실무_06.17.pptx

25

Information Hiding• 지나친 데이터 노출은 혼란을 가중시킬 수 있음

– (ex) Brand, Speed, Gear, Color 이 노출되었다면 ?• 외부와 상호작용하기 위한 인터페이스 부분만 남기고

나머지는 내부에서 처리– (ex) 가속 , 기어 변속 , 브레이크

• 정의된 객체는 ‘잘 동작한다’는 가정하에 실제로 사용을 어떻게 하면 되는가가 관심사 . 객체 내부의 세부적인 동작이 어떻게 되는지는 알고 싶지 않음

• 또 외부에서 함부로 객체의 상태를 바꿀 수 없도록 안전 장치를 만들어놓은 것으로 볼 수도 있음

Page 26: C++프로그래밍 및 실무_06.17.pptx

26

상속 (Inheritance)

계좌소유자계좌번호잔액

입금하기출금하기

Savings Account

이자율이자 지급하기

Checking Account

수수료수수료 뺏어가기

• Savings Account 와 Checking Account 는 모두 공통적으로 ‘계좌’의 속성과 행동 양식을 가진다 .

• 새로 구현할 것이 아니라 ‘계좌’의 속성 및 행동 양식을 그대로 물려받는다 .

• Child class(subclass; derived class)

Parent class(super class; base class)

Page 27: C++프로그래밍 및 실무_06.17.pptx

27

PolymorphismShapedraw()

getSize()

Rectangledraw()

getSize()

Circledraw()

getSize()

Triangledraw()

getSize()

• Polymorphism ( 다형성 ) 은 다른 type 에 대해 같은 interface 를 제공한다 .• 위의 예는 Sub Typing 이라고도 부름 . Rectangle, Circle, Triangle 은

Shape 의 draw 와 getSize 라는 인터페이스를 상속받지만 각자 하는 일이 다르다 .• 다형성의 장점은 객체를 한꺼번에 다룰 수 있다는 점 . Shape 로 통일되어 있지 않을 때 모든 Rectangle, Circle, Triangle 의 넓이의 합을 구하려면 ?

• Function Overloading 도 넓게는 Polymorphism 의 개념에 포함됨

Page 28: C++프로그래밍 및 실무_06.17.pptx

28

Class• C 의 struct

– 관련 있는 데이터들을 하나의 type 으로 묶기 위한 시도– (ex) 계좌 레코드 { 소유자 , 계좌번호 , 잔액 }

• C++ 의 class– C 의 struct 개념을 확장하여 function까지도 가질 수 있는

type– (ex)C 에서 입금하기를 구현한다면 계좌 레코드를 접근하는

함수가 필요하다 . 아예 class 가 function 을 포함한다면 ?

Page 29: C++프로그래밍 및 실무_06.17.pptx

29

Class• Member variable (or member data)

– 클래스 내의 변수

• Member function (method)– 클래스 내의 함수 : 객체가 무슨 일을 하는지 정의할 수 있다 !

• Instance– 클래스 자체는 type 일 뿐– 클래스에 의해 만들어진 변수 ( 메모리에 실재 )

“ 내가 그의 이름 (type)을 불러 주었을 때그는 나에게로 와서꽃 (instance)이 되었다"

Page 30: C++프로그래밍 및 실무_06.17.pptx

30

Class 선언하기

class ClassName : public BaseClassName{public:

SomeType publicMemberVar;void foo(){

/* some defines */}void foo2(); /* elsewhere */

protected:SomeType protectedMemberVar;

private:SomeType privateMemberVar;

};

나중에 다른 곳에서 정의해줘야 함

상속이 필요한 경우에만

• 앞으로 ClassName 이라는 type 을 추가한다는 의미임 !• 실제로 클래스를 사용하기 위해선 인스턴스 (instance) 를 생성해야함

Member Variable

Member Function

Page 31: C++프로그래밍 및 실무_06.17.pptx

31

Class 에서 선언한 멤버 함수는 ?• 클래스 자체에서 멤버함수를 정의하는 경우

– Inline 함수 등을 염두에 두고 매우 짧은 함수 ( 단순히 멤버 변수 값을 리턴해주는 함수 )

• 클래스 정의는 header 파일 (*.h), 클래스 내의 함수 정의는 source 파일 (*.cpp) 에 넣는다 .

void ClassName::foo2(){/* defines */

}

Page 32: C++프로그래밍 및 실무_06.17.pptx

32

Access modifiers• 클래스 내의 멤버 변수나 멤버 함수를 외부에서 접근할 수 있는지

여부를 지정– Public

• C 에서의 struct 처럼 외부에서 ( 클래스 밖에서 ) 마음대로 접근할 수 있음– Private

• 클래스 안의 메소드 (멤버 함수 ) 에서만 접근 가능– Protected

• 외부에서 보기에는 private 로 접근이 불가능하지만 , 상속 관계하에서는 public으로 접근이 가능함

• Access Modifier 를 따로 지정하지 않으면 – Class 는 자동으로 private– Struct 는 자동으로 public 으로 간주– C++ 에서 struct 와 class 의 차이는 default access modifier 의 차이 뿐

Page 33: C++프로그래밍 및 실무_06.17.pptx

33

this 키워드

class ClassName{public:

void PrintAddress(){std::cout << "this = " << this << std::endl;

}};

• 클래스의 멤버 함수에서 자기 자신을 참조하고 싶을 때• this 의 type 은 해당 클래스의 포인터 타입이라고 볼 수 있음

ClassName name;std::cout << "Address of name = " << &name << std::endl; // Address of name = 0038FD6Fname.PrintAddress(); // this = 0038FD6F

• 인스턴스가 다르면 당연히 다른 값이어야 함• 멤버 변수의 이름과 지역 변수의 이름이 겹칠 때 모호성을 해소하기 위해 사용할 수도 있음

Page 34: C++프로그래밍 및 실무_06.17.pptx

34

Static Member Variable• 클래스는 type 을 의미하고 각 member variable 은

독립적임• 그러나 Static 키워드를 추가하면 클래스 type 에 대해

유일한 변수를 할당할 수 있음class CountableClass {public:

CountableClass() { std::cout << " 인스턴스 생성 " << this << std::endl; count++; }~CountableClass() { std::cout << " 인스턴스 소멸 " << this << std::endl; count--; }int getCount() const { return count; }

private:static int count;

};

int CountableClass::count = 0;

int _tmain(int argc, _TCHAR* argv[]){

CountableClass instanceA;{

CountableClass instanceB;std::cout << instanceB.getCount() << std::endl;

}std::cout << instanceA.getCount() << std::endl;return 0;

}

Page 35: C++프로그래밍 및 실무_06.17.pptx

35

Const Member Variableclass CountableClass {public:

CountableClass() : typeCode(456) { /* 생성자 */ }private:

static const int staticTypeCode = 123;const int typeCode;

};

• 멤버 변수의 성격이 상수일 때 const 키워드를 붙인다 .

• Static 키워드를 붙이면 바로 초기화 가능 (type 이 int 일 때만 )

• 일반 const member variable 은 생성자의 초기화 리스트에서 초기화

Page 36: C++프로그래밍 및 실무_06.17.pptx

36

Mutable Member Variable• Const 한정자가 붙은 함수는 member variable 의 값을 수정할 수 없다 !

class CountableClass {public:/* 생략 */int getCount() const {

callCount++;return count;

}private:

static int count;int callCount;

};

컴파일 에러 : Expression must be modifiable L-Value

• 그렇다고 getCount() 에 const 를 뺄 수도 없음• Member variable 앞에 mutable 넣으면 해결 !

mutable int callCount;

Page 37: C++프로그래밍 및 실무_06.17.pptx

37

생성자 (Constructor)class Contact{public:

Contact() : name("undefined"), age(0) {}

Contact(const std::string& name_, int age_): name( name_ ), age( age_ ) {}

private:std::string name;int age;

};• 클래스와 같은 이름을 가지는 함수 ( 리턴 type 은 없음 - void 가 아님 )• 객체가 생성될 때 자동으로 호출된다

• new 연산자에 의해 생성되거나 (malloc 은 안됨 )• Local variable 로 할당되는 순간

• 외부에서 접근 가능해야 하므로 반드시 public• 매개변수가 없는 Contact() 가 기본 생성자 (default constructor)

초기화 리스트

매개변수를 가질 수 있음

Page 38: C++프로그래밍 및 실무_06.17.pptx

38

멤버 초기화 리스트 (Member Initialization List)

• 초기화 리스트의 순서는 아무 상관 없다 .class Type1 { public: Type1(int a){ std::cout << "Type 1 초기화 " << std::endl; } };class Type2 { public: Type2(int b){ std::cout << "Type 2 초기화 " << std::endl; } };class Type3 { public: Type3(int c){ std::cout << "Type 3 초기화 " << std::endl; } };

class MemberInitializationTest {public:

MemberInitializationTest(): type1(0), type2(0), type3(0)

{}

private:Type2 type2;Type3 type3;Type1 type1;

} test;• 실행 결과는 ?• Class 안에서 정의된 순서에 의해 초기화가 진행됨

Page 39: C++프로그래밍 및 실무_06.17.pptx

39

레퍼런스 멤버의 초기화

class Manager { /* some definitions */ };

class TestObject {public:private:

Manager& manager;} testObject;

멤버 변수로 reference 변수 가능함단 , 초기화 리스트에서 초기화하지 않으면컴파일 에러 (no appropriate default constructor available)

class TestObject {public:

TestObject(Manager& manager_) : manager(manager_) {}private:

Manager& manager;} testObject(Manager());

실제로는 올바른 객체를 넣어야겠죠 ?

Page 40: C++프로그래밍 및 실무_06.17.pptx

40

소멸자 (Destructor)• 객체가 소멸될 때 자동으로 불리는 함수

– Delete 연산자에 의해– scope 가 끝나 local variable 의 생명 주기가 끝났을 때

• 클래스 이름 앞에 ~ 가 붙는다• 역시 리턴 타입 없음• 매개변수는 없다 ( 사용자가 부르는 함수가 아님 )• Access modifier 는 public 이어야 함

class Base {public:/* … */

~Base(){std::cout << "Base 소멸 " << std::endl;

}};

Page 41: C++프로그래밍 및 실무_06.17.pptx

41

상속된 클래스에서의 생성자 / 소멸자

class Base {public:

Base(){std::cout << "Base 생성 " << std::endl;

}

~Base(){std::cout << "Base 소멸 " << std::endl;

}};

class Derived : public Base {public:

Derived(){

std::cout << "Derived 생성 " << std::endl;}

~Derived(){std::cout << "Derived 소멸 " << std::endl;

}};

실행 결과

int _tmain(int argc, _TCHAR* argv[]){

Derived instance;return 0;

}

Page 42: C++프로그래밍 및 실무_06.17.pptx

42

복사 생성자 (Copy Constructor)• 필요성 – Implicit Copy 의 문제점

class MyString{public:

void allocate(){pointer = new char[16]; // initial buffer

}

/* for debug */void setPointer(char* pointer_) { pointer = pointer_; }char* getPointer() const { return pointer; }

private:char* pointer;

};

Page 43: C++프로그래밍 및 실무_06.17.pptx

43

복사 생성자 (Copy Constructor) [2]• 내부의 포인터 주소 자체가 복사됨MyString str1;MyString str2;

str1.allocate();str2 = str1; // Implicit Copy

std::cout << "str1.getPointer() = " << (int)str1.getPointer() << std::endl;

std::cout << "str2.getPointer() = " << (int)str2.getPointer() << std::endl;

H E L L O W O R L D \0

str1

str2

• pointer

• pointer

* str1 그리고 str2 가 같은 주소를 가리키므로 str1 을 수정하면 str2 에도 반영됨

Page 44: C++프로그래밍 및 실무_06.17.pptx

44

복사 생성자 (Copy Constructor) [3]class MyString{public:

MyString() : pointer(nullptr) {}MyString(const MyString& copy_from_me){

this->allocate(); // 적당한 공간 할당 후// copy_from_me 에서부터 문자열 복사하기

}

… 생략 …

MyString str1;str1.allocate();MyString str2(str1);

Page 45: C++프로그래밍 및 실무_06.17.pptx

45

복사 대입 연산자 =

MyString& operator=(const MyString& copy_from_me){this->allocate(); // 적당한 공간 할당 후// copy_from_me 에서부터 문자열 복사하기return *this; // 자기 자신을 리턴함

}

( 생각해봐야 할 점 )self-assignment (ex) str1 = str1;

Page 46: C++프로그래밍 및 실무_06.17.pptx

46

Getter and Setter– 노가다 ?연락처 Class

• 이름

• 전화번호

• 이메일

string getName() const

void setName(const string& name)

string getPhone() const

void setPhone(const string& phone)

Member Variables

string getEmail() const

void setEmail(const string& email)

• 그러나 멤버 변수가 외부로 노출되어 있을 시 ,• 값이 한번 바뀌면 언제 바뀌었는지 추적하기가 너무 어렵다 .

• Getter/ Setter 만들면 , 언제 어디서 값이 바뀌는지 추적이 용이

Page 47: C++프로그래밍 및 실무_06.17.pptx

47

상속 범위  public protected private 

클래스내 O  O  O 

 friend 함수 내 O  O  O 

자식 클래스 내 O  O  X 

클래스 외부(main 등 )

O  X  X 

• 상속 받을 때 보통 부모 클래스의 메소드를 접근하게 되므로 public 상속을 주로 사용한다 .• Is-a 관계 : A savings account is an account.

• Private 상속• Is-implemented-in-terms-of• ‘ 구현’을 편하게 할 목적으로 부모 클래스를 상속받는 경우엔 부모 클래스의 메소드가 외부로 노출되어선 안되므로

• 경험상 , Private 상속 보다는 멤버 변수로 부모 클래스를 들고 있는 편이 나았음

Page 48: C++프로그래밍 및 실무_06.17.pptx

48

상속 시 이름이 겹칠 때

class ConflictBase {public:int X;};

class ConflictDerived : public ConflictBase {public:int X;void PrintX(){

std::cout << X << std::endl;}void PrintBaseX(){

std::cout << ConflictBase::X << std::endl;}}; 같은 이름이 있으면 자기 자신의 멤버 변수가 우선하지만 부모 클래스의 X 가 필요한 경우는 위처럼 범위를 지정해줄 수 있다 .

Page 49: C++프로그래밍 및 실무_06.17.pptx

49

상속 시 이름이 겹칠 때 (2)ConflictDerived d;d.X = 1;d.PrintX();d.PrintBaseX();

ConflictBase& base(d);base.X = 2;d.PrintX();d.PrintBaseX();

출력 결과 >1-858993460 ( 쓰레기값 )12

• 자식 클래스를 부모 클래스로 캐스팅해서 쓸 수도 있다 .• 반대로는 하면 안됨 ( 자식 클래스의 크기 >= 부모 클래스의 크기 )

Page 50: C++프로그래밍 및 실무_06.17.pptx

50

가상함수 (Virtual Function)• A function or method whose behavior can be

overridden with an inheriting class by a function with the same signature

• 부모 클래스와 자식 클래스가 같은 형태의 함수 ( 리턴값 , 매개변수 목록 , 함수 이름 ) 을 갖고 있을 때 , 자식 클래스의 함수가 실행된다 .

Page 51: C++프로그래밍 및 실무_06.17.pptx

51

가상함수 (Virtual Function) [2]class Shape {public:

double getSize(){return 0.0f;

}};

class Rectangle : public Shape {public:

Rectangle(double width, double height) : width(width), height(height) {}

double getSize(){ return width * height; }private:

double width;double height;

};

class Circle : public Shape {public:

Circle(double radius) : radius(radius) {}double getSize(){ return 3.141592 * radius *

radius; }private:

double radius;};

Rectangle rectangle(10,20);std::cout << "Rectangle 1 = " << rectangle.getSize() << std::endl;

Shape& shape(rectangle);std::cout << "Shape (Rectangle 1) = " << shape.getSize() << std::endl;

• Rectangle 을 Shape 로도 다루고 싶은데 ...

• 원래 의도는 Rectangle::getSize() 를 호출하는 것이었지만 , Shape::getSize() 가

• Shape *ptr = &rectangle; ptr->getSize(); 도 마찬가지• 게다가 ptr 에는 circle 이 대입될 수도 있고 현 상황에서는 실행 중에 타입을 알 수 있는 방법이 전혀 없기 때문이다 .

Page 52: C++프로그래밍 및 실무_06.17.pptx

52

가상함수 (Virtual Function) [3]• 함수 앞에 virtual 키워드를 붙인다 .

• virtual 이 있을 때와 없을 때 무엇이 다른 걸까 ?

class Shape {public:

virtual double getSize(){return 0.0f;

}};

멤버 변수 외에 __vfptr 이라는 값이 들어있다 . 이는 virtual table 의 주소를 가리키는 값으로 4byte 의 추가 공간을 필요로 한다 . __vfptr 을 따라가보면 Rectangle::getSize() 이 지정되어 있다 .

Page 53: C++프로그래밍 및 실무_06.17.pptx

53

Virtual Table 이란 ?

그림 출처 http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/

• type 별로 무슨 함수가 실행되어야 할지 각 함수의 주소를 표로 나타낸 것• 객체의 메소드를 실행할 때 static 한

type 에 의존하지 않고 객체에 type 정보를 추가로 둔다 .

• D1 에서 function1 을 부를 때• 바로 부르는 것이 아니라

__vptr 를 통해 function1() 의 시작 주소를 얻는다• Function2 를 부를 때

• Function2 는 정의가 되어 있지 않아 virtual table 에 base 의 function2 주소로 따라가도록 되어있다 .

오버헤드 : __vptr 크기 (pointer 크기 )vtable 에서 함수 주소 읽어오기

Page 54: C++프로그래밍 및 실무_06.17.pptx

54

Polymorphism 의 응용

• Abstract Class (혹은 Interface Class)class Shape {public:

Shape() {}virtual double getSize() = 0;virtual void draw() = 0;

};

class Rectangle : public Shape {public:

Rectangle(double width, double height) : width(width), height(height) {}

double getSize(){ return width * height; }void draw() { std::cout << "The rectangle

is drawed : " << width << "x" << height << std::endl; }private:

double width;double height;

};

class Circle : public Shape {public:

Circle(double radius) : radius(radius) {}double getSize(){ return 3.141592 * radius

* radius; }void draw() { std::cout << "The circle is

drawed : " << radius << std::endl; }private:

double radius;};

for ( int i = 0; i < _countof(shapes); ++i ) {

std::cout << shapes[i]->getSize

<< std::endl;shapes[i]->draw();

}

Page 55: C++프로그래밍 및 실무_06.17.pptx

55

소멸자와 virtual• Shape 와 Rectangle, Circle 에 모두 소멸자 함수를

정의했을 때

• Rectangle, Circle 소멸자 코드는 실행되지 않음• 소멸자가 virtual 이 아니므로 virtual table 에 없음

for ( int i = 0; i < _countof(shapes); ++i ) {delete shapes[i];

}

virtual ~Shape() {std::cout << "Shape 파괴 " << (int)this << std::endl;

}• Shape 의 소멸자가 실행되기 전 Rectangle 소멸자 ,

Circle 소멸자도 실행됨을 알 수 있다 .• 이와 같이 virtual 을 쓰지 않으면 자식 클래스의 소멸자가 실행되지 않으므로 상속을 고려한다면 항상 소멸자에는 virtual 을 넣도록 한다 .

Page 56: C++프로그래밍 및 실무_06.17.pptx

56

C++ Template• C++ 의 강력한 기능 중 하나 – 그러나 난해하기도 한

부분• Generic Programming• Template Metaprogramming• 코드를 컴파일러가 ‘자동’으로 생성해준다 .

• 종류– 함수 템플릿– 클래스 템플릿

Page 57: C++프로그래밍 및 실무_06.17.pptx

57

Function Template• Function Overloading 만으론 한계가 있다 .• Swap 함수의 구현을 생각해볼 때 ,

– Type 별로 Swap 함수를 일일이 구현한다는 것은 불가능함– 그렇다고 Type 에 따라 구현하는 방식이 달라지지도 않음

• 일반화된 표현 방식의 필요성– 특정 Type 에 대한 대입 연산자만 잘 정의되어 있다면 no

problem

Page 58: C++프로그래밍 및 실무_06.17.pptx

58

Function Template [2]template< typename value_type >void Swap( value_type& t1, value_type& t2 ){

value_type t = t1;t1 = t2;t2 = t;

}

• value_type 에 = 연산만 잘 정의되어 있으면 어떤 type 에 대해서도 swap 가능

• 컴파일러의 타입 추론 -- Swap<Rectangle>(rec1, rec2); 으로 불러도 되나 Swap(rec1, rec2); 도 문제 없음

• 사용된 모든 종류의 value_type 에 대한 코드를 컴파일러에서 생성해준다 . (Implicit Instantiation)

Rectangle rec1(10,20);Rectangle rec2(30,40);rec1.draw();rec2.draw();

Swap(rec1, rec2);

rec1.draw();rec2.draw();

Page 59: C++프로그래밍 및 실무_06.17.pptx

59

Function Template [3]

template< typename To, typename From >To my_cast( const From& from ){

std::cout << typeid(From).name() << " to " << typeid(To).name() << std::endl;

return static_cast<To>(from);}

char a = 'a';int a_casted = my_cast<int>(a); 컴파일러가 typename From 은 알아서 추론해줌

* 캐스팅 함수의 정의

Page 60: C++프로그래밍 및 실무_06.17.pptx

60

Function Template [4]• 템플릿 특수화 (Template Specialization)

– 어떤 type 에 대해서는 특별하게 처리하고 싶은 경우가 있을 때template<> long my_cast( const char& from ){

std::cout << "[long] 재정의된 캐스팅 " << std::endl;return static_cast<long>(from);

}

* char -> long 은 다르게 처리하고 싶을 때 (…)

char a = 'a';int a_casted = my_cast<int>(a);long b_casted = my_cast<long>(a);

Page 61: C++프로그래밍 및 실무_06.17.pptx

61

Function Template [5]

test t;t.Test( 1 );t.Test<char>( (char) 1 );t.Test( (char) 1 );

1. 일반 함수가 가장 우선2. 템플릿 특수화에 의한 함수는 그 다음3. 마지막으로 템플릿 함수

* 템플릿 특수화의 우선 순위

Page 62: C++프로그래밍 및 실무_06.17.pptx

62

Class Template• Function Template 와 마찬가지로 클래스에서도

template 을 제공template<typename T>class MyStack{public:

void Push(const T& item);T Pop() { return T(); }

private:T* data;

};

template<typename T> void MyStack<T>::Push(const T& item){std::cout << "push " << item << std::endl;

}

보통 template 코드는 클래스 선언 내에 정의되는 경우가 많다 .

* 클래스 템플릿 선언과 별도로 정의할 수도 있다 .

MyStack<int> intStack;MyStack<double> doubleStack;MyStack<Shape*> shapePointerStack;

intStack.Push(123);doubleStack.Push(456.0);shapePointerStack.Push(nullptr);

Page 63: C++프로그래밍 및 실무_06.17.pptx

63

Template 관련 에러 메시지

• 에러 메시지 읽기void Push(const T& item) {

static_assert( sizeof(T) == 4, "The size of T should be 4 bytes." ); }

// T 의 크기가 4 바이트가 아니면 컴파일 에러가 발생하도록 하였음 (C++11)

1>h:\home\noel\documents\personal\dev\work\temp\tutorial1\tutorial1.cpp(149): error C2338: The size of T should be 4 bytes.1> h:\home\noel\documents\personal\dev\work\temp\tutorial1\tutorial1.cpp(149) : while compiling class template member function 'void MyStack<T>::Push(const T &)'1> with1> [1> T=double1> ]1> h:\home\noel\documents\personal\dev\work\temp\tutorial1\tutorial1.cpp(162) : see reference to function template instantiation 'void MyStack<T>::Push(const T &)' being compiled1> with1> [1> T=double1> ]1> h:\home\noel\documents\personal\dev\work\temp\tutorial1\tutorial1.cpp(158) : see reference to class template instantiation 'MyStack<T>' being compiled1> with1> [1> T=double1> ]

Page 64: C++프로그래밍 및 실무_06.17.pptx

64

STL(Standard Template Library)• 표준 템플릿 라이브러리에는 중요한 자료 구조와

알고리즘들이 미리 구현되어 있음• 검증된 라이브러리 - 개발 기간을 단축할 수 있음• 각 자료 구조들의 특성을 잘 이해해야 함

• 중요 개념– 컨테이너 (Container) : 순차 컨테이너 , 연관 컨테이너– 반복자 (Iterator) : 컨테이너의 원소들을 탐색하기 위함 – 알고리즘 (Algorithms) : 기본적인 알고리즘들이 정의되어 있음

(Generic 한 라이브러리의 특징상 성능을 극한으로 끌어올리진 않았음 )

Page 65: C++프로그래밍 및 실무_06.17.pptx

65

STL 컨테이너 (Container)• Sequence Container

• Vector 동적 배열• List 순서가 있는 리스트• Deque 양 끝에서 입력과 출력 가능• String 문자열

• Associative Container• Map 사전과 같은 구조 <key, value>• Multi Map 중복 key 를 허용• Set 집합 <key>• Multi Set 중복 key 를 허용

• Adaptor Container• Stack• Queue• Priority Queue

Page 66: C++프로그래밍 및 실무_06.17.pptx

66

std::string• ‘ 문자열’을 처리하기 위한 클래스로 C 의char* 을 직접 다루는 것에 비해 매우 편리

#include <string>

string message = "hello world";string message2( "c++" );string message3( 10, '=' );string message4 = message;

cout << message << endl;cout << message2 << endl;cout << message3 << endl;cout << message4 << endl;

* C 의 null-terminated string 과 다른 점 C 에서는 문자열의 끝을 나타내기 위해 마지막에 ‘ \0’ 을 통해 나타냈으나 std::string 에서는 size 를 담고 있는 변수가 있으므로 ‘ \0’ 과 같은 null 문자가 필요 없다 .

Page 67: C++프로그래밍 및 실무_06.17.pptx

67

std::string [2]cout << message.size() << endl; // 11

string name;cin >> name;

string msg = "Hello world, " + name + "!";cout << msg << endl;

문자열 길이 (strlen)

string::operator+(const string&) 에 의한 문자열 결합 (strcat)

첨자 접근msg[0] = 'y';

문자열간 비교(name == "quit")

그 외에도 문자열 검색을 위한 find 멤버 함수 , 부분 문자열 추출을 위한 substr 등…C 의 문자열 함수와 씨름하던 것에 비하면…

Page 68: C++프로그래밍 및 실무_06.17.pptx

68

std::string [3]• typedef basic_string<char, char_traits<char>,

allocator<char> > string;• typedef basic_string<wchar_t,

char_traits<wchar_t>, allocator<wchar_t> > wstring;

• 1byte 단위의 string 과 2byte 단위의 wstring 이 있음• 두 string 이 완전히 다른 것이 아니라 글자 하나에 대한 type 이 char 인지

wchar_t 인지에 대한 차이밖에 없음• traits 라는 개념을 통해 문자열 비교 , 길이 구하기 , 검색 등의 기능을 재정의 할 수 있음

• 예를 들어 string 과 같이 char 기반의 문자열이지만 대소문자를 구별하지 않는 문자열 istring 등을 traits 재정의를 통해 만들어낼 수 있음 Generic Programming 의 매력

Page 69: C++프로그래밍 및 실무_06.17.pptx

69

std::vector<T>• ‘ 동적 배열’

– 저장할 데이터 개수가 가변적일 때– 중간에 데이터 삽입 / 삭제가 없을 때 ( 한 칸씩 당기거나 밀기

때문에 속도 저하 )– 빈번하게 데이터를 검색하지 않을 경우– 데이터 접근을 랜덤하게 하고 싶을 때 (첨자를 통한 접근 )

#include <vector>

sizeof(T)

[0] [1] [2] [3] [4] [5]

vector<int> scores(5);for (int i = 0; i < scores.size(); ++i)

cin >> scores[i];

Page 70: C++프로그래밍 및 실무_06.17.pptx

70

std::vector<T> [2]

vector<string> animals;animals.push_back("dog");animals.push_back("cat");

for (int i = 0; i < animals.size(); ++i)cout << animals[i] << endl;

Ex) 문자열 (std::string) 벡터

Member functions 기능push_back(val) 컨테이너의 마지막에 원소를 추가한다 . 미리 만들어둔

버퍼가 가득차면 추가로 확장한다 .pop_back 마지막에 원소 삭제insert 특정 위치에 원소 삽입erase 특정 위치의 원소 삭제 또는 지정 범위 원소 삭제clear 초기화 ( 모든 원소 삭제 )back 제일 마지막 원소 반환

Page 71: C++프로그래밍 및 실무_06.17.pptx

71

std::deque<T>• 벡터에서 push_back(val), pop_back() 에앞에서도 추가 /삭제 : push_front(val), pop_front()

• queue<T>, stack<T> 는 내부적으로 deque<T> 를 사용하도록 되어있음

#include <deque>

Page 72: C++프로그래밍 및 실무_06.17.pptx

72

std::map<key_type, T>• ‘ 사전’ 형식의 자료 구조• data[“key”] : 검색 뿐만 아니라 value_type 의

초기값이 들어가므로 단순 검색에는 find 함수를 이용해야 함

string tmp;map< string, int > count;while (true){

cin >> tmp;if (tmp == "q") break;count[tmp]++;

}

for (map<string, int>::const_iterator itr = count.begin(); itr != count.end(); ++itr){

cout << itr->first << " : " << itr->second << endl;}

a friend in need is a friend indeeda : 2friend : 2in : 1indeed : 1is : 1need : 1

cout << count[“smith”] << endl; 없는 단어이므로 0 이 나오겠지만 <“smith”, 0> 이라는 항목으로 tree 에 추가가 된다 .

Page 73: C++프로그래밍 및 실무_06.17.pptx

73

std::map<key_type, T>• 내부 구현은 Red Black Tree. 임의의 키에 대해서

O(log N) 의 접근• Find 함수로 검색

map< string, int > score;score["dog"] = 96;score["cat"] = 90;

string name;cin >> name;

map< string, int >::const_iterator itr = score.find(name);if (itr != score.end()) {

cout << itr->second;}else{

cout << "not found" << endl;}

Page 74: C++프로그래밍 및 실무_06.17.pptx

74

Container 의 올바른 선택Container Random

AccessInsert Erase Find Sort

list N/A C C N N log N

vector(deque)

C C~N C~N N N log N

set C log N log N log N C

map log N log N log N log N C

• 중복된 key 를 허용하고 싶을 때 multiset, multimap• 모든 경우에 대해 최적의 컨테이너는 없고 상황에 따라 효율적인 컨테이너를 골라 써야 한다 .

Page 75: C++프로그래밍 및 실무_06.17.pptx

75

반복자 (Iterator)• 컨테이너의 순회 방법을 일반화하기 위해 만든 개념

– 컨테이너 요소 하나를 가리킬 수 있다– 가리키는 지점의 요소를 읽거나 쓸 수 있다 . * 연산자 .– 증감 연산자에 의해 (++, --) 다음이나 이전 위치로 이동할 수

있다 .– 반복자끼리 대입 , 비교 연산이 가능하다 .

• 벡터의 경우 random access 가 가능하므로 index 를 증가시키는 for 문을 사용해도 무방

• 그러나 다른 종류의 컨테이너에 대해서는 ?– 반복자를 사용하면 컨테이너 순회를 정말 간결하게 표현할 수

있음

Page 76: C++프로그래밍 및 실무_06.17.pptx

76

반복자 (Iterator)• 컨테이너를 순회하면서 모든 원소 출력

typedef std::vector<int> Container;Container intArray;intArray.push_back(1);intArray.push_back(2);intArray.push_back(3);

for (Container::iterator itr = intArray.begin(); itr != intArray.end(); itr++){

cout << *itr << endl;}

• 컨테이너의 종류가 다른 것 (list, deque)으로 바뀌어도 아래 코드는 변하지 않는다

• 검색이나 단순 순회처럼 컨테이너에 들어있는 원소 값을 바꾸지 않는다면 상수 반복자를 사용할 수 있다 . Iterator 대신 const_iterator 를 쓴다 .begin -> cbegin, end -> cend

Page 77: C++프로그래밍 및 실무_06.17.pptx

77

Operator Overloading표현식 멤버 함수 멤버 함수가 아닐 때 예제@a a.operator@() operator@(a) !std::cin std::cin.operator!()

a@b a.operator@(b) operator@(a.b) std::cout << “hello world” std::cout.operator<<(const std::string&)

a=b a.operator=(b) X std::string s; s = “abc”;std::string.operator=(const char*)

a[b] a.operator[](b) X std::map<int, int> m; m[1] = 2; m.operator[](int)

a-> a.operator->(b) X std::unique_ptr<…> ptr; ptr->foo(); ptr.operator->()

a@ a.operator@(0) operator@(a,0) std::vector<…>::iterator i; i++; i.operator++(0);

Page 78: C++프로그래밍 및 실무_06.17.pptx

78

Operator + Overloadingclass ComplexNumber{public:ComplexNumber operator+(const ComplexNumber& e){

return ComplexNumber(this->real + e.real, this->imaginary + e.imaginary);}

• 복소수 끼리 더하는 연산• A @ B 형태이고 , 멤버 함수에서 operator@(B) 형태로 overload 가능

Page 79: C++프로그래밍 및 실무_06.17.pptx

79

Operator << Overloadingclass ComplexNumber{public:ComplexNumber(double real_, double imaginary_)

: real(real_), imaginary(imaginary_) {}

friend ostream& operator<< (ostream& os, ComplexNumber& a){

os << a.real << "+" << a.imaginary << "i";return os;

}/* 생략 */private:double real;double imaginary;};

ComplexNumber c1(1, 2);cout << c1 << endl; // 1+2i

* 의의 : stream 만 잘 정의되면 화면 출력이든 , 파일이든 , 아니면 네트워크든 모두 같은 양식으로 보낼 수 있다 .

friend 를 쓴 이유는 클래스의 멤버는 아니지만 클래스의 보호된 멤버에 접근하기 위해서임 ( 특수한 경우에만 사용해야함 )

Page 80: C++프로그래밍 및 실무_06.17.pptx

80

Operator() Overloading• Function Object 구현 시 사용 (Functor 라고도 불림 )• STL 의 많은 부분에서 사용되고 있음

// TEMPLATE FUNCTION sorttemplate<class _RanIt> inlinevoid sort(_RanIt _First, _RanIt _Last){ // order [_First, _Last), using operator<

_STD sort(_First, _Last, less<>());}

// TEMPLATE STRUCT lesstemplate<class _Ty = void>struct less: public binary_function<_Ty, _Ty, bool>{ // functor for operator<

bool operator()(const _Ty& _Left, const _Ty& _Right) const{ // apply operator< to operands

return (_Left < _Right);}

};

Page 81: C++프로그래밍 및 실무_06.17.pptx

81

알고리즘 (Algorithm)• for_each, find, find_if, count, count_if, …• copy, swap, transform, replace, fill, generate,

remove, unique, reverse, rotate, shuffle, …• partition, sort, nth_element, …• binary_search, …• min, max, …• next_permutation, prev_permutation, …

• http://www.cplusplus.com/reference/algorithm/

Page 82: C++프로그래밍 및 실무_06.17.pptx

82

std::for_each• std::for_each( 시작 iterator, 끝 iterator, 함수 );

struct PrintIntElement{ void operator()(int& elem){ cout << elem << endl;

} };std::for_each(intArray.begin(), intArray.end(), PrintIntElement());

std::for_each(intArray.begin(), intArray.end(), [](int& elem){ cout << elem << endl; } );

<Function object 의 활용 >

<C++11 에서 더 간결해진 문법 >

Algorithm 함수를 사용하여 코드를 만든 의도가 더 잘 드러나도록 할 수 있다 .

Page 83: C++프로그래밍 및 실무_06.17.pptx

83

std::sortvector<int> data;data.push_back(2);data.push_back(3);data.push_back(1);

sort(data.begin(), data.end()); // 오름차순 정렬struct Desc{

bool operator()(const int& e1, const int& e2){return e1 > e2;

}};sort(data.begin(), data.end(), Desc()); // 내림차순 정렬Predicate 함수를 갈아끼우는 방식으로 여러 가지 조건 구현 가능

Page 84: C++프로그래밍 및 실무_06.17.pptx

84

Algorithm 기타 예제

string msg = "The STL algorithms are generic because ...";transform(msg.begin(), msg.end(), msg.begin(), toupper);

transform 대문자로의 변환

next_permutation 순열 생성vector<int> a(3);for (size_t i = 0; i < a.size(); ++i)

a[i] = i + 1;

do{

copy(a.begin(), a.end(), ostream_iterator<int>(cout, "\t"));cout << endl;

} while (next_permutation(a.begin(), a.end())); 1 2 31 3 22 1 32 3 13 1 23 2 1Press any key to continue . . .

Page 85: C++프로그래밍 및 실무_06.17.pptx

85

예외 (Exception) 처리

• C 에서의 에러 처리 방법– 함수의 리턴값으로 판단하기

(unix 함수들은 에러가 발생하면 대부분 -1 리턴 )– global 변수에 저장된 에러 번호

• (윈도우 ) GetLastError() 함수• (unix) errno() 함수

– 개중에는 프로그램을 더이상 진행시킬 수 없는 에러도 있음

• C++ 에서는 예외 (exception) 처리 기능을 제공– 프로그램 실행 도중에 비정상적인 상황이 발생하여 더 이상

진행할 수 없을 때 , 예외를 발생시킴

Page 86: C++프로그래밍 및 실무_06.17.pptx

86

try-catch 구문try{

int *buffer = 0; //new int[N];if (buffer == nullptr)

throw exception("allocation failed");

int *buffer_2 = 0; //new int[N];if (buffer_2 == nullptr)

throw bad_exception();throw 123;

}catch (bad_exception& e){

cerr << e.what() << endl;}catch (exception& e){

cerr << e.what() << endl;}catch (int errorNumber){

cerr << errorNumber << endl;}catch (...){

cerr << "unknown exception" << endl;}

• try 블록 안의 명령들을 실행하다 throw 문에서 예외가 발생하면 catch 로 넘어가 예외를 처리한다 .• catch(…) 은 catch 구문에서 받기로 지정하지 않은 type 의 예외가 들어왔을 때의 처리다 .• C++ 에서 정의된 예외만 핸들링 가능• 만약 catch 해주는 코드가 없으면 함수를 바로 빠져나가 그 상위 함수에서 찾는다 .• Main 까지 가도 없으면 프로그램이 종료됨

Page 87: C++프로그래밍 및 실무_06.17.pptx

87

RTTI (Runtime Type Information)• 프로그램 실행 중 객체의 type 을 알 수 있도록 함• dynamic_cast, typeid 연산자 , type_info 클래스

Super super;Base base;Derived derived;

cout << typeid(super).name() << endl;cout << typeid(base).name() << endl;cout << typeid(derived).name() << endl;cout << typeid(int).name() << endl;cout << typeid(int*).name() << endl;

class Superclass Baseclass Derivedintint *Press any key to continue . . .

class Super { public: virtual ~Super(){} };class Base : public Super {};class Derived : public Base {};

Super* p = &derived;cout << typeid(*p).name() << endl;Super? or Derived?

Page 88: C++프로그래밍 및 실무_06.17.pptx

88

형변환 (Casting)

• C++ 의 세분화된 casting– static_cast– dynamic_cast– reinterpret_cast– const_cast

• Implicit casting ( 암시적 캐스팅 )• Explicit casting ( 명시적 캐스팅 )int i = 10;char c = i; // implicit castchar d = (char)i; // explicit cast (C style)char e = char(i); // explicit cast (C++ style)

Page 89: C++프로그래밍 및 실무_06.17.pptx

89

C 에서의 casting 의 관대함

32bit 에서는 int 와 int* 의 크기가 같으므로 아무런 문제가 없었지만 64bit 에서 int* 의 크기는 8bytes, int 의 크기는 그대로 4bytes 이므로 aabbccdd 만 출력됨

Page 90: C++프로그래밍 및 실무_06.17.pptx

90

static_cast• 실수형—정수형 , 정수형—열거형 (enum) 등의 기본

데이터 타입 간의 변환• void pointer 를 다른 형식의 pointer 로 변환• 서로 다른 type 간의 pointer끼리는 변환 불가

A* -> void* -> B* 는 됨…

Page 91: C++프로그래밍 및 실무_06.17.pptx

91

dynamic_cast• 모호한 포인터에 대한 변환• RTTI(Runtime Type Information) 정보를 확인하므로

– 추가적인 오버헤드 .• 실패 시 null 을 리턴

Shape

Rectangle Circle

Rectangle* -> Shape* 나Circle* -> Shape* 는 문제가 없음 그렇다면 Shape* 를 Rectangle* 로 변환할 수 있는지 ? (down-casting)

Page 92: C++프로그래밍 및 실무_06.17.pptx

92

• 포인터끼리 아무런 제약없이 변환• 정수형 <-> 포인터

int data = 301;int* ptr = &data;

cout << *ptr << endl;//cout << *static_cast<double*>(ptr) << endl;cout << *reinterpret_cast<double*>(ptr) << endl;

301-9.25596e+061Press any key to continue . . .

reinterpret_cast• 포인터의 상수성을 제거하는 데 사용

double PI = 3.14;const double* ptr = &PI;

// *ptr = 3.1415; // expression must be a modifiable value

*const_cast<double*>(ptr) = 3.1415;cout << *ptr << endl;

const_cast

Page 93: C++프로그래밍 및 실무_06.17.pptx

93

RAII(Resource Acquisition Is Initialization)

• Scope Bound Resource Management• 객체가 생성될 때 리소스를 획득 , 객체가 소멸할 때

리소스를 반환try{

FILE *fp;fopen_s(&fp, "input.txt",

"r");/* some works */throw exception();fclose(fp); // 안 불림 !!!

}catch (exception& e){

cerr << e.what() << endl;}

어떤 원인에서든지 (throw, return,break, goto 등등 ) 리소스를 획득하는 부분과 리소스를 반환하는 부분이 짝이 되지 못하게 되면 프로그램이 종료될 때까지 해당 리소스를 사용한 채로 열어두게 된다 .

Page 94: C++프로그래밍 및 실무_06.17.pptx

94

RAII(Resource Acquisition Is Initialization)

try{_ifstream ifs("input.txt");/* some works */throw exception();

}catch (exception& e){

cerr << e.what() << endl;}

class _ifstream{public: _ifstream(const char*) { cout << "open!" << endl; }virtual ~_ifstream(){ cout << "close!" << endl; }};

실제 ifstream 의 동작을 보기 어려우므로 (…)

open!close!Unknown exceptionPress any key to continue . . .

Scope 에서 벗어나는 순간 무조건 소멸자가 불리므로 앞 예제에서 하지 못했던 리소스 반환 절차를 진행할 수 있다 .

Page 95: C++프로그래밍 및 실무_06.17.pptx

95

Smart Pointer• new 와 delete 의 짝을 맞춰주는 일도 항상 골칫거리

• Smart Pointer (Reference Counted Pointer)– 포인터 객체가 생성될 때 +1, 소멸될 때 -1– 소멸자에서 Count값이 0 이 되면 delete 한다 .– 포인터끼리 복사가 일어나면 +1

• Overhead : 카운터를 저장할 공간 (4bytes?)

{shared_ptr<_ifstream> p(new _ifstream("input.txt")); // ref

= 1{

ConfigLoader loader(p); // ref = 2} // ref = 1

} // ref = 0 -> delete

Page 96: C++프로그래밍 및 실무_06.17.pptx

96

Smart Pointer• Reference Counted 가 잘못 동작하는 경우

• Type A 인 객체가 Smart Pointer<Type B> 를 들고 있고• Type B 인 객체가 Smart Pointer<Type A> 를 들고 있을 때

• 즉 , cyclic 관계가 형성될 때 Reference Count 가 제대로 되지 않는다 .

Shared_ptr<A>ref = 1

shared_ptr<B>ref = 1

B 가 생성되면서 A 를 참조Shared_ptr<A>

ref = 2

shared_ptr<B>ref = 1

B 가 먼저 소멸Shared_ptr<A>

ref = 2

shared_ptr<B>ref = 0

delete b;A 가 소멸되나ref=2 에서 ref=1 이므로

delete a; 는 호출되지 않는다Memory leak 발생

Page 97: C++프로그래밍 및 실무_06.17.pptx

97

소스 코드 버전 관리

• 소스 코드의 변경 사항을 추적하고 여러 사람이 협업하여 소프트웨어를 만들기 위한 도구– 코드를 여기저기 대량으로 수정했는데 잘못된 수정 !

(Diff & Revert)– 여러 사람이 각 파트를 맡아 개발한 뒤 자동으로 합쳐주는 건

없을까 ?(Merge)

– 실험적인 기능을 넣고 싶은데 기존 개발 흐름에 방해가 될 것 같음(Branch)

• 현재 널리 쓰이는 버전 관리– SVN (Subversion) 서버 - 클라이언트 구조– Git 분산 저장소 시스템 (

서버가 필요 없음 )

Page 98: C++프로그래밍 및 실무_06.17.pptx

98

SVN 구성

• SVN 서버– http://www.visualsvn.com/ 에서 무료로 다운로드 가능

• SVN 클라이언트– http://tortoisesvn.net/ - 탐색기와 연동됨

• Visual Studio 플러그인– AnkhSVN https://ankhsvn.open.collab.net/

Page 99: C++프로그래밍 및 실무_06.17.pptx

99

Git 구성

• 로컬에서만 작업하면 Git 서버 필요 없음• 무료 원격 저장소 ( 개인용 )

– Bitbucket https://bitbucket.org/ • Git 클라이언트

– SourceTree http://www.sourcetreeapp.com/ – TortoiseGit https://code.google.com/p/tortoisegit/

• 보다 친절한 설명서 (Googling: git 설명서 )– http://rogerdudler.github.io/git-guide/index.ko.html – http://git-scm.com/book/ko/

Page 100: C++프로그래밍 및 실무_06.17.pptx

100

Diff in SourceTree

이전에 commit 했던 버전과 비교하여 뭐가 달라졌는지 볼 수 있다 .

Page 101: C++프로그래밍 및 실무_06.17.pptx

101

Revert 기능

잘못된 수정인 경우 특정 시점으로 돌아갈 수도 있고 변경 이력에 누적

Page 102: C++프로그래밍 및 실무_06.17.pptx

102

Debugging 기능 잘 활용하기

• IDE(Visual Studio, Eclipse, …) 에서 제공하는 디버깅 기능을 잘 이용하기

• 디버거 기본 기능– Breakpoint

• 실행을 멈추고 싶은 지점에서 일시 정지– Step by step

• 한줄씩 실행하기 (Step over)• 현재 실행하려는 함수 안으로 들어가기 (Step in)• 현재 함수를 실행하고 바깥으로 나오기 (Step out)

– Watch• 각종 변수 값을 확인할 수 있음

– Call Stack• 이 함수로 어떻게 들어왔고 어떤 상황인지 파악

– Memory & Register

Page 103: C++프로그래밍 및 실무_06.17.pptx

103

Visual Studio Debug 메뉴

Page 104: C++프로그래밍 및 실무_06.17.pptx

104

Debugging 예제 – is_primebool is_prime(int n){

int cnt = 0;for (int i = 1; i*i < n; ++i){

if (n%i == 0){cnt++;if (cnt>1)

return false;}

}if (cnt == 1) return true;return false;

}

int _tmain(int argc, _TCHAR* argv[]){

for (int i = 1; i < 100; ++i){if (is_prime(i))

cout << i << "\t";}cout << endl;return 0;

}

2 3 4 5 7 9 11 13 17 1923 25 29 31 37 41 43 47 49 5359 61 67 71 73 79 83 89 97Press any key to continue . . .

처음부터 Step by Step 으로 들어가면 너무 오래 걸리니까 Is_prime 함수의 첫번째 줄에 Conditional Break 를 건다 .

즉 , n = 9 일 때 break 를 걸어보자

Page 105: C++프로그래밍 및 실무_06.17.pptx

105

Breakpoints Window

Page 106: C++프로그래밍 및 실무_06.17.pptx

106

Breakpoint Condition

우선 원하는 줄 왼쪽 칸을 클릭 해빨간 원 모양의 break point 를 설정한 뒤 ,Condition… 을 클릭

n == 9 일 때 멈춘다Conditional Breakpoint 는 십자 표시

Page 107: C++프로그래밍 및 실무_06.17.pptx

107

When Breakpoint Is Hit

9 의 약수는 1,3,9 이므로 3 까지는 계산했어야 했는데 2까지밖에 계산 안함

Page 108: C++프로그래밍 및 실무_06.17.pptx

108

Local Variables & Watch

현재 scope 상에서 살아있는 모든 local 변수의 type 과 값을 알려준다 .

Locals 에 자동으로 뜨는 변수 말고 다른 변수 값을 보고 싶으면 Watch 창을 이용한다 .

주소를 얻어오거나 포인터 참조 등을 하는 간단한 연산 정도는 됨

Page 109: C++프로그래밍 및 실무_06.17.pptx

109

Call Stack

현재 Break 가 걸린 지점을 기준으로 누가 이 함수를 불렀는지 알아낼 수 있다 .

Page 110: C++프로그래밍 및 실무_06.17.pptx

110

Call Stack (@ Stack Overflow)

Page 111: C++프로그래밍 및 실무_06.17.pptx

111

Call Stack (Symbol Loading)• 디버그 모드로 빌드되거나 디버그 심볼이 공개된

프로그램 ( 또는 모듈 ) 에 한해서 Symbol 파일을 로드하면 기계어 주소 대신 함수명을 볼 수 있고 추가적인 디버그 정보를 얻을 수 있다 .

회색으로 표시된 글자 ntdll.dll!770da22b() 이 부분이 심볼 파일이 로드 되지 않은 것이고 , 아래 스택 프레임은 정확하지 않을 수도 있음

Page 112: C++프로그래밍 및 실무_06.17.pptx

112

Call Stack (Symbol Loading)

옵션 Debugging Symbols 에서 Microsoft Symbol Servers 를 지정하면 MS에서 제공하는 심볼 파일 (*.pdb) 을 얻을 수 있다 . 심볼 파일이 로드되면 아까전 기계어 주소로 표시되었던 함수가 원래 함수 이름으로 바뀐다 .

Page 113: C++프로그래밍 및 실무_06.17.pptx

113

Magic Debugging NumberABABABAB HeapAlloc 으로 메모리 할당 후 가드 바이트에 채워진 값CCCCCCCC 초기화 되지 않은 스택 메모리CDCDCDCD 메모리 할당 후 초기화 되지 않은 힙 메모리BAADF00D LocalAlloc(LMEM_FIXED) 으로 메모리 할당된 후 초기화 되지 않은 값FDFDFDFD 할당된 메모리의 전후 가드용 바이트에 채워지는 값FEEEFEEE 힙 메모리를 해제한 후 채워지는 값int uninitialized_stack;int *pa = &uninitialized_stack;cout << hex << *pa << endl; // ccccccc

int *pb = new int[16];cout << hex << pb[0] << endl; // cdcdcdcd

Visual Studio 기준 & Debug 모드일 때만

Page 114: C++프로그래밍 및 실무_06.17.pptx

114

대형 C++ 프로젝트에서는 빌드 시간이 문제

• 코드 한줄 수정하고– 빌드 1 시간

• 완화 방법– 불필요한 Include 는 항상 제거하는 습관– 전방 선언 (Forward Declaration) 활용– 미리 컴파일된 헤더 (Precompiled Header)– Pimpl idiom– Cpp 묶어서 빌드하기 (unity build)

• 실제 프로젝트의 복잡도가 높아서라기 보단 잘못 설계된 헤더 파일 관계때문인 경우가 허다…

Page 115: C++프로그래밍 및 실무_06.17.pptx

115

C++ Include Tree

정말 간단한 프로그램을 빌드하기 위해서도 엄청나게 많은 헤더 파일들이 필요함결국 cpp 파일마다 빌드가 되어야 하는데 참조하지 않아도 될 include 덩어리들에 의한 부하가 상당해진다사실 왼쪽 그림은 매우 양호한 편

Page 116: C++프로그래밍 및 실무_06.17.pptx

116

Show Includes 옵션으로 검사하기

Page 117: C++프로그래밍 및 실무_06.17.pptx

117

Output Window 출력 메시지 (앞부분 )

1> Note: including file: r:\debugging\stdafx.h1> Note: including file: r:\debugging\targetver.h1> Note: including file: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\SDKDDKVer.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdio.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\sal.h1> Note: including file: c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sourceannotations.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vadefs.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\swprintf.inl1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\tchar.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wchar.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wtime.inl1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iostream1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\istream1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ostream1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ios1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocnum1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\climits1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\yvals.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\use_ansi.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\limits.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cmath1> Note: including file: c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h

Page 118: C++프로그래밍 및 실무_06.17.pptx

118

전방 선언 (Forward Declaration)• ClassA.h, ClassA.cpp, ClassB.h, ClassB.cpp 가 있을 때 ,• ClassB 작성 시 ClassA 가 필요하다면 ?

– #include “ClassA.h” 을 ClassB.h 파일에 넣기– 이제 ClassA.h 가 수정되면 ClassB.h 도 바뀌었고 , ClassB.cpp 도

바뀌므로 다시 빌드 되어야 함 ( 여기까진 문제가 없음 )– 그러나 ClassA.h 와 전혀 관계없던 ClassC.h 에서 ClassB.h 를 참조하고 있었다 . (흔한 상황 )

– 이렇게 꼬리에 꼬리를 물다보면 하나 수정해도 전체 프로젝트가 빌드됨 (-_-)

• 전방선언을 활용– ClassB.h 위에 class ClassA; 라고만 해둔다 . 이후 ClassB.cpp

에서 #include “ClassA.h” 를 해주고 – 단 , ClassA 의 포인터에 대해서만 가능한 방법 . 즉 , Class B 내에

필연적으로 ClassA a 와 같이 일반 변수가 들어가야 한다면 이 방법을 사용할 수 없다 . 그러나 대부분 기능 자체가 필요해서 쓰는 경우가 많으므로 ClassA *a 로 두고 heap 에 생성하는 식으로 꼼수를 쓸 수 있다 .

Page 119: C++프로그래밍 및 실무_06.17.pptx

119

Precompiled Header• C/C++ 빌드 과정에서 매번 반복적으로 컴파일하는 엄청난 분량의 헤더 파일 부하를 줄이기 위함

• stdafx.h 의 정체 (VS 기준 ; linux gcc 에서는 별도로 설정 )• 그렇다고 아무거나 넣으면 안됨 ( 잘 변경되지 않는 라이브러리

위주로 )