C++/Inheritance

C++ Inheritance

Soul-Learner 2016. 12. 24. 17:53

C++ 프로그래밍, 상속 ( Inheritance )

상속이란 이미 정의된 클래스로부터 접근 가능한 멤버들을 그대로 가져와서 새로운 클래스를 파생하는 것을 말한다. 예를 들어, 도형(Shape) 클래스가 있을 때 도형 클래스에는 모든 도형에 공통적으로 포함될 수 있는 속성과 함수가 정의되어 있다고 하자. 이어서 삼각형(Triangle) 클래스가 필요한 상황이 되었다면 삼각형 클래스를 처음부터 새로 작성하는 것보다는 도형 클래스를 기반으로 삼각형 클래스를 파생하는 것이 더 쉽고 간결한 표현이 가능하다. 왜냐면 삼각형도 도형이기 때문에(IS-A Relationship) 도형 클래스의 모든 멤버를 삼각형도 그대로 가져야 한다

상속은 기반 클래스(Base Class)로부터 파생 클래스(Derived Class)로 기반 클래스의 접근 가능한 멤버를 그대로 가져오는 것이므로 상속할 때는 최소 접근 레벨을 명시해야 한다. 다음과 같은 선언으로 상속을 설정할 수 있다


기반 클래스(Base Class) /  파생 클래스(Derived Class)의 다른 이름들

  • 기반 클래스 : 부모(Parent) 클래스, 상위(Super) 클래스, 
  • 파생 클래스 : 자식(Child) 클래스, 하위(Sub) 클래스


CShape 를 기반 클래스로 CTriangle 클래스를 파생하는 경우

class CTriangle : public CShape {  /*  상속된 멤버 외에 추가할 멤버 선언 */  }

위의 예에서 기반 클래스 CShape 왼쪽에 있는 접근 제한자(Access Specifier)는 최소 접근 레벌(Mininum Access Level)을 나타내며, public 외에 protected, private 등을 사용할 수 있다. 최소 접근 레벨이 public 이면 기반 클래스로부터 public 이상의 레벨이 적용된 멤버들만 상속의 대상이 된다. 예를 들어 최소 접근 레벨이 public이라면 상속의 대상은 protected, public 이 적용된 멤버들이다. protected도 포함되는 이유는 자식 클래스에서는 부모 클래스의 protected 멤버에도 접근이 가능하기 때문이다.


상속할 때 protected혹은 private 을 사용하면.....

class CCircle : protected CShape

위와 같이 상속할 때 접근제한자(Access Specifier)를 protected, private 등으로 설정하면 위에서 언급한 것과 같이 부모 클래스에서 상속할 멤버의 최소 접근 레벨을 의미하고 동시에 자식 클래스에 상속되는 멤버의 최대 접근 레벨이 된다. 그러므로 위와 같이 설정하면 CCircle 클래스에 상속되는 부모의 멤버는 모두 protected 로 선언된다. 만약 private 라면 동일한 원리로 상속된 모든 멤버는 자식 클래스에서 모두 private 으로 선언된다. private 으로 상속을 설정했다하더라도 부모의 private 멤버에는 접근하지 못하므로 private 멤버를 상속할 수는 없다

자식 클래스에서 추가되는 멤버는 작성자가 임의로 접근 제한자를 지정할 수 있다.


상속할 때 접근 제한자를 생략하면....

클래스를 상속할 때 접근 제한자를 생략하면 디폴트로 private 으로 설정되고, 구조체(struct)를 상속할 때 접근 제한자를 생략하면 디폴트로 public 으로 설정된다


상속되지 않는 것

생성자, 소멸자, friends 선언, operator=() 멤버


CShape클래스를 기반으로 CCircle, CTriangle 클래스를 파생하는 예

#include <iostream>
#include <locale>
#include <string>
#define _USE_MATH_DEFINES // C,C++ 표준에는 M_PI변수가 없다
// math.h 에는 다른 컴파일러에서 추가된 비표준 수학상수가 있는데 사용하려면 위처럼 선언해야 한다
#include <cmath>  // 원주율 M_PI와 제곱함수 pow()를 사용하기 위함

using namespace std;

class CShape
{
	protected:
	double width;
	double height;

	public:
	void set_width(double w) { width = w; }
	void set_height(double h) { height = h; }
};

