Presentation is loading. Please wait.

Presentation is loading. Please wait.

C++ Espresso 제6장 생성자와 소멸자.

Similar presentations


Presentation on theme: "C++ Espresso 제6장 생성자와 소멸자."— Presentation transcript:

1 C++ Espresso 제6장 생성자와 소멸자

2 객체가 생성될 때 초기화를 담당하는 생성자에 대하여 살펴봅니다.
이번 장에서 학습할 내용 객체가 생성될 때 초기화를 담당하는 생성자에 대하여 살펴봅니다. 생성자 소멸자 초기화 리스트 복사 생성자 디폴트 멤버 함수

3 생성자 생성자(contructor): 객체가 생성될 때에 필드에게 초기값을 제공하고 필요한 초기화 절차를 실행하는 멤버 함수

4 객체의 일생

5 생성자의 특징 클래스 이름과 동일하다 반환값이 없다. 반드시 public 이어야 한다. 중복 정의할 수 있다.
class Car { public: Car() } }; 생성자

6 디폴트 생성자 #include <iostream> #include <string>
using namespace std; class Car { private: int speed; // 속도 int gear; // 기어 string color; // 색상 public: Car() { cout << "디폴트 생성자 호출" << endl; speed = 0; gear = 1; color = "white"; } }; int main() Car c1; // 디폴트생성자호출 return 0;

7 생성자의 외부 정의 Car::Car() { cout << "디폴트 생성자 호출" << endl;
speed = 0; gear = 1; color = "white"; }

8 매개 변수를 가지는 생성자 #include <iostream> #include <string>
using namespace std; class Car { private: int speed; // 속도 int gear; // 기어 string color; // 색상 public: Car(int s, int g, string c) { speed = s; gear = g; color = c; } void print() { cout << "============== " << endl; cout << "속도: " << speed << endl; cout << "기어: " << gear << endl; cout << "색상: " << color << endl; cout << "============== " << endl; };

9 매개 변수를 가지는 생성자 #include <iostream> #include <string>
using namespace std; class Car { private: int speed; // 속도 int gear; // 기어 string color; // 색상 public: Car(int s, int g, string c) { speed = s; gear = g; color = c; } void printInfo(); };

10 매개 변수를 가지는 생성자 int main() { Car c1(0, 1, "red"); // 생성자 호출
Car c2(0, 1, "blue"); // 생성자 호출 c1.print(); c2.print(); return 0; } ============== 속도: 0 기어: 1 색상: red 색상: blue

11 생성자의 중복 정의 생성자도 메소드이므로 중복 정의가 가능하다. #include <iostream>
#include <string> using namespace std; class Car { private: int speed; // 속도 int gear; // 기어 string color; // 색상 public: Car(); Car(int s, int g, string c) ; };

12 생성자의 중복 정의 Car::Car() { cout << "디폴트 생성자 호출<< endl;
speed = 0; gear = 1; color = "white" } Car::Car(int s, int g, string c) cout << "매개변수가 있는 생성자 호출<< endl; speed = s; gear = g; color = c; int main() Car c1; // 디폴트 생성자 호출 Car c2(100, 0, "blue"); // 매개변수가 있는 생성자 호출 return 0; 매개 변수가 있는 생성자 호출 디폴트 생성자 호출 계속하려면 아무 키나 누르십시오 . . .

13 생성자 호출의 다양한 방법 int main() { Car c1; // ①디폴트 생성자 호출
Car c2(); // ②이것은 생성자 호출이 아니라 c2()라는 함수의 원형 선언 Car c3(100, 3, "white"); // ③생성자 호출 Car c4 = Car(0, 1, "blue");// ④이것은 먼저 임시 객체를 만들고 이것을 c4에 복사 return 0; }

14 생성자를 하나도 정의하지 않으면? 컴파일러가 비어있는 디폴트 생성자를 자동으로 추가한다. class Car {
int speed; // 속도 int gear; // 기어 string color; // 색상 }; 컴파일러가 비어있는 디폴트 생성자를 자동으로 추가한다. class Car { int speed; // 속도 int gear; // 기어 string color; // 색상 public: Car() { } }

15 디폴트 매개 변수 디폴트 생성자를 정의한 것과 같은 효과를 낸다.
Car(int s=0, int g=1, string c=“red") { speed = s; gear = g; color = c; } 디폴트 생성자를 정의한 것과 같은 효과를 낸다.

16 생성자에서 다른 생성자 호출하기 … class Car { int speed; // 속도 int gear; // 기어
string color; // 색상 public: // 첫 번째 생성자 Car(int s, int g, string c) { speed = s; gear = g; color = c; } // 색상만 주어진 생성자 Car(string c) { Car(0, 0, c); // 첫 번째 생성자를 호출한다. }; int main() { Car c1("white"); return 0;

17 중간 점검 문제 1. 만약 클래스 이름이 MyClass라면 생성자의 이름은 무엇이어야 하는가?
2. 생성자의 반환형은 무엇인가? 3. 생성자는 중복 정의가 가능한가? 4. 클래스 안에 생성자를 하나도 정의하지 않으면 어떻게 되는가?

18 소멸자

19 소멸자의 특징 소멸자는 클래스 이름에 ~가 붙는다. 값을 반환하지 않는다. public 멤버 함수로 선언된다.
소멸자는 매개 변수를 받지 않는다. 중복 정의도 불가능하다. class Car { public: ~Car() } }; 소멸자

20 소멸자 class Car { private: int speed; // 속도 int gear; // 주행거리
string color; // 색상 public: Car() { cout << "생성자 호출" << endl; speed = 0; gear = 1; color = "white"; } ~Car() cout << "소멸자 호출" << endl; }; int main() Car c1; return 0; 생성자 소멸자 생성자 호출 소멸자 호출

21 디폴트 소멸자 만약 프로그래머가 소멸자를 정의하지 않았다면 어떻게 되는가? 디폴트 소멸자가 자동으로 삽입되어서 호출된다
class Time { int hour, minute, second; public: print() { ... } } ~Time()을 넣어준다.

22 중간 점검 문제 1. 만약 클래스 이름이 MyClass라면 소멸자의 이름은 무엇이어야 하는가?
2. 소멸자의 반환형은 무엇인가? 3. 소멸자는 중복 정의가 가능한가?

23 멤버 초기화 목록 멤버 변수를 간단히 초기화할 수 있는 형식
Car(int s, int g, string c) : speed(s), gear(g), color(c) { ...// 만약 더 하고 싶은 초기화가 있다면 여기에 }

24 상수 멤버의 초기화 멤버가 상수인 경우에는 어떻게 초기화하여야 하는가? class Car 아직 생성이 안됐음! {
const int MAX_SPEED = 300; int speed; ... } 아직 생성이 안됐음! class Car { const int MAX_SPEED; int speed; // 속도 public: Car() MAX_SPEED = 300; } 상수를 변경할 수 없음!

25 상수 멤버의 초기화 class Car { const int MAX_SPEED; int speed; // 속도 public:
Car() : MAX_SPEED(300) } }; 상수 멤버의 초기화는 이렇게.

26 참조자 멤버의 초기화 #include <iostream> #include <string>
using namespace std; class Car { string& alias; int speed; // 속도 public: Car(string s) : alias(s) cout << alias << endl; } }; int main() Car c1("꿈의 자동차"); return 0; 꿈의 자동차 계속하려면 아무 키나 누르십시오 . . .

27 객체 멤버의 경우 생성자 호출 #include <iostream> #include <string>
using namespace std; class Point { int x, y; public: Point(int a, int b) : x(a), y(b) } }; class Rectangle Point p1, p2; Rectangle(int x1, int y1, int x2, int y2) : p1(x1, y2), p2(x2, y2) 생성자 호출

28 중간 점검 문제 1. 초기화 리스트를 반드시 사용하여서 초기화해야되는 멤버의 타입은?
2. 클래스 MyClass의 상수 limit를 초기화 리스트를 사용하여서 초기화 하여 보라.

29 복사 생성자 한 객체의 내용을 다른 객체로 복사하여서 생성

30 복사 생성자의 특징 자동으로 디폴트 복사 생성자가 생성된다. 자신과 같은 타입의 객체를 매개 변수로 받는다.
Car(Car& obj); Car(const Car& obj);

31 복사 생성자 #include <iostream> #include <string>
using namespace std; class Car { int speed; // 속도 int gear; // 기어 string color; // 색상 public: Car(int s, int g, string c) : speed(s), gear(g), color(c) { cout << "생성자 호출" << endl; } Car(const Car &obj) : speed(obj.speed), gear(obj.gear), color(obj.color) cout << "복사 생성자 호출" << endl; };

32 복사 생성자 복사 생성자 호출 int main() { Car c1(0, 1, "yellow"); Car c2(c1);
c1.print(); c2.print(); return 0; } 복사 생성자 호출 ============== 속도: 0 기어: 1 색상: yellow

33 얕은 복사 문제 멤버의 값만 복사하면 안되는 경우가 발생한다. 얕은 복사(shallow copy) 문제 복사

34 예제 #include <iostream> #include <string>
using namespace std; class Student { char *name; // 이름 int number; public: Student(char *p, int n) { cout << "메모리 할당" << endl; name = new char[strlen(p)+1]; strcpy(name, p); number = n; } ~Student() { cout << "메모리 소멸" << endl; delete [] name; }; int main() { Student s1("Park", ); Student s2(s1); // 복사 생성자 호출 return 0;

35 예제 메모리 할당 메모리 소멸 메모리의 소멸이 2번 호출되었음

36 문제점 이름을 저장하는 동적 메모리 공간이 별도로 할당되지 않았음

37 깊은 복사 class Student { .... Student(const Student& s) {
cout << "메모리할당<< endl; name = new char[strlen(s.name)+1]; strcpy(name, s.name); number = s.number; } }; 메모리 할당 메모리 소멸

38 이름을 저장하는 동적 메모리 공간을 별도로 할당

39 복사 생성자가 호출되는 경우 기존의 객체의 내용을 복사하여서 새로운 객체를 만드는 경우
객체를 값으로 매개 변수로 전달하는 경우 객체를 값으로 반환하는 경우 생각보다 많이 사용됩니다. 복사 생성자

40 예제 class Car { Car(const Car &obj) : speed(obj.speed), gear(obj.gear), color(obj.color) { cout << "복사 생성자 호출" << endl; } }; void isMoving(Car obj) if( obj.getSpeed() > 0 ) cout << "움직이고 있습니다" << endl; else cout << "정지해 있습니다" << endl; int main() Car c(0, 1, "white"); isMoving(c); return 0;

41 실행 결과 일반 생성자 호출 복사 생성자 호출 정지해 있습니다 복사 생성자는 어디에서 호출되었을까?

42 중간 점검 문제 1. 복사 생성자는 언제 사용되는가? 2. 얕은 복사와 깊은 복사의 차이점은 무엇인가?

43 디폴트 멤버 함수 자동으로 추가된다. 디폴트 생성자 디폴트 소멸자 디폴트 복사 생성자 디폴트 할당 연산자

44 예제 Date 클래스에 생성자와 소멸자를 추가

45 예제 #include <iostream> using namespace std; class Date {
private: int year; int month; int day; public: Date(); // 디폴트생성자 Date(int year); // 생성자 Date(int year, int month, int day); // 생성자 void setDate(int year, int month, int day); // 멤버함수 void print(); // 멤버함수 }; Date::Date() // 디폴트생성자 { year = 2010; month = 1; day = 1; }

46 예제 Date::Date(int year) // 생성자 { setDate(year, 1, 1); }
Date::Date(int year, int month, int day) // 생성자 setDate(year, month, day); void Date::setDate(int year, int month, int day) this->month = month; // this는현재객체를가리킨다. this->day = day; this->year = year; void Date::print() cout << year << "년" << month << "월" << day << "일" << endl;

47 예제 int main() { Date date1(2009, 3, 2); // 2009.3.2
date1.print(); date2.print(); date3.print(); return 0; } 2009년 3월 2일 2009년 1월 1일 2010년 1월 1일

48 예제 Time 클래스에 생성자와 소멸자를 추가

49 예제 #include <iostream> using namespace std; class Time {
private: int hour; // int minute; // int second; // public: Time(); // 생성자 Time(int h, int m, int s); void setTime(int h, int m, int s); void print(); }; // 첫번째생성자 Time::Time() { setTime(0, 0, 0); }

50 예제 // 두번째생성자 Time::Time(int h, int m, int s) { setTime(h, m, s); }
// 시간설정함수 void Time::setTime(int h, int m, int s) hour = ((h >= 0 && h < 24) ? h : 0); // 시간검증 minute = ((m >= 0 && m < 60) ? m : 0); // 분검증 second = ((s >= 0 && s < 60) ? s : 0); // 초검증 // “시:분:초”의형식으로출력 void Time::print() cout << hour << ":" << minute << ":" << second << endl;

51 예제 int main() { Time time1; cout << "기본생성자호출후시간: ";
time1.print(); // 두번째생성자호출 Time time2(13, 27, 6); cout << "두번째생성자호출후시간: "; time2.print(); // 올바르지않은시간으로설정해본다. Time time3(99, 66, 77); cout << "올바르지않은시간설정후시간: "; time3.print(); return 0; }

52 예제 기본 생성자 호출 후 시간: 0:0:0 두번째 생성자 호출 후 시간: 13:27:6
기본 생성자 호출 후 시간: 0:0:0 두번째 생성자 호출 후 시간: 13:27:6 올바르지 않은 시간 설정 후 시간: 0:0:0

53 예제 Circle 객체 안에 Point 객체가 들어 있는 경우 Circle

54 예제 #include <iostream> #include <string>
using namespace std; class Point { private: int x; int y; public: Point(); Point(int a, int b); void print(); }; Point::Point() : x(0), y(0) { } Point::Point(int a, int b) : x(a), y(b)

55 예제 void Point::print() {
cout << "( " << x << ", " << y << " )\n"; } class Circle { private: int radius; Point center; // Point 객체가멤버변수로선언되어있다. public: Circle(); Circle(int r); Circle(Point p, int r); Circle(int x, int y, int r); void print(); }; // 생성자 Circle::Circle(): radius(0), center(0, 0)

56 예제 Circle::Circle(int r) : radius(r), center(0, 0) { }
Circle::Circle(Point p, int r) : radius(r), center(p) Circle::Circle(int x, int y, int r) : radius(r), center(x, y) void Circle::print() cout << "중심: "; center.print(); cout << "반지름: " << radius << endl << endl;

57 예제 int main() { Point p(5, 3); Circle c1; Circle c2(3);
Circle c3(p, 4); Circle c4(9, 7, 5); c1.print(); c2.print(); c3.print(); c4.print(); return 0; } 중심: ( 0, 0 ) 반지름: 0 반지름: 3 중심: ( 5, 3 ) 반지름: 4 중심: ( 9, 7 ) 반지름: 5

58 예제 문자열을 클래스로 작성해보자. H e l o W r d

59 예제 #include <iostream> using namespace std; class MyString {
private: char *pBuf; //동적으로할당된메모리의주소값저장 public: MyString(const char *s=NULL); MyString(MyString& s); ~MyString(); void print(); // 문자열을화면에출력 int getSize(); // 문자열의길이반환 };

60 예제 // 생성자 MyString::MyString(const char *s) { if( s == NULL )
pBuf = new char[1]; pBuf[0] = NULL; } else pBuf = new char[::strlen(s)+1]; strcpy(pBuf, s); // 복사생성자 MyString::MyString(MyString &s) pBuf = new char[s.getSize()+1]; strcpy(pBuf, s.pBuf);

61 예제 // 소멸자 MyString::~MyString() { if ( pBuf ) delete [] pBuf; }
void MyString::print() cout << pBuf << endl; int MyString::getSize() return strlen(pBuf);

62 예제 int main() { MyString str1; MyString str2("Hello");
MyString str3 = "World!"; MyString str4(str3); str1.print(); str2.print(); str3.print(); str4.print(); return 0; } Hello World!

63 중간 점검 문제 1. MyString 클래스에 두 개의 문자열을 합하는 멤버 함수인 add(String& s)를 추가하여 보자. 2. MyString 클래스에서 변환 생성자를 이용하여서 묵시적인 변환이 일어나지 못하도록 explicit를 다음과 같이 생성자에 추가한 후에 코드를 다시 컴파일하여 보자. 컴파일 오류가 발생하는 부분은 어디인가? explicit MyString(const char *s=NULL);

64 Q & A


Download ppt "C++ Espresso 제6장 생성자와 소멸자."

Similar presentations


Ads by Google