chapter 8 상속

박준우·2025년 3월 15일

명품C++프로그래밍

목록 보기
8/10

1. 상속이란?

캡슐화를 위해 사용된다. 캡슐화된 자식 클래스들은 상속된 부모클래스의 객체변수, 함수 등을 사용할 수 있으며, 이에 따라 코드를 Tree형식으로 만드는 것을 의미한다.

이에 따라 코드의 중복을 피하고, 관리의 효용성, 보안 등의 효과를 얻을 수 있다.

2. 상속 사용법

class Point {
	int x, y;
public:
	void set(int x, int y) { this =>x; this->y= y;}
    void showPoint(){
    	cout << "(" << x <<"," <<y << ")" << endl;
    }    
}

class ColorPoint : public 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); // Point의 set함수를 사용가능
    cp.setColor("Red"); // ColorPoint의 함수를 사용하였음
    cp.showColorPoint(); // 
}    

접근 지정자 사용과 주의할 점

Point의 x,y는 private(defalt)이기에, x,y가 colorPoint자식객체에 그대로 존재함에도 불구하고, showColorPoint -> public된 showPoint로만 x,y를 출력할 수 있다.

3. 상속과 객체 포인터

(1) 업캐스팅

업캐스팅이란? 자식클래스의 객체를 부모클래스의 포인터로 가리키는 것을 의미한다.

int main(){
	ColorPoint cp;
    ColorPoint *pDer = &cp; //자식클래스 cp객체주소를 pder 포인터로 입력
    Point *pBase = pDer;  // 부모클래스 타입으로 pder을 업캐스팅

업캐스팅이 완료된 객체는 부모클래스타입이 되었기에, 자식의 맴버들에 접근할 수 없다.

(2)다운 캐스팅

다운캐스팅이란? 부모클래스의 객체를 자식클래스의 포인터로 가리키는 것을 의미한다.

int main(){
	ColorPoint cp;
    ColorPoint *pDer = &cp; 
    Point *pBase = pDer;  // 업캐스팅 
	
    pDer = (ColorPoint*)pBase; //다운 캐스팅(명시적 선언이 필수)
  
    }

4. 접근지정자 지정

protect로 맴버 변수를 지정하면, 상속받은 클래스만 이 맴버를 접근할 수 있다.
그런데 상속받은 클래스에 선언한 public, protect, private 표기는 뭘까?

이는 상속을 받은 부모의 맴버를 대상으로, 추가로 접근을 지정하는 것으로,
만약, public으로 부모의 맴버를 선언했음에도, 상속시 상속접근지정자에 protect처럼 상위의 Lock을 건다면, 자식 클래스에서 접근지정자 Lock단계를 상향시킨다.

5. 상속과 생성자, 소멸자

자식클래스의 객체가 생성될 때, 부모의 생성자와, 자식의 생성자 모두 실행된다.
이 때 부모의 생성자가 먼저 실행된다. 호출은 자식-> 부모로 이어지지만, 실행은 부모->자식으로 실행되기 때문이다.

소멸자는 마찬가지로, 스택에 비워지는 순으로 자식부터 삭제된다.

주의사항

상속된 생성자에서 부모의 생성자 부터 출력을 시작하지만, 따로 명시하지 않는다면 기본생성자(매개변수없는)를 생성, 실행한다. 따라서, 부모의 특정생성자를 선택해 실행하고 싶다면 이를 명시해야한다.

class A{
public:
	A() {cout << "A기본생성자를 선택" << endl}
	B(int x) {cout <<"A매개변수생성자 A를 선택" << x <<  endl;};
};

class B :public A{
public:
	B() {cout << "B기본생성자를 선택" << endl}    
	B(int x) : A(x+3){ //A의 매개변수생성자를 선택하도록 지정
		cout << "N매개변수생성자선택" << x <<endl;
	}    
};

main(){
	B b(5);
    }

결과: 8, 5

6. 다중 상속과 가상 상속

다중상속

상속은 여러개를 지원한다.

class A{
protected:
	int add(int a, int b) {return a+b;}
};

class B{
protected:
	int minus(int a, int b) {return a-b;}
};    

class Calculater : public A, public B{
public:
	int calc(char op, int a, int b);
};

int Calculator::calc(char op, int a, int b){ // 클래스 A, B도 같이 생성자실행
	int res =0;
    switch(op){
    	case '+' : res = add(a,b); break;
		case '-' : res = minus(a,b); break;
    return res;
}

int main(){
	Calculator K
    cout "2+4=" << K.calc('+', 2, 4) << endl;
	cout "100-8=" << K.calc('-', 100, 8) << endl;
}   

가상상속

이런 다중 상속에는 문제가 있는데, root 클래스가 1개고, 이를 상속받는 branch가 2개, 이를 호출하는 leaf가 1개인 다이아몬드 모양 Tree가 존재한다고 하자.
이때, Leaf 클래스에는 branch에서 각각 호출한 root의 맴버가 중복상속된다.

이를 해결하기 위한 것이 Virtual 상속(가상상속)이다.

class branchA : virtual public root{};
class branchB : virtual public root{};

virtual은 부모클래스의 맴버를 자식 메모리스택에 넣을 때, 부모맴버 공간은 1번만 할당하도록 지시하는 명령어이다.

profile
DB가 좋아요

0개의 댓글