class CCircle : public CShape // 최소접근레벨은 public, 자식은 protected에도 접근가능
{
	public:
	CCircle(double w, double h) {
		width = w;
		height = h;
	}

	double get_area() {
		return M_PI * pow(width/2, 2);
	}
};

class CTriangle : public CShape
{
	public:
	CTriangle(double w, double h) {
		width = w;
		height = h;
	}

	double get_area() {
		return width * height / 2;
	}
};

int main() {
	setlocale(LC_ALL, "");

	wcout << L"상속 (Inheritance)" << endl;

	CCircle circle(5,5);
	CTriangle tri(5,5);

	double circle_area = circle.get_area();
	double tri_area = tri.get_area();

	wcout << L"원의 면적=" << circle_area << endl;
	wcout << L"삼각형 면적=" << tri_area << endl;

	return 0;
}


상속과 생성자

생성자는 상속되지 않지만 자식 클래스의 객체가 생성될 때는 자식 클래스의 생성자에서 부모 클래스의 기본 생성자(Default Constructor)가 묵시적으로 호출된다. 이는 컴파일러에 의해 자식 클래스의 생성자에서 부모 클래스의 기본 생성자를 호출하도록 코드를 추가하기 때문이다. 결국 자식 클래스의 객체가 생성되기 전에 먼저 부모 클래스의 객체가 생성되도록 생성자가 연쇄적으로 호출되는 것이다.

상위 클래스의 생성자가 호출되도록 컴파일러가 코드를 추가할 때는 기본 생성자를 호출하도록 되어 있는데 필요하다면 작성자가 명시적으로 파라미터가 있는 다른 생성자를 호출하도록 변경할 수도 있다.


상위 클래스의 생성자를 명시적으로 호출하는 예

부모 클래스에 파라미터를 가진 생성자가 정의되어 있고 자식 클래스에서도 동일한 목적으로 생성자가 필요하다면 자식 클래스에서 부모 클래스의 생성자를 명시적으로 호출하도록 코드를 추가하면 된다

#include <iostream>
#include <locale>
#include <string>
#define _USE_MATH_DEFINES // C,C++ 표준에는 M_PI변수가 없다
// math.h 에는 다른 컴파일러에서 추가된 비표준 수학상수가 있는데 사용하려면 위처럼 선언해야 한다
#include <cmath>  // 원주율 M_PI와 제곱함수 pow()를 사용하기 위함

using namespace std;

class CShape
{
	protected:
	double width;
	double height;

	public:
	// 부모클래싀의 생성자
	CShape(double w, double h) {
		width = w;
		height = h;
	}

	void set_width(double w) { width = w; }
	void set_height(double h) { height = h; }
};

class CCircle : public CShape // 최소접근레벨은 public, 자식은 protected에도 접근가능
{
	public:
	CCircle(double w, double h) : CShape(w,h) // 상위 클래스의 파라미터 있는 생성자 호출
	{
		wprintf(L"CCircle 생성자 실행\n");
	}

	double get_area() {
		return M_PI * pow(width/2, 2);
	}
};

class CTriangle : public CShape
{
	public:
	CTriangle(double w, double h) : CShape(w,h) // 상위 클래스의 파라미터 있는 생성자 호출
	{
		wprintf(L"CTriangle 생성자 실행\n");
	}

	double get_area() {
		return width * height / 2;
	}
};

int main() {
	setlocale(LC_ALL, "");

	wcout << L"상속 (Inheritance)" << endl;

	CCircle circle(5,5);
	CTriangle tri(5,5);

	double circle_area = circle.get_area();
	double tri_area = tri.get_area();

	wcout << L"원의 면적=" << circle_area << endl;
	wcout << L"삼각형 면적=" << tri_area << endl;

	return 0;
}


다중상속(Multiple Inheritance)

C++ 언어에서는 자바언어와 달리 다중 상속이 허용된다. 다중 상속은 부모 클래스가 여러개 이므로 단순히 콤마(,)로 분리하여 다수개의 클래스를 선언해주면 된다. 예를 들어, 큐브(Cube)라는 입체도형 클래스 작성한다고 할 때, CShape 클래스아 C3DObject 라는 클래스를 동시에 상속해야 한다면 다음과 같이 선언하면 된다

class Cube : public CShape, public C3DObject