# 상속 (Inheritance)
# 오버로딩(Overloading)과 오버라이딩(Overriding)
# 가상함수, 순수가상함수 (Virtual Function, Pure Virtual Function)
# 멤버이니셜라이저 (Memeber Initializer)
#멤버 이니셜라이저(Member Initializer)
여기에 한 코드가 있다.
#include <iostream> int main() { int num1 = 10; int num2(20); std::cout << "num1 : " << num1 << std::endl; std::cout << "num2 : " << num2 << std::endl; return 0; } </span>
출력 결과는?
6행에서 num2(20) 을 했다.
신기하게 생겼다. 하지만 그냥 간단하게 생각하면
'num2를 20으로 초기화'
라는 뜻이다.
이번엔 다른 코드를 한번 보자
#include <iostream> class A { public: A() { a = 1; b = 1; } private: const int a; const int b; }; int main() { A a; return 0; } </span>
이 코드는 컴파일이 되는가?
컴파일 에러!
이유는 무엇일까?
바로 const인 int형 a의 값을 1로 바꾸려했기 때문이다.
이걸 그럼 어떻게 초기화를 할까?
바로 멤버 이니셜라이저를 사용하면된다
개선된 코드를 보겠습니다.
#include <iostream> class A { public: A() : a(1), b(1) { std::cout << a << std::endl; std::cout << b << std::endl; } private: const int a; const int b; }; int main() { A a; return 0; }
6행을 주목하면된다!
6행에서 A클래스의 기본 생성자로 const인 int형 값들을 초기화 했다.!
컴파일 에러는 먹지 않는다.
출력결과를 본다면
이제 풀이를 하자면
아까
int num2(20);
구문이 생각 난다면 쉬울것이다.
말로 풀어서 설명을하면,
'num2'를 '20'으로 초기화
멤버 이니셜라이저도 마찬가지이다
A() : a(1), b(1)
{
}
a를 1로 초기화, b를 1로 초기화
여기서 알아야할 점이 또 하나있다.
바로 선언 순서대로 초기화가 진행된다는 점이다.
코드를 보겠습니다.
#include <iostream> class A { public: A(int a, int b) : y(b), x(y) { } const int x; const int y; }; int main() { A a(3, 3); std::cout << "a.x = " << a.x << std::endl; std::cout << "a.y = " << a.y << std::endl; return 0; }
코드를 해석하자면,
const int x;
const int y;
1. x가 y보다 먼저 선언이 되었으므로 먼저 초기화가 진행이 된다.
2. x(y) => x를 y로 초기화
y가 무엇인지 모르므로 x가 쓰레기값으로 초기화
3. y(b) => y를 b로 초기화
b가 3으로 들어왔으므로 y가 b로 초기화
4. main()에서의 출력값
x에 쓰레기값으로 초기화가 되어 정상적으로 출력되지않는다.
이 예제를 통해서
변수의 선언 순서에따라 멤버이니셜라이저의 순서가 결정된다는것을 알았다.
마지막으로 알아야할 점이있습니다.
참고 : http://insidecoding.blogspot.kr/2015/04/member-initialiser.html
바로, 상속관계에서 생성자의 호출 순서가 부모->자식 순서로 된다고 말씀드렸었는데요
더 깊게 들어가자면, 순서는 이렇습니다.
1. 자식의 생성자 호출
2. 기계어가, 자식생성자에 부모의 생성자를 멤버 이니셜라이저 과정을 코드에 삽입
3 부모의 생성자 호출
4. 자식 생성자 멤버 이니셜라이저
코드를 먼저 보겠습니다.
#include <iostream> class Point { public: Point(int _x, int _y) : x(_x), y(_y) { std::cout << "부모" << std::endl; } private: const int x; const int y; }; class Point3D : public Point { public: int z; Point3D(int a, int b , int c) : Point(a, b), z(c){ std::cout << "자식" << std::endl; } }; int main() { Point3D p3d(1,2,3); }
4. Point(a, b) => Point를 a, b로 초기화
5. Point(int _x, int _y) : x(_x), y(_y)
{
std::cout << "부모" << std::endl;
}
부모의 생성자 호출, 부모의 생성자 초기화완료 => 콘솔창에 "부모" 출력
6. Point3D(int a, int b, int c) : Point(a, b), z(c)
이렇게 진행이되는데요
출력결과를 보겠습니다.
저도 처음에는 막연히 부모 -> 자식 순서로 된다고 알고있었는데
신기하네요
정리하자면
1. 멤버 이니셜라이저를 통해 const를 초기화할 수 있다.
2. 멤버 이니셜라이저는 변수 선언 순서대로 진행된다.
3. 생성자는 알고보면, 자식생성자에서 부모생성자를 호출하는것이다.
[알게된점]
1. 생성자 호출과정의 심화
2. 상수초기화
많이 쓰인다고 하는데 저는 아직 많이 안써봐서 익숙치가 않네요
차차 쓰면서 익혀둬야겠습니다.
잘못된 부분이 있다면 지적해주시면 감사하겠습니다!
'복습 > C++' 카테고리의 다른 글
[C++] 복습일지 c++ 파일분할 (2) | 2018.01.25 |
---|---|
[C++] 복습일지 inline함수 그리고 virtual (0) | 2018.01.24 |
[C++] 복습일지 part 2 - 3 #가상함수, 순수가상함수 (0) | 2018.01.14 |
[C++] 복습일지 part 2 - 2 #오버로딩(Overloading)과 오버라이딩(Overriding) (0) | 2018.01.14 |
[C++] 복습일지 part 2 - 1 #상속(Inheritance) (0) | 2018.01.14 |