IT 프로그래밍/C++

[c++] 순수 가상 함수, 추상 기본 클래스, 인터페이스 클래스

기술1 2024. 5. 28. 14:56
반응형

순수 가상 함수

virtual void speak() const = 0;

 

부모 클래스에서 자식 클래스에 특정 함수를 만들고 싶을 때 이것을 쓰는 것입니다. 

 

그러면 만약에 speak()를 깜빡했을 때 오류가 뜨게 되는 것입니다. 이것이 바로 순수 가상 함수를 사용하는 이유입니다. 즉 자식 클래스가 깜빡할 경우를 대비해서 경고 표시를 만들어주는 것이라고 보면 됩니다. 

 

class를 설계할 때 구조를 도와주는 것이라고 보면 됩니다.

 

다이아몬드 상속문제

#include <iostream>
#include <string>
using namespace std;

class PoweredDevice
{
public:
	int m_i;

	PoweredDevice(int power)
	{
		cout << "PowerDevice: " << power << '\n';
	}
};

class Scanner : virtual public PoweredDevice
{
public:
	Scanner(int scanner, int power)
		: PoweredDevice(power)
	{
		cout << "Scanner : " << scanner << '\n';
	}
};

class Printer : virtual public PoweredDevice
{
public:
	Printer(int printer, int power)
		: PoweredDevice(power)
	{
		cout << "Printer : " << printer << '\n';
	}
};

class Copier : public Scanner, public Printer
{
public:
	Copier(int scanner, int printer, int power)
		: Scanner(scanner, power), Printer(printer, power),
		PoweredDevice(power)
	{
	}
};

int main()
{
	Copier cop(1, 2, 3);

	cout << &cop.Scanner::PoweredDevice::m_i << endl;
	cout << &cop.Printer::PoweredDevice::m_i << endl;

	return 0;
}

 

 

전체코드입니다.

class PoweredDevice
{
public:
	int m_i;

	PoweredDevice(int power)
	{
		cout << "PowerDevice: " << power << '\n';
	}
};

powerdevice 클래스는 m_i라는 멤버 변수를 가지고 있으며, 생성자에서 power값을 출력합니다.

 

class Scanner : virtual public PoweredDevice
{
public:
	Scanner(int scanner, int power)
		: PoweredDevice(power)
	{
		cout << "Scanner : " << scanner << '\n';
	}
};

scanner 클래스는 powerdevice 를 가상 상속합니다. 생성자에서 poweredDevice의 생성자를 호출하고 scanner의 값을 출력합니다. 

 

class Printer : virtual public PoweredDevice
{
public:
	Printer(int printer, int power)
		: PoweredDevice(power)
	{
		cout << "Printer : " << printer << '\n';
	}
};

printer 클래스도 poweredDevice를 가상 상속합니다. 생성자에서 PoweredDevice의 생성자를호출하고 printer의 값을 출력합니다. 

 

class Copier : public Scanner, public Printer
{
public:
	Copier(int scanner, int printer, int power)
		: Scanner(scanner, power), Printer(printer, power),
		PoweredDevice(power)
	{
	}
};

Copier 클래스는 Scanner와 Printer를 다중 상속 받습니다. 생성자에서는  Scanner와 Printer의 생성자를 호출하고 PoweredDevice 생성자를 명시적으로 호출합니다. 가상 상속 덕분에 PoweredDevice의 생성자는 한 번만 호출됩니다. 

 

int main()
{
	Copier cop(1, 2, 3);

	cout << &cop.Scanner::PoweredDevice::m_i << endl;
	cout << &cop.Printer::PoweredDevice::m_i << endl;

	return 0;
}

main 함수에서 Copier의 객체를 생성합니다. 이 과정에서 Scanner, Printer, 그리고 PoweredDevice의 생성자가 호출됩니다. PoweredDevice의 생성자는 가상 상속 덕분에 한 번만 호출됩니다. 

 

      PoweredDevice
         /    \
    Scanner   Printer
         \    /
        Copier

다이아몬드 상속 구조는 현재 이런 식으로 되어 있습니다. 

 

Scanner와 Printer가 각각 PoweredDevice를 상속받고, Copier가 이 둘을 상속받을 때, PoweredDevice의 인스턴스가 두 번 생성되는 문제가 발생할 수 있습니다. 

 

이를 해결하기 위해 Scanner와 Printer는 PoweredDevice를 가상 상속합니다. 이렇게 하면 Copier가 생성될 대 PoweredDevice의 인스턴스는 한 번만 생성됩니다. 

 

가상상속?

 

가상상속을 사용하면 최상위 클래스의 인스턴스가 중복 생성되지 않도록 보장합니다. Scanner와 Printer의 클래스에서 virtual키워드를 사용하여 PoweredDevice를 가상 상속하면, Copier클래스는 PoweredDevice의 인스턴스를 단 한 번만 생성성합니다. 

 

반응형