본문 바로가기

[C++] 클래스 상속(inheritance)

Kwonriver 2022. 1. 1.
728x90

상속

Super, Delived, Base, Child, 부모클래스, 자식클래스 등으로 불리는 기능들을 의미한다.

클래스 선언부에 : 를 이용하여 상속을 알린다.

자식클래스는 부모클래스를 상속받아 부모클래스의 멤버변수, 멤버함수를 사용할 수 있는 권한을 가진다.

이 권한은 private, protected, public 에 따라 사용할 수 있는 권한이 다르다.

class Car
{
private:
	int lotNumber;
protected:
	int Price;

	int GetLotNumber();
};

int Car::GetLotNumber()
{
	return lotNumber;
}

class SportCar : public Car
{
public:
	void ShowCarPrice();
	void ShowLotNumber();
};

void SportCar::ShowCarPrice()
{
	std::cout << Price << std::endl;
}

void SportCar::ShowLotNumber()
{
	std::cout << GetLotNumber() << std::endl;
}

위는 Car를 public 상속을 받아 SportCar Class를 생성한 내용이다.

부모클래스의 private에 있는 멤버변수, 함수들은 상속받아도 직접 접근이 불가능하여 GetLotNumber라는 protected함수를 생성하여 접근하였다.

protected는 자식이 접근할 수 있으나 클래스 외부에서는 직접 접근이 불가능하다.

 

클래스의 생성자

자식클래스의 생성자가 호출되는 도중 부모클래스의 생성자가 자동으로 호출된다.

class Car
{
private:
	int lotNumber;
public:
	Car();
};

Car::Car()
{
	std::cout << "Car 생성자 호출" << std::endl;
}

class SportCar : public Car
{
public:
	SportCar();
};

SportCar::SportCar()
{
	std::cout << "SportCar 생성자 호출" << std::endl;
}

int main()
{
	// 자식클래스의 생성자 호출
	SportCar myCar;
}

부모클래스의 생성자는 자식클래스보다 항상 먼저 실행된다.

위 코드의 실행 결과

이렇기 때문에 자식클래스 생성자 호출 시 반드시 부모클래스가 호출할 수 있는 생성자가 존재해야 한다.

class Car
{
private:
	int lotNumber;
public:
	Car(int Number) : lotNumber(0)
	{
		std::cout << "Car 생성자 호출" << "Number : " << Number << std::endl;
	}
};

class SportCar : public Car
{
public:
	SportCar(int number);
};

SportCar::SportCar(int number)
{
	std::cout << "SportCar 생성자 호출" << std::endl;
}

위 코드는 SportCar의 생성자 부분에서 컴파일 에러가 발생한다.

{ 부분에 빨간 줄 발생

 

class Car
{
private:
	int lotNumber;
public:
	Car() : lotNumber(0) { std::cout << "Car 디폴트 생성자 호출" << std::endl; }
	Car(int Number) : lotNumber(0)
	{
		std::cout << "Car 생성자 호출" << "Number : " << Number << std::endl;
	}
};

class SportCar : public Car
{
public:
	SportCar(int number);
};

SportCar::SportCar(int number)
{
	std::cout << "SportCar 생성자 호출 " << "Number : " << number << std::endl;
}

디폴트 생성자를 추가하여 에러를 없앴다.

실행 시 자동으로 기본 생성자가 호출된 모습

 

상속을 하면 무엇이 좋을까?

수 많은 데이터를 처리할 때 각각의 변수가 모두 다른 형태이면 묶어서 처리하기가 힘들다.

위 예제로 예를 들어 Sport Car 클래스 뿐만 아니라 PickUpTruck, Sedan, SUV, Bus 등등 무수히 많은 종류가 생겼을 때 각각의 클래스를 배열로 따로 지정해야 한다.

그러나 Car를 상속받아 만들면 Car 클래스에 저장이 가능해진다.

 

class Car
{
private:
	int lotNumber;
public:
	Car() : lotNumber(0) { std::cout << "Car 디폴트 생성자 호출" << std::endl; }
	Car(int Number) : lotNumber(0)
	{
		std::cout << "Car 생성자 호출" << "Number : " << Number << std::endl;
	}
};

class SportCar : public Car
{
public:
	SportCar(int number);
};

class SUV : public Car
{
public:
	SUV(int number);
};

class Bus : public Car
{
public:
	Bus(int number);
};

SportCar::SportCar(int number)
{
	std::cout << "SportCar 생성자 호출 " << "Number : " << number << std::endl;
}

SUV::SUV(int number)
{
	std::cout << "SUV 생성자 호출 " << "Number : " << number << std::endl;
}

Bus::Bus(int number)
{
	std::cout << "BUS 생성자 호출 " << "Number : " << number << std::endl;
}

int main()
{
	// 자식클래스의 생성자 호출
	Car* pArrMyCars[10] = { 0, };
	pArrMyCars[0] = new SUV(0);
	pArrMyCars[1] = new Bus(1);
	pArrMyCars[2] = new SportCar(2);
	pArrMyCars[3] = new Car(3);

	for (int i = 0; i < 10; i++)
	{
		if (pArrMyCars[i] == NULL)
			continue;

		delete pArrMyCars[i];
	}
}

Car* 배열 안에 Car를 상속받아 만든 클래스들을 모두 넣을 수 있다. 

728x90