일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 아두이노
- C언어
- 시스템프로그래밍
- 라인트레이서
- map
- Array
- html
- Visual Micro
- Stack
- c++
- queue
- Deque
- 아두이노 소스
- LineTracer
- 운영체제
- stl
- directx
- 아두이노 컴파일러
- 수광 소자
- 통계학
- 자료구조
- Algorithm
- arduino compiler
- priority_queue
- list
- set
- 컴퓨터 그래픽스
- Arduino
- WinAPI
- vector
- Today
- Total
Kim's Programming
C++ - 생성자(Constructor) 본문
생성자
객체초기화
1 2 3 4 | Position posit; Posit.x=40; Posit.y=10; Posit.ch='A' | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include<iostream> class Position { private: int x; int y; char ch; public: Position(int ax, int ay, char ach) { x = ax; y = ay; ch = ach; } void Output() { printf(" 위치는 x : %d , y : %d입니다.\n", x, y); printf(" 문자 = %c\n", ch); } }; void main() { Position Posit(30, 10, 'A'); Posit.Output(); } | cs |
클래스의 이름이 Position이므로 생성자 함수의 이름도 똑같습니다. Position 생성자는 세 개의 인수를 전달 받아 대응되는 멤버 변수에 대입함으로써 객체를 초기화합니다. 멤버에 값을 대입하는 것이 본연의 임무이므로 생성자의 본체는 통상 단순한 대입문으로 구성됩니다. Position 클래스가 생성자를 정의하고 있으므로 main 함수의 코드는 단 두줄만 있으면 됩니다. Posit 객체 선언문 뒤의 괄호 안에 멤버의 초기값들이 나열되어 있는데 이 값들이 생성자의 형식 인수로 전달됩니다. 생성자에 의해 Posit의 (x,y)는 (30,10)으로 초기화되고 ch는 'A'문자로 초기화 됩니다. Output함수를 호출하면 초기화 된 값들을 출력할 것입니다.
::생성자 호출
생성자는 객체가 생성될 떄 컴파일러에 의해 자동으로 호출됩니다. 사용자는 객체 선언문의 뒤쪽에 생성자로 전달될 인수를 명시함으로써 생성자를 호출하는데는 두 가지 방법이 있습니다.
암시적 방법 : Position Posit(30,10,'A');
명시적 방법 : Position Posit = Position(30,10,'A');
컴파일러에 따라 이 두 문장을 처리하는 내부적인 동작은 조금 달라질 수 있어도 객체를 초기화하는 효과는 동일합니다. 암시적 방법의 경우 객체를 위한 메모리를 할당하고 생성자를 호출하여 할당된 메모리를 초기화합니다. 명시적인 방법은 두 가지 형태로 처리되는데 암시적인 방법과 같은 식으로 초기화 하는 컴파일러도 있고 이름없는 임시 객체를 만든후 대입하는 컴파일러도 있지만 초기화 된다는 결론만은 그대로기 떄문에 암시적 방법을 더 많이 이용합니다.
::생성자 인수
생성자가 객체를 초기화하기 위해서는 멤버의 모든 초기값을 인수로 전달받아야 합니다. 그래서 생성자의 형식 인수 목록은 보통 멤버 목록과 일치하는 경우가 많은데 이때 형식인수 이름이 멤버 이름과 같아서는 곤란하게 됩니다 다음 생성자 코드를 보겠습니다.
1 2 3 4 5 6 | Position(int x, int y, char ch) { x = x; y = y; ch = ch; } | cs |
형식 인수의 이름이 멤버의 이름과 똑같이 되어있는데 지역변수가 전역이나 멤버보다 더 우선인 규칙에 의해 에러는 발생하지는 않습니다. 하지만 이 경우 함수 본체에서 참조하는 x,y,ch는 객체의 멤버 변수가 아니라 형식 인수이며 자신에게 자신의 값을 대입하는 아무 의미없는 코드가 됩니다. 생성자 본체에서 전달받은 인수와 초기화할 멤버의 이름을 구분해야하는데 다음의 방법들을 쓸 수 있습니다.
- 형식 인수에 일정한 점두를 붙여 멤버 이름과 구분되도록 합니다. 위의 코드의 경우는 ax,ay,ach등으로 접두 a를 붙였는데 Arugument의 머리글자 a를 따온것 입니다. 접두를 붙이든 접미를 붙이든 멤버 변수의 이름과 구분되어야 합니다. 완전히 다른 이름을 붙이면 문법적으로는 문제는 없지만 인수 멤버간 대응관계를 파악하기 어려워 알아보기 위함입니다.
- 멤버 이름을 작성하는 특별한 규칙을 정하고 이 규칙대로 멤버의 이름을 짓습니다. MFC의 경우 m_라는 접두를 클래스의 멤버에 일일이 붙이는데 이 방식대로 Position클래스를 작성한다면 멤버의 이름은 m_x,m_y,m_ch가 됩니다. 멤버 이름에 특별한 규칙이 적용되므로 생성자에서는 m_을 뺀 x,y,ch를 형식 인수로 사용할 수도 있습니다. 멤버마다 m_을 붙이는 것은 귀찮은 과정이지만 명칭으로 멤버임을 구별할 수 있는 것이기도 합니다.
- 형식 인수 이름과 멤버 이름을 같이 쓰되 함수의 본체에서 멤버 변수를 참조할 때 범위 연산자를 사용합니다. 범위 연산자는 지역변수와 클래스의 멤버를 구분할 때도 사용할 수 있습니다.123456Position(int x, int y, char ch){Position::x = x;Position::y = y;Position::ch = ch;}
cs 그냥 x는 인수 x를 의미하는 것이 아니고 Position::x는 Position 클래스에 소속된 멤버 x를 의미합니다. 어쨌든 중요한 것은 생성자의 형식 인수와 멤버 변수의 이름이 구분되도록 하는 것입니다. 이외에 this라는 특별한 포인터를 사용하는 방법도 있지만 뒷쪽에서 포스팅 하겠습니다.
::생성자 오버로딩
특수한 면이 있지만 생성자도 함수의 일종입니다. 그러무로 오버로딩이 가능합니다. 디폴트 인수를 사용할 수도 있고 인라인으로 선언할 수도 있습니다. 개게를 초기화하는 방법이 여러가지존재할 경우 원하는 만큼 생성자를 복수 개 정의할 수 있으며 객체를 선언할 때 초기화 방법을 선택할 수 있습니다. 물론 이 경우 인수의 개수나 타입이 달라야 하는 오버로팅 규칙을 만족하여야합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include<iostream> #include<time.h> #include<Windows.h> void gotoxy(int x, int y) { COORD CursorPosition = { x, y }; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), CursorPosition); } class Position { private: int x; int y; char ch; public: Position(char ach) { x = rand() % 80; y = rand() % 24; ch = ach; } Position(int ax, int ay, char ach = 'S') { x = ax; y = ay; ch = ach; } void OutPosition() { gotoxy(x, y); putchar(ch); } }; void main() { srand(time(NULL)); Position Posit(30, 20, 'A'); Position Posit_2(40, 5); Position Posit_3('K'); Posit.OutPosition(); Posit_2.OutPosition(); Posit_3.OutPosition(); } | cs |
이 소스의 Position 클래스는 두 개의 생성자를 정의하고 있습니다. Position(char)생성자는 ch에 대한 초기값만 전달받으며 좌표는 난수로 선택하도록 하고 Position(int,int,char)생성자는 세 개의 인수를 전달받아 모든 멤버를 초기화 하되 마지막 인수에는 디폴트 값'S'를 적용합니다. 오버로딩된 함수는 호출부의 인수 목록으로 호출할 함수가 선택되는데 생성자도 마찬가지입니다. 객체를 선언할 때 어떤 인수가 전달되었는가에 따라 적절한 생성자가 선택됩니다. main에서 세 개의 Position객체를 생성하는데 각각 어떤 생성자에 의해 초기화 되는지 보면 됩니다. 컴파일러는 객체 선언문의 인수 목록을 보고 호출할 생성자를 결정하는데 만약 해당되는 생성자가 없을 경우는 에러로 처리됩니다. Position A 선언문의 경우 인수를 취하지 않는 Position()생성자를 호출하는데 이런 원형을 가지는 생성자가 정의되어 있지 않으므로 컴파일러는 A 객체를 생성할 수 없습니다. Position("문자열");선언문도 문자열을 받아들이는 생성자가 없기 떄문에 에러가 나게됩니다. 그러나 Position C(12.34,23,45);호출문은 산술 변환 규칙에 의해 Position(int,int,char);와 호환되므로 가능합니다.
'Programming > Cplusplus' 카테고리의 다른 글
C++ - 클래스 생성자/파괴자(1/3) (1) | 2015.08.30 |
---|---|
C++ - 파괴자(Destructor) (0) | 2015.08.30 |
C++ - 클래스(Class)(2/2) (0) | 2015.08.28 |
C++ - 클래스(Class)(1/2) (0) | 2015.08.28 |
C++ - 구조체의 확장 (0) | 2015.08.27 |