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

Slides:



Advertisements
Similar presentations
© 2010 인피니티북스 All rights reserved 제 7 장 클래스의 활용 C++ Espresso.
Advertisements

3. C++와 객체지향 C++ 코딩 방법 객체 단위로 2 개의 파일 인터페이스 파일 구현파일
명품 C++ 프로그래밍 3장. 클래스와 객체.
명품 C++ 8장 상속.
명품 C++ 4장. 객체 포인터와 객체 배열, 객체의 동적 생성.
Power C++ 제6장 포인터와 문자열.
C++ Espresso 제3장 배열과 포인터.
C++ Espresso 제3장 배열과 포인터.
C++ Espresso 제1장 기초 사항.
C++ Espresso 제2장 제어문과 함수.
쉽게 풀어쓴 C언어 Express 제13장 구조체 C Express Slide 1 (of 25)
C++ Espresso 제10장 프렌드와 연산자 중복.
Java Presentation 중간 시험2 풀이
강좌명 : C++프로그래밍 (C++ Programming)
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
제6장 객체배열과 벡터 객체 배열을 이해한다. 벡터(vector) 클래스를 사용할 수 있다.
명품 C++ 13장 예외 처리와 C 언어와의 링크 지정.
C++ Exspresso 제5장 클래스의 기초.
8. 객체와 클래스 (기본).
명품 JAVA Essential.
명품 JAVA Programming.
C++ Espresso 제9장 다형성.
[INA470] Java Programming Youn-Hee Han
어서와 Java는 처음이지! 제6장 클래스, 메소드 심층연구.
10장 템플릿과 표준 템플릿 라이브러리(STL)
배열, 포인터, 참조 배열은 같은 형을 가지는 변수들의 묶음이다..
명품 C++ 8장 상속.
C++ Espresso 제7장 클래스의 활용.
3장. 포인터, 배열, 구조체 포인터, 배열, 구조체 학습목표 기본적 데이터 타입
명품 Java Programming.
7장 클래스.
명품 C++ 7장 프렌드와 연산자 중복.
18장. 헤더 파일과 구현 파일 01_ 헤더 파일과 구현 파일의 사용.
14장. 함수 1 01_ 함수의 기본 02_ 인자의 전달.
Chapter 05. 클래스 완성. chapter 05. 클래스 완성 01. 복사 생성자 복사 생성(Copy Construction) 생성될 때 자신과 같은 타입의 객체를 변수로 받아, 이 객체와 같은 값을 갖는 새로운 객체를 생성하는 것 명시적인 생성 과정뿐만.
C ++ 프로그래밍 시작.
Chapter 1 C++ 기초 Copyright © 2010 Pearson Addison-Wesley. All rights reserved.
C++ Programming: chapter 7 – inheritence
제4장 클래스와 객체 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
C++ 개요 객체지향 윈도우즈 프로그래밍 한국성서대학교 유일선
스택(Stack) 김진수
17장. 문자열 01_ 문자열 사용의 기본 02_ 문자열의 사용.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
13. 연산자 오버로딩.
Chapter 3 클래스. 최호성.
제5장 생성자와 접근제어 객체 지향 기법을 이해한다. 클래스를 작성할 수 있다. 클래스에서 객체를 생성할 수 있다.
가상함수와 추상 클래스.
Chapter 1 C와는 다른 C++. 최호성.
제2장 제어구조와 배열 if-else 문에 대하여 학습한다. 중첩 if-else 문에 대하여 학습한다.
제 12장. 사용자 정의형으로서의 클래스 학기 프로그래밍언어및실습 (C++).
4. 고급변수 사용 : 포인터와 관련하여 메모리 바라보기
게임프로그래밍 I - 1차원 배열 - 공주대학교 게임디자인학과 박 찬 교수 2011년 4월 25일.
Chapter 12. String 클래스의 디자인
루프와 카운트 Looping and counting
멤버 함수인 operator+()가 실행, 또는 전역 함수인 operator+()가 실행 Point p3 = p1+p2; 에서
제8장 포인터와 동적객체 생성 포인터의 개념을 이해한다. 포인터와 관련된 연산을 이해한다.
C-언어와 기반구조 정보보호학과 이정수 교수.
5. 논리적 자료표현 : 구조체.
제 11장. 템플릿과 STL 학기 프로그래밍언어및실습 (C++).
3장,4장 발표 서정우.
03. 메모리 관리 C++ 프로그램에서 다룰 수 있는 메모리의 종류
C++ Espresso 제13장 입출력과 파일처리.
포인터와 배열 조 병 규 한 국 교 통 대 학 교 SQ Lab..
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
10장 템플릿과 표준 템플릿 라이브러리(STL)
컴퓨터 프로그래밍 기초 - 11th : 파일 입출력 및 구조체 -
실습과제 1번 /* 1. 멤버 변수로 반경 radius를 갖고, 그 값을 모니터에 출력하는
C# 09장. 클래스와 객체.
C.
C++ 언어의 특징
Presentation transcript:

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

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

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

객체의 일생

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

디폴트 생성자 #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;

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

매개 변수를 가지는 생성자 #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; };

매개 변수를 가지는 생성자 #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(); };

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

생성자의 중복 정의 생성자도 메소드이므로 중복 정의가 가능하다. #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) ; };

생성자의 중복 정의 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; 매개 변수가 있는 생성자 호출 디폴트 생성자 호출 계속하려면 아무 키나 누르십시오 . . .

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

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

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

생성자에서 다른 생성자 호출하기 … 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;

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

소멸자

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

소멸자 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; 생성자 소멸자 생성자 호출 소멸자 호출

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

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

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

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

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

참조자 멤버의 초기화 #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; 꿈의 자동차 계속하려면 아무 키나 누르십시오 . . .

객체 멤버의 경우 생성자 호출 #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) 생성자 호출

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

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

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

복사 생성자 #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; … };

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

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

예제 #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", 20100001); Student s2(s1); // 복사 생성자 호출 return 0;

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

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

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

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

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

예제 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;

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

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

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

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

예제 #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; }

예제 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;

예제 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일

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

예제 #include <iostream> using namespace std; class Time { private: int hour; // 0 - 23 int minute; // 0 - 59 int second; // 0 - 59 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); }

예제 // 두번째생성자 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;

예제 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; }

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

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

예제 #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)

예제 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)

예제 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;

예제 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

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

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

예제 // 생성자 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);

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

예제 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!

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

Q & A