● 파생 클래스와 기본 클래스의 생성자 호출 및 실행


Q1)  파생 클래스의 객체가 생성될 때, 파생 클래스의 생성자와 기본 클래스의 생성자가 모두 실행되는가?


-> 둘 다 실행된다. 파생 클래스, 기본 클래스 모두 각각의 멤버 초기화나 필요한 초기화를 각각 수행한다.


Q2) 파생 클래스의 생성자와 기본 클래스의 생성자 중에서 누가 먼저 실행되는가?


-> 기본 클래스의 생성자가 먼저 실행된다.



다음을 보자.


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
#include <iostream>
using namespace std;
 
class  A {
public:
    A() { cout << "생성자 A" << endl; }
    ~A() {cout << "소멸자 A" << endl; }
};
 
class  B : public A {
public:
    B() { cout << "생성자 B" << endl; }
    ~ B() {cout << "소멸자 B" << endl; }
};
 
class  C : public B {
public:
    C() { cout << "생성자 C" << endl; }
    ~ C() { cout << "소멸자 C" << endl; }
};
 
int main() {
    C c; // 객체 c 생성
    return 0// 객체 c 소멸
 
cs



C c; 

에서 파생 클래스의 생성자가 먼저 호출되지만, 결국 기본 클래스의 생성자가 먼저 실행되고 나서야 파생 클래스의 생성자가 실행된다.


why? : 파생 클래스의 생성자에서 기본 클래스의 생성자를 호출할 때 인자 값을 전달해야 하기 때문이다.



● 소멸자의 실행 순서


: 생성자의 실행 순서와 반대로 실행된다. 


why? : 파생 클래스의 소멸자 코드를 실행한 후 기본 클래스의 소멸자를 호출하도록 컴파일 하기 때문이다.




● 파생 클래스에서 기본 클래스 생성자 호출


파생 클래스를 작성하는 개발자는 함께 실행할 기본 클래스의 생성자를 지정하여야 한다.

하지 않을 경우, 묵시적으로 기본 클래스의 기본 생성자가 실행되도록 컴파일한다.


※ 만일 기본 생성자가 선언되어 있지 않으면 '사용할 수 있는 적절한 기본 생성자가 없습니다. ' 라는 오류를 발생시킨다.




아래는 명시적으로 생성하는 경우의 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
 
class  A {
public:
    A() { cout << "생성자 A" << endl; }
    A(int x) {
        cout << "매개변수생성자 A" << x << endl
    }
};
 
class  B : public A {
public:
    B() { // A() 호출하도록 컴파일됨
        cout << "생성자 B" << endl;
    }
    B(int x) : A(x+3) {
        cout << "매개변수생성자 B" << x << endl;
    }
};
 
int main() {
    B b(5);
}
cs



명시적으로 기본 생성자 호출 코드를 작성하지 않는 경우 컴파일러가 다음과 같이 기본 생성자 호출 코드를 삽입한다.


1
2
3
4
5
6
7
8
class B {
    B() : A() {
        cout << "생성자 B" << endl;
    }
    B(int x) : A() {
        cout << "매개변수생성자 b" << x << endl;
    }
};
cs


'C++ > C++ 문법' 카테고리의 다른 글

#09 - 1 가상함수와 추상 클래스  (1) 2018.10.08
#8-5 가상 상속  (0) 2018.10.07
#8-2 상속과 객체 포인터  (0) 2018.10.07
#8-1 상속  (0) 2018.10.07
#7-B 연산자 중복  (0) 2018.10.07

● 상속과 객체 포인터


업 캐스팅기본 클래스의 포인터 -> 파생 클래스의 객체

클래스 객체를 파생 클래스로 변환하는것



=> 파생 클래스의 객체를 기본 클래스의 객체처럼 다룰 수 있게 한다.


1
2
3
4
5
6
7
8
9
10
11
12
int main() {
    ColorPoint cp;
    ColorPoint *pDer = &cp;
    Point* pBase = pDer; // up-casting
    
    pDer->set(34);
    pBase->showPoint();
    pDer->setColor("Red");
    pDer->showColorPoint();
 
    pBase->showColorPoint(); // 컴파일 오류
}
cs


위에서 showColorPoint()는 부모 클래스인 Point의 멤버가 아니므로 오류가 난다.

-> pBase로는 ColorPoint클래스 중 Point에서 상속 받은 멤버에만 접근이 가능하다.



up-casting 시 다음과 같은 명시적 타입 변환이 필요 없다.


1
Point* pBase = (Point*)pDer; // (Point*) 생략이 
cs


( 왜냐하면 cp객체는 ColorPoint 타입이지만 Point 타입이기도 하기 때문이다. )




다운 캐스팅  :  파생 클래스의 포인터 -> 기본 클래스 포인터가 가리키는 객체

클래스 객체를 기반 클래스로 변환하는것


1
2
3
4
5
6
7
8
9
10
11
12
int main() {
    ColorPoint cp;
    ColorPoint *pDer;
    Point* pBase = &cp;
 
    pBase->set(34);
    pBase->showPoint();
 
    pDer = (ColorPoint*)pBase; // down-casting
    pDer->setColor("Red"); // 정상 컴파일
    pDer->setColorPoint();
}
cs


실행 결과 : 

(3,4)

Red(3,4)


※ down-casting은 명시적으로 타입 변환을 지정해야 한다.



※ down-casting 주의사항


1
2
3
4
5
6
7
8
9
ColorPoint *pDer;
Point *pBase, po;
pBase = &po;
pDer = (ColorPoint*)pBase; // 다운 캐스팅
 
pDer->set(34);
pDer->setColor("Red"); /*setColor는 ColorPoin의 멤버이므로
                       컴파일 오류는 없으나 실행 중 오류가 생김*/
 
cs


=> pDer은 ColorPoint 타입의 포인터이므로 setColor()함수를 호출하는 데에는 문법적인 오류가 없다.

but 이 라인이 실행되면 pDer이 가리키는 객체 공간에는 setColor() 함수가 없기 때문실행중에 오류가 발생하여 비정상 종료한다.

'C++ > C++ 문법' 카테고리의 다른 글

#8-5 가상 상속  (0) 2018.10.07
#8-3 상속과 생성자, 소멸자  (0) 2018.10.07
#8-1 상속  (0) 2018.10.07
#7-B 연산자 중복  (0) 2018.10.07
#07-A 프렌드  (0) 2018.10.05

● 상속 선언



< 예시 : Point 클래스를 상속받는 ColorPoint 클래스 만들기 >


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
#include <iostream>
#include <string>
using namespace std;
 
class Point { // 2차원 평면에서 한 점을 표현하는 클래스 Point 선언
    int x, y; //한 점 (x,y) 좌표값
public:
    void set(int x, int y) { this->= x; this->= y; }
    void showPoint() {
        cout << "(" << x << "," << y << ")" << endl;
    }
};
 
class ColorPoint : public Point { // 2차원 평면에서 컬러 점을 표현하는 클래스 ColorPoint. Point를 상속받음
    string color;// 점의 색 표현
public:
    void setColor(string color)  {    this->color = color; }
    void showColorPoint();
};
 
void ColorPoint::showColorPoint() {
    cout << color << ":";
    showPoint(); // Point의 showPoint() 호출
}
 
int main() {
    Point p; // 기본 클래스의 객체 생성
    ColorPoint cp; // 파생 클래스의 객체 생성
    cp.set(3,4); // 기본 클래스의 멤버 호출
    cp.setColor("Red"); // 파생 클래스의 멤버 호출
    cp.showColorPoint(); // 파생 클래스의 멤버 호출
}
cs



※ parent 클래스는 public으로 하면 됨


=> 실행 결과


Red:(3,4)



※ 기본 클래스의 private 멤버의 접근


:   Parent class의 private 멤버는 Child class의 함수로는 접근할 수 없다! => Parent 클래스에서 상속받은 함수로만 간접적으로 접근 가능하다!



※ private 멤버는 해당 클래스 내의 멤버 함수들에게만 접근이 허용된다.

'C++ > C++ 문법' 카테고리의 다른 글

#8-3 상속과 생성자, 소멸자  (0) 2018.10.07
#8-2 상속과 객체 포인터  (0) 2018.10.07
#7-B 연산자 중복  (0) 2018.10.07
#07-A 프렌드  (0) 2018.10.05
#6 함수 중복과 static 멤버  (0) 2018.10.05