상세 컨텐츠

본문 제목

C++ [Has a] 관계

C++/C++98

by deulee 2023. 8. 7. 13:16

본문

대부분의 상속을 한다는 것은 클래스의 관계가 "IS A" 관계라는 것이다.

 

그렇다면 "HAS A" 관계는 어떨까?

 

#include <iostream>

class A {
private:
	int a;
public:
	A(int _a) : a(_a)
	{}
	void funcA()
	{
		std::cout << "A: " << a << std::endl;
	}
};

class B {
private:
	A a; // 포함 하고 있음.
	int b;
public:
	B(int _a, int _b) : a(_a), b(_b)
	{}
	void funcB()
	{
		a.funcA();
		std::cout << "B: " << b << std::endl;
	}
};

int main(void)
{
	B b(1, 2);
	b.funcB();
	return 0;
}

이렇게 상속을 하지 않음에도 불구하고 클래스 "B"는 클래스 "A"를 "포함"함으로써 클래스 "A"의 멤버를 사용할 수 있게 된다.

 

물론 public 멤버만 사용할 수 있지만 말이다.

 

초기화 하는 방법도 보면 멤버 초기화 리스트를 사용하여 해당 멤버 변수에 직접적으로 초기화 작업을 하는 것을 볼 수 있다. 이때, 멤버 객체에 직접 초기화 하는 것이기 때문에 "A(_a)" 식으로 클래스를 초기화해주면 안된다.

 

만약 초기화를 하지 않는다면 디폴트 생성자가 호출이 된다.

 

이런 식으로 굳이 상속을 하지 않더라도 클래스를 재활용하는 방법이 있다는 것을 기억해두자.


Private 상속

private 상속 또한 "Has a" 관계를 가지는 방법 중 하나이다.

 

이 전글에서도 한 번 언급한 적이 있지만 구체적으로 public 상속과 어떻게 다른지 확인해보도록 하겠다.

 

  • 포함 & private 상속
    • 객체의 구현만 재사용할 뿐 인터페이스는 상속받지 않는다.
  • public 상속
    • 객체의 구현뿐만 아니라 인터페이스까지도 같이 상속 받는다.

구현 상속이라는 말은 "객체의 구체적인 동작만 재사용할 수 있고 인터페이스는 물려받지 않는 상속이며 좀 더 구체적으로는 멤버 함수를 호출할 수는 있지만 스스로 멤버 함수를 가지지는 않는 상속"이다.

 

이 말이 무슨 말이냐 하면 다음과 같다.

 

포함과 private 상속은 스스로의 멤버 함수 내에서 포함하거나 상속 받은 멤버의 함수를 호출할 수 있지만, 외부에서 상속 받거나 포함한 객체의 멤버를 참조하거나 호출할 수 없다. (이를 구현만 상속 받고 인터페이스는 상속을 받지 못함이라고 한다.)

 

반대로 public 상속은 멤버 함수 내에서 상속 받는 멤버를 호출할 뿐만 아니라 외부에서도 상속받은 멤버 함수의 기능을 사용하거나 참조할 수 있다.

 

이 차이가 "Has a"와 "Is a" 관계를 나누는 차이라고 생각하면 된다.

 

정리하자면 다음과 같다.

기법 private 상속, 포함 public 상속 순수 가상 함수
인터페이스 상속 X O O
구현 상속 O O X

구현 상속은 단순히 어떤 객체를 재사용하기 위한 기법에 불과하다.

 

하지만 인터페이스 상속은 클래스간의 계층 관계를 이룸으로써 다형성을 구현할 수 있다는 점에서 단순한 재활용 이상의 의미를 가진다.

 

일단 상속받은 후 일부 함수의 동작을 재정의할 수도 있고 객체 타입에 따라 다른 동작을 하도록 만들 수도 있다. 객체 지향의 진정한 매력은 바로 다형성이다. 그리고 이를 위한 전제 조건이 public 상속이다.

 

이는 다음 장에서 상세하게 다루도록 하겠다.

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

C++ 가상 파괴자  (0) 2023.08.07
C++ 가상 함수  (0) 2023.08.07
C++ 다중 상속  (0) 2023.08.07
C++ 오버라이딩  (0) 2023.08.07
C++ 상속  (0) 2023.08.07

관련글 더보기