C++ 프로그래밍 07 2007년 2학기 전자정보공학대학 컴퓨터공학부
Outline Review: 동적 메모리 할당 Review: 문자열 헤더 파일과 구현 파일 객체지향 프로그래밍: CLASS
Review: 메모리 할당 컴퓨터 내의 메모리를 확보하는 일 정적(static) 메모리 할당 동적(dynamic) 메모리 할당 int a[100] : 100개의 정수공간 확보 (400 byte) 정적(static) 메모리 할당 프로그램 실행 전에 메모리 크기 결정 동적(dynamic) 메모리 할당 프로그램 실행 후에 메모리 크기 결정
Review: 정적 할당 vs. 동적 할당 int length = 100; int arr[length]; 배열은 변수를 사용해 크기 지정을 할 수 없다. 동적 할당은 변수를 통해 할 수 있다. int length = 100; int arr[length]; int length = 100; int * arr = new int [length];
Review: 동적 메모리 할당의 규칙(1) new, delete와 new[], delete[] 쌍을 맞춰서 사용하자. 해제한 메모리를 또 해제해서는 안 된다. int * p; p = new int; // 메모리 1개 할당 delete p; // 메모리 1개 해제 p = new int [100]; // 메모리 100개 할당 delete [] p; // 메모리 100개 해제 short* p = new short [100]; // 메모리를 할당한다. delete[] p; // 메모리를 해제한다. delete[] p; // 메모리를 해제한다. Error!
Review: 동적 메모리 할당의 규칙(2) NULL 포인터를 해제하는 것은 안전하다 char* p = NULL; delete p; // 혹은 delete[] p char* p = NULL; p = char [100]; delete [] p; p = NULL;
Review: C 스타일과 C++ 스타일의 문자열 C++: 문자열 클래스(string) 를 사용 C++이 더 개선된 방법이지만 기존에 만들어진 많은 소스 코드에서 C 스타일을 사용하고 있기 때문에 두 가지 스타일을 배워야 한다.
Review: 문자열의 길이와 복사 (C style) #include <iostream> #include <cstring> using namespace std; int main() { char src[] = “Sejong University"; int len = strlen(src); // 1. 길이를 잰다 char* dest = new char [len + 1]; // 2. 메모리 할당 strcpy(dest, src); // 3. 문자열 복사 cout << "src = " << src << "\n"; cout << "dest = " << dest << "\n"; delete[] dest; return 0; }
Review: 문자열의 결합과 비교 (C style) #include <iostream> #include <cstring> using namespace std; int main() { char str1[20] = "abcde"; char str2[] = "fghij"; strcat(str1, str2); cout<<“str1=“<<str1<<“\n”; if ( strcmp( str1, "abcdefghij") == 0) cout << "str1 and \"abcdefghij\" are identical.\n"; if ( strcmp( "123456", str1) != 0) cout << "\"123456\" and str1 are NOT identical.\n"; return0; }
Review: C++ 스타일의 문자열 생성 C++ 스타일의 문자열 변수를 생성하는 예 #include <iostream> #include <string> using namespace std; int main() { string s = "C++ Style~"; cout << s << "\n"; return 0; } [17-21]
Review: 문자열의 복사 (C++ Style) 대입 연산자(=) 사용 실행 결과 #include <iostream> #include <string> using namespace std; int main() { string src = “Sejong University"; string desc; desc = src; // 문자열 복사 cout << "src = " << src << "\n"; cout << "desc = " << desc << "\n"; return 0; }
Review: 문자열의 길이 (C++ Style) string 객체의 맴버함수 size() 사용 #include <iostream> #include <string> using namespace std; int main() { string s1; string s2 = "123"; string s3 = "abcdefg"; cout << "s1 = " << s1.size() << "\n"; cout << "s2 = " << s2.size() << "\n"; cout << "s3 = " << s3.size() << "\n"; return 0; }
Review: 문자열의 결합과 비교(C++ Style) #include <iostream> #include <string> using namespace std; int main() { string str1 = "abcde"; string str2 = "fghij"; str1 = str1 + str2; if ( str1 == "abcdefghij“ ) cout << "str1 and \"abcdefghij\" are identical.\n"; if ( "123456" != str1 ) cout << "\"123456\" and str1 are NOT identical.\n"; return 0; }
Review: 문자열의 검색 (C++ Style) string 객체의 맴버함수 find( ) 사용 #include <iostream> #include <string> using namespace std; int main() { string text = "Napster's pay-to-play service is officially out, " "and we have a review of the now-legit Napster. " "We also size up its companion music player from Samsung."; cout<< text <<“\n”; cout << "Offset of 'official' = " << text.find( "official" ) << "\n"; }
Review: 문자열의 일부분 얻기(C++ Style) string 객체의 맴버함수 substr( ) 사용 #include <iostream> #include <string> using namespace std; int main() { string path = "c:\\My Document\\Pictures\\33.jpg"; int len = path.size(); string ext = path.substr( len - 3, 3); cout << "extention = " << ext << "\n"; return 0; }
헤더 파일과 구현 파일
#include 지시문(1) 하나의 소스 파일로 된 예제 소스 코드 #include <iostream> #include <cmath> using namespace std; struct Point { int x, y; }; double Distance(Point p1, Point p2); int main() // 생략 double dist_a_b = Distance(a, b); } double Distance(Point p1, Point p2)
#include 지시문(2) #include 지시문을 사용해서 두 개의 소스 파일로 나누어 보자. // Example.h struct Point { int x, y; }; double Distance(Point p1, Point p2); // Example.cpp #include <iostream> #include <cmath> using namespace std; #include “Example.h” int main() { // 생략 double dist_a_b = Distance(a, b); } double Distance(Point p1, Point p2)
#include 지시문(3) 두 가지 버전의 예제를 비교해보자. [18-3]
헤더파일과 구현파일을 나누는 방법 하나의 소스 코드로 이루어진 프로그램을 여러 개의 헤더 파일과 구현 파일로 나눌 때 다음의 규칙대로 하자. 규칙 1. 공유될 함수가 있는 구현 파일의 이름을 따서, 헤더 파일을 만든다. 규칙 2. 이 헤더 파일에 공유될 함수의 원형을 적어준다. 규칙 3. 공유될 함수를 호출할 구현 파일에서는 이 헤더 파일을 포함한다. 규칙 4. 구현 파일에서는 자기 자신에 대한 헤더 파일을 포함한다.
실전 테스트 (1) 다음의 세 구현 파일이 제대로 컴파일 될 수 있도록 고치고, 헤더 파일도 추가하자. // A.cpp void A1() { A2(); } void A2() B1(); B2(); // B.cpp void B1() { } void B2() // Example.cpp int main() { A1(); B1(); return 0; }
실전 테스트 (2) 세 구현 파일의 호출 관계를 그림으로 그려보자. [18-7]
실전 테스트 (3) 앞에서 배운 규칙대로 한 결과 // A.h void A1(); void A2(); // B.h void B1(); void B2(); // B.cpp #include “B.h” void B1() { } void B2() // A.cpp #include “A.h” #include “B.h” void A1() { A2(); } void A2() B1(); B2(); // Example.cpp #include “A.h” #include “B.h” int main() { A1(); B1(); return 0; }
다른 파일에 있는 구조체 사용하기 (1) 하나의 소스 파일로 된 예제 소스 코드 struct Point { int x, y; }; double Distance(const Point& pt1, const Point& pt2) // 이 함수의 내용은 생략한다. return 0.0f; } int main() // 두 점을 만든다. Point a = {100, 100}; Point b = {200, 200}; // 함수를 호출한다. double dist; dist = Distance(a, b); return 0;
다른 파일에 있는 구조체 사용하기 (2) 여러 개의 파일로 나누어 보자. // Point.h struct Point { int x, y; }; // Example2.h double Distance(const Point& pt1, const Point& pt2); // Example2.cpp #include “Point.h” #include “Example2.h” double Distance(const Point& pt1, const Point& pt2) { // 이 함수의 내용은 생략한다. return 0.0f; } // Example1.cpp #include “Point.h” #include “Exaple2.h” int main() { // 두 점을 만든다. Point a = {100, 100}; Point b = {200, 200}; // 함수를 호출한다. double dist; dist = Distance(a, b); return 0; }
다른 파일에 있는 구조체 사용하기 (3) 파일들의 포함 관계를 그림으로 그려보자. [18-10]
다른 파일에 있는 구조체 사용하기 (4) 다른 파일에 있는 구조체를 사용하기 위한 방법을 정리해보자. 규칙 1. 구조체의 이름을 따서 새로운 헤더 파일을 만든다. 규칙 2. 이 헤더 파일에 구조체의 정의 부분을 위치시킨다. 규칙 3. 구조체를 사용하는 구현 파일마다 이 헤더 파일을 포함시킨다.
헤더 파일이 두 번 포함되는 것 막기 전처리기를 사용해서 헤더 파일의 중복 포함을 막는 예 중복 포함을 막는 방법 정리 헤더 파일의 이름을 따서 심볼을 만든다 ( 예: POINT_H ) 헤더 파일의 제일 앞에 이 심볼을 사용해서 #ifndef, #define 명령을 추가한다. 헤더 파일의 제일 끝에 #endif를 추가한다. // Point.h #ifndef POINT_H #define POINT_H struct Point { int x, y; }; #endif
표준 라이브러리의 헤더 파일 표준 라이브러리의 헤더 파일은 <> 를 사용해서 포함한다. 우리가 만든 헤더 파일은 “”를 사용해서 포함한다. <> 를 사용한 경우에는 컴파일러와 함께 표준 라이브러리 설치된 디렉토리에서 헤더 파일을 찾는다. 반면에 “”를 사용한 경우에는 여러 분이 작업 중인 프로젝트가 위치한 디렉토리에서 헤더 파일을 찾는다. #include <iostream> #include <string> #include <cmath> #include “Example1.h”
객체 지향 프로그래밍의 이해 (Object Oriented Programming)
객체지향 프로그래밍의 비유(1) 객체지향 프로그래밍은 부품을 모아서 조립하는 과정이 비유할 수 있다. 여기서 객체를 부품이라고 볼 수 있다. [20-1]
객체지향 프로그래밍의 비유(2) 부품별로 분업할 수 있는 것처럼, 객체를 만들 때도 자신의 객체에 대해서만 노력을 집중할 수 있다. 제가 발생한 경우에 해당 부품만 교체하면 되듯이, 객체에 문제가 있는 경우에는 해당 객체만 고치면 된다. [20-2]
객체지향 프로그래밍의 비유(3) 하나의 부품을 여러 제품에 사용할 수 있는 것처럼, 잘 만들어 놓은 객체는 다음 번 프로젝트에도 재사용할 수 있다. 부품들의 규격이 정해져 있어야 조립이 가능한 것처럼, 객체간의 연결 부분도 잘 약속되어 있어야 한다. [20-4] [20-5]
클래스(Classes)와 객체(Objects) (1) 클래스와 객체는 ‘붕어빵 틀’과 ‘붕어빵’의 관계다. 혹은 ‘제품의 설계도’와 ‘제품’의 관계라고 말할 수도 있다. [20-6]
클래스(Classes)와 객체(Objects) (2) 문법적인 측면에서 바라본 클래스와 객체 [20-7]
캡슐화(Encapsulation) 캡슐화란 약속되지 않은 부분은 감싸서 숨겨버리는 것을 말한다. 캡슐화를 통해서 정보은닉을 달성할 수 있다. [20-10]
상속(Inheritance) 상속이란 기존 클래스를 토대로 새로운 클래스를 만드는 방법을 말한다. 예) 상속 모형 예) 붕어빵 틀을 상속받아서 수염 달린 붕어빵 틀을 만들기
다형성(Polymorphism)(1) 다형성이란 서로 다른 객체를 동일한 방식으로 명령을 내릴 수 있는 성질을 말한다. 이 때 서로 다른 객체들은 같은 명령을 받지만 제각기 다른 방식으로 명령을 수행할 수 있다. 예) 백열들과 삼파장 램프는 동일한 소켓에 끼워서 사용할 수 있다. [20-13]
다형성 (2) 문서 저장 객체와 HTML 저장 객체의 예 [20-14]
클래스와 객체
클래스의 정의 Point 클래스를 정의하는 예 // Point 클래스를 정의한다. class Point { public: // 멤버 변수들 int x, y; // 멤버 함수 void Print() cout << "( " << x << ", " << y << ")\n"; } };
클래스의 정의 Point 클래스를 정의하는 예
객체의 생성과 사용(1) 클래스 객체를 생성하고 사용하는 예 // 객체를 생성한다. Point pt1, pt2; pt1.x = 100; pt1.y = 100; pt2.x = 200; pt2.y = 200; // pt1, p2의 내용을 출력한다. pt1.Print(); pt2.Print();
객체의 생성과 사용(2) Print() 함수에서 사용하는 x, y의 의미 [21-3]
일반 함수와 멤버 함수의 차이점 다음과 같은 차이점을 가지고 있다. 외부에서 멤버 함수를 호출하기 위해서는 객체의 이름을 명시해주어야 한다. 멤버 함수 안에서는 객체의 이름을 명시하지 않고 멤버에 접근할 수 있다. 외부에서 접근 할 수 없도록 설정된 멤버라 할지라도 멤버 함수 안에서는 접근할 수 있다.
멤버 함수의 위치 클래스의 정의 바깥쪽에 멤버 함수를 정의한 예 class Point { public: // 멤버 변수 int x, y; // 멤버 함수 void Print(); }; void Point::Print() cout << "( " << x << ", " << y << ")\n"; }
멤버 함수 안에서의 이름 충돌 클래스의 정의 바깥쪽에 멤버 함수를 정의한 예 class Point { public: // 멤버 변수 int x, y; // 멤버 함수 void Print(); }; void Point::Print() int x = 333; cout << "( " << x << ", " << y << ")\n"; }
객체를 사용한 초기화와 대입 일반 변수와 같은 방식으로 초기화와 대입 가능 Point pt1, pt2; pt1.x = 100; pt1.y = 100; pt2.x = 200; pt2.y = 200; // pt1을 사용해서 새로운 pt3를 초기화 한다. Point pt3 = pt1; pt3.Print(); // pt2을 pt3에 대입한다. pt3 = pt2;
생성자와 소멸자 생성자는 객체를 생성할 때 자동으로 호출되는 함수이다. 소멸자는 객체를 소멸할 때 자동으로 호출되는 함수이다. 그러므로 생성자는 객체를 사용할 수 있도록 초기화 하는 코드를 넣기에 알맞은 장소이다. 소멸자는 객체를 소멸할 때 자동으로 호출되는 함수이다. 그러므로 소멸자는 객체가 사용한 리소스를 정리하는 코드를 넣기에 알맞은 장소이다.
디폴트 생성자(Default Constructors) 디폴트 생성자의 추가 class Point { public: int x, y; void Print(); Point(); }; Point::Point() x = 0; y = 0; } // 실제 실행 시.. Point pt; // 생성자가 호출된다. pt.Print();
인자가 있는 생성자(1) 인자가 있는 생성자의 추가 class Point { public: int x, y; void Print(); Point(); Point(int initialX, int initialY); }; Point::Point(int initialX, int initialY) x = initialX; y = initialY; } // 중간 생략 Point pt(3, 5); pt.Print();
인자가 있는 생성자(2) 생성자로의 인자 전달
복사생성자(Copy Contructors)(1) class Point { public: int x, y; void Print(); Point(); Point(int initialX, int initialY); Point(const Point& pt); }; Point::Point(const Point& pt) cout << "복사 생성자 호출됨!!\n"; x = pt.x; y = pt.y; } // 중간 생략 Point pt1(100, 100), pt2(200, 200); // pt1을 사용해서 새로운 pt3를 초기화 한다. Point pt3 = pt1; pt3.Print(); // pt2을 pt3에 대입한다. pt3 = pt2; 복사 생성자의 추가 [21-8]
복사생성자(Copy Contructors)(2) 복사 생성자는 자기 자신의 타입에 대한 레퍼런스를 인자로 받는 생성자다. 그러므로 다음의 두 가지 원형 중 한 가지 모습을 가질 수 있다. 다음과 같은 두 가지 방식으로 복사 생성자를 호출할 수 있다. Point( Point& pt ); Point( const Point& pt ); Point pt1; Point pt2 = pt1; Point pt3( pt1 );
얕은 복사와 깊은 복사 기본적으로 제공되는 복사 생성자는 얕은 복사를 하도록 구현되어 있다. 깊은 복사가 필요하다면 별도의 복사 생성자를 만들어야 한다. [21-11]
반드시 생성자가 필요한 경우 멤버 변수중에 레퍼런스 변수 혹은 Const 속성의 변수가 있는 경우에는 반드시 생성자에서 초기화 해주어야 한다. class NeedConstructor { public: const int maxCount; int& ref; int sample; NeedConstructor(); }; NeedConstructor::NeedConstructor() : maxCount(100), ref(sample) sample = 200; }
소멸자(1) 소멸자를 사용해서 할당한 메모리를 해제하는 예 class DynamicArray { public: int* arr; DynamicArray(int arraySize); ~DynamicArray(); }; DynamicArray::DynamicArray(int arraySize) // 동적으로 메모리를 할당한다. arr = new int [arraySize]; } DynamicArray::~DynamicArray() // 메모리를 해제한다. delete[] arr; arr = NULL;
소멸자(2) 소멸자를 사용해서 할당한 메모리를 해제하는 예 int main() { // 몇 개의 정수를 입력할지 물어본다. 소멸자를 사용해서 할당한 메모리를 해제하는 예 int main() { // 몇 개의 정수를 입력할지 물어본다. int size; cout << "몇 개의 정수를 입력하시겠소? "; cin >> size; // 필요한 만큼의 메모리를 준비한다. DynamicArray da(size); // 정수를 입력 받는다. for (int i = 0; i < size; ++i) cin >> da.arr[i]; // 역순으로 정수를 출력한다. for (i = size - 1; i >= 0; --i) cout << da.arr[i] << " "; cout << "\n"; // 따로 메모리를 해제해 줄 필요가 없다. return 0; }
소멸자(3) DynamicArray 객체를 생성한 모습 [21-20]
접근 권한 설정하기(1) 멤버의 접근 권한을 설정하는 예 class AccessControl { public: char publicData; void publicFunc() {}; protected: int protectedData; void protectedFunc() {}; private: float privateData; void privateFunc() {}; }; int main() // 객체를 생성하고, 각 멤버에 접근해보자 AccessControl ac; ac.publicData = 'A'; // 성공 ac.publicFunc(); // 성공 ac.protectedData = 100; // 실패 ac.protectedFunc(); // 실패 ac.privateData = 4.5f; // 실패 ac.privateFunc(); // 실패 return 0; } 멤버의 접근 권한을 설정하는 예
접근 권한 설정하기(2) 멤버의 접근 권한 설정하기 접근 권한 키워드에 대한 요약 (뒤에서 더욱 자세히 분류) [21-23] public : 외부에서의 접근을 허용한다. protected, private : 외부에서 접근할 수 없다. [21-23]
접근자 접근자란 외부에서 접근이 거부된 멤버 변수의 값을 읽거나, 변경하려는 용도의 멤버 함수를 말한다. class Point { public: void SetX(int value) if (value < 0) x = 0; else if (value > 100) x = 100; else x = value; } int GetX() {return x;}; // 중간 생략 private: // 멤버 변수 int x, y; };
정적 멤버 (Static Members) 정적 멤버란 모든 객체들이 공유하는 멤버를 말한다. [21-29]
정적 멤버를 사용한 객체의 개수 세기(1) class Student { public: string name; // 이름 int sNo; // 학번 Student(const string& name_arg, int stdNumber); ~Student(); // 정적 멤버들 static int student_count; static void PrintStdCount(); }; // 정적 멤버 변수 int Student::student_count = 0; // 정적 멤버 함수 void Student::PrintStdCount() cout << "Student 객체 수 = " << student_count << "\n"; }
정적 멤버를 사용한 객체의 개수 세기(2) Student::Student(const string& name_arg, int stdNumber) { // 학생 객체의 수를 증가시킨다. student_count++; name = name_arg; sNo = stdNumber; } Student::~Student() // 학생 객체의 수를 감소시킨다. student_count--; void Func() Student std1("Bill", 342); Student std2("James", 214); Student::PrintStdCount();
정적 멤버를 사용한 객체의 개수 세기(3) 정적 멤버를 사용해서 객체의 개수를 세는 예 int main() { Student::PrintStdCount(); Student std("Jeffrey", 123); Func(); return 0; }
헤더 파일과 소스 파일로 나누기 헤더 파일에 넣어야 할 것과 구현 파일에 넣어야 할 것 Point 클래스 예제를 헤더 파일과 구현 파일로 나눈 예 [21-32]
인라인 함수 = 함수를 인라인으로 만들면 실제로 함수가 호출되는 대신에, 함수를 호출한 위치에 함수의 내용이 그대로 옮겨진다. // 인라인 함수 inline void Func() { cout << “왜 인라인 함수를 쓰지?\n”; cout << “도대체 인라인이 뭐야!!\n”; cout << “뭐! 내가 인라인이야?\n”; } int main() // 인라인 함수를 호출한다. Func(); return 0; = int main() { // 인라인 함수를 호출한다. cout << “왜 인라인 함수를 쓰지?\n”; cout << “도대체 인라인이 뭐야!!\n”; cout << “뭐! 내가 인라인이야?\n”; return 0; }
인라인 함수를 만드는 법 멤버 함수를 인라인으로 만드는 방법에는 두 가지가 있다. 클래스의 내부에 정의한 멤버 함수들은 자동으로 인라인 함수가 된다. 클래스의 외부에 정의한 멤버 함수는 함수의 정의 앞에 inline 키워드를 추가한다. class CPoint { // 중간 생략 }; inline void CPoint::SetX(int value) if (value < 0) x = 0; else if (value > 100) x = 100; else x = value; } inline void CPoint::SetY(int value) if (value < 0) y = 0; else if (value > 100) y = 100; else y = value;
인라인 함수의 사용 규칙 인라인 함수는 헤더 파일에 위치해야 한다. 크기가 작은 함수만 인라인으로 만드는 것이 좋다. 인라인 함수가 클래스의 정의 내부에 있는 경우 => 어차피 클래스의 정의는 헤더 파일에 위치하므로 특별히 신경 써줄 것이 없다. 인라인 함수가 클래스의 정의 외부에 있는 경우 => 함수의 정의를 반드시 헤더 파일에 위치시켜야 한다. 크기가 작은 함수만 인라인으로 만드는 것이 좋다. 크기가 큰 함수를 인라인으로 만들면 실행 파일의 크기가 커지기 때문에 실행 성능이 낮아질 수 있다.
Const 함수 다음의 조건을 만족 하는 함수만 Const 함수로 만들 수 있다. 멤버 변수의 값을 변경하지 않는 멤버 함수 멤버 함수를 Const 함수로 만들면 좋은 점 다른 개발자가 “아, 이 함수는 멤버 변수의 값을 변경하지 않는구나”라고 생각하게 만든다. 실수로 멤버 변수의 값을 바꾸려고 하면, 컴파일러가 오류 메시지를 통해서 알려준다. 객체가 Const 속성을 가진 경우에는 Const 함수만 호출할 수 있다. [12-36]
Const 함수의 사용(1) 가능한 모든 함수를 Const 함수로 만드는 것이 좋다. class Point { public: // 멤버 함수 void Print() const; // 생성자들 Point(); Point(int initialX, int initialY); Point(const Point& pt); // 접근자 void SetX(int value); void SetY(int value); int GetX() const {return x;} int GetY() {return y;} private: // 멤버 변수 int x, y; };
Const 함수의 사용(2) Const 객체를 통해서 멤버 함수를 호출하는 예 매개변수 pt가 Const 객체이지만 CPoint::GetX()는 Const 함수이기 때문에 호출될 수 있다. 그러나, CPoint::GetY() 는 Const 함수가 아니기 때문에 컴파일 오류를 발생시킨다. void Area( const Point& pt) { // (0,0)과 pt 가 이루는 사각형의 면적을 구한다. int area = pt.GetX() * pt.GetY(); // Error // 결과 출력 cout << "(0, 0)과 이 점이 이루는 사각형의 면적 = " << area << "\n"; }
멤버 함수에 대한 포인터(1) 멤버 함수에 대한 포인터 타입을 정의하는 예 #include "Point.h" // void XX() 형태의 함수에 대한 포인터 typedef void (*FP1)(int); // void Point::XX() 형태의 멤버 함수에 대한 포인터 typedef void (Point::*FP2)(int); int main() { // 객체를 생성한다. Point pt(50, 50); // FP1, FP2를 사용해서 Print() 함수를 가리킨다. // FP1 fp1 = &Point::SetX; // 에러 FP2 fp2 = &Point::SetX; // 성공 // 함수 포인터를 사용해서 함수 호출 (pt.*fp2)(100); // 내용 출력 pt.Print(); return 0; }
멤버 함수에 대한 포인터(2) 멤버 함수의 포인터 타입 정의와 호출
객체의 배열(1) 객체의 배열을 정의하는 경우 디폴트 생성자로 초기화 된다. #include "Point.h" int main() { // 점 3개의 배열 Point arr[3]; // 모든 원소를 출력한다. for (int i = 0; i < 3; ++i) arr[i].Print(); return 0; }
객체의 배열(2) 객체의 배열을 초기화하는 예 int main() { // 점 3개의 배열 Point arr[3] = { Point(100, 100), Point(50, 100), Point( 10, 10) }; // 모든 원소를 출력한다. for (int i = 0; i < 3; ++i) arr[i].Print(); return 0; }
객체의 동적인 생성 동적 메모리 할당을 사용해서 객체를 생성하는 예 Point pt(50, 50); Point* p1 = new Point(); // 디폴트 생성자 사용 Point* p2 = new Point(100, 100); // 인자있는 생성자 사용 Point* p3 = new Point( pt); // 복사 생성자 사용 p1->Print(); p2->Print(); p3->Print(); delete p1; delete p2; delete p3;
생성자와 소멸자의 호출 시점(1) 동적 메모리 할당을 사용한 경우의 생성자와 소멸자의 호출 시점을 알아보자. int main { Point pt(100, 100); Point* p = 0; p = new Point(50, 50); pt.Print(); p->Print(); // 동적으로 생성한 객체를 해제한다. delete p; p = NULL; return 0; }
생성자와 소멸자의 호출 시점(2) 생성자와 소멸자의 호출 시점을 표로 정리
클래스 안에 넣을 수 있는 다른 것들 열거체나 typedef을 클래스 안에서 정의하는 예 class Point { public: enum { MIN_X = 0, MAX_X = 100, MIN_Y = 0, MAX_Y = 100 }; typedef int COOR_T; // 좌표의 타입 // 멤버 함수 void Print() const; void Offset(COOR_T x_delta, COOR_T y_delta); void Offset(const Point& pt); // 생성자들 Point(); Point(COOR_T initialX, COOR_T initialY); Point(const Point& pt); // 접근자 void SetX(COOR_T value); void SetY(COOR_T value); COOR_T GetX() const {return x;}; COOR_T GetY() const {return y;}; private: // 멤버 변수 COOR_T x, y; };
This 포인터(1) 멤버 함수 안에서 자기 자신의 주소를 확인하는 예 class WhoAmI { public: int id; WhoAmI(int id_arg); void ShowYourself() const; }; WhoAmI:: WhoAmI(int id_arg) id = id_arg; } void WhoAmI::ShowYourself() const cout << "{ID = " << id << ", this = " << this << "}\n";
This 포인터(2) 멤버 함수 안에서 자기 자신의 주소를 확인하는 예 int main() { // 세 개의 객체를 만든다. WhoAmI obj1( 1); WhoAmI obj2( 2); WhoAmI obj3( 3); // 객체들의 정보를 출력한다. obj1.ShowYourself(); obj2.ShowYourself(); obj3.ShowYourself(); // 객체들의 주소를 출력한다. cout << "&obj1 = " << &obj1 << "\n"; cout << "&obj2 = " << &obj2 << "\n"; cout << "&obj3 = " << &obj3 << "\n"; return 0; }
This 포인터(3) 멤버 함수의 호출과 가상의 코드 [21-50]
연습 student class 를 구현(헤더 파일과 구현파일 사용) 이름, 번호,수학, 영어, 국어 점수의 맴버 변수 총점 및 평균을 구하는 맴버 함수 학생의 내용을 입력 받는 함수 학생의 내용을 이쁘게 출력해 주는 print() 맴버함수 student로 4개의 크기를 갖는 배열을 만들고 내용을 입력하면 출력해 주는 프로그램