C++ 디자인 패턴 :
protected constructor (protected생성자)
생성자의 정확한 호출 순서를 이해해야 한다.
1. Dog의 생성자가 먼저 호출된다. (Dog d; 에 의해 호출됨)
2. Dog의 생성자 안에서 기반 클래스인 Animal의 생성자를 호출한다.
class Animal
{
protected:
Animal() {}
};
class Dog : public Animal
{
public:
Dog() {} // Dog() : Animal() {}
};
int main()
{
Animal a; // error
Dog d; // ok.
}
생성자를 protected에 만드는 이유?
- 자기 자신(Animal)을 만들 수는 없다.
- 하지만 파생 클래스(Dog)의 객체는 만들 수 있다.
- 동물은 추상적 개념으로 객체가 존재할 수 없지만 강아지는 현실 세계에 객체가 존재하는 이치와 같다.
protected 소멸자
1. 객체를 스택에 만들 수 없게 할 때 주로 사용하는 기업
2. 객체를 힙에만 만들 수 있게 한다.
3. 참조 계수 기반의 객체 수명 관리 기법에서 주로 사용한다.
아래와 같이 protected 안에 ~Car() 소멸자를 만들면 아래와 같은 에러가 발생한다.
소멸자가 자동으로 호출되지만 protected에 의해 오류가 발생하는 것이다.
#include <iostream>
using namespace std;
class Car
{
public:
Car() {}
void Destroy() { delete this;}
protected:
~Car(){ cout << "~Car" << endl;}
};
int main()
{
Car c; // 스택에 객체를 만들수 없다.
}
에러 문구
main.cpp:16:9: error: ‘Car::~Car()’ is protected within this context
16 | Car c; // 스택에 객체를 만들수 없다.
| ^
main.cpp:11:5: note: declared protected here
11 | ~Car(){ cout << "~Car" << endl;}
| ^
그래서 Car를 포인터 형태 객체로 생성할 수 있다.
하지만 아래와 같이 delete p; 를 수행하면 역시나 에러가 발생한다.
소멸자가 역시나 protected 안에 존재하기 때문이다.
#include <iostream>
using namespace std;
class Car
{
public:
Car() {}
protected:
~Car(){ cout << "~Car" << endl;}
};
int main()
{
Car* p = new Car;
delete p;
}
역시 protected에 의해 에러가 발생한다.
그래서 아래와 같이
Destroy()를 만들어주고 멤버함수를 통해 p->Destroy(); 호출해주면 문제없이 컴파일이 되는 것을 볼 수 있다.
Destroy()는 자기 자신을 delete 하기 때문에 문제없이 protected 접근이 가능하고 잘 수행된다.
#include <iostream>
using namespace std;
class Car
{
public:
Car() {}
void Destroy() { delete this;}
protected:
~Car(){ cout << "~Car" << endl;}
};
int main()
{
Car* p = new Car;
p->Destroy();
}
자주 사용하는 기법은 아니지만 숙지할 것!
나중에 참조 계수 기반의 객체 수명 관리 기법 공부할 때 다시 한 번 숙지!
'C++' 카테고리의 다른 글
[C++] 디자인 패턴 : 변하는 것을 분리하는 방법 2가지 (0) | 2022.01.30 |
---|---|
[C++] 디자인패턴 : uscasting (0) | 2022.01.28 |
[C++] Design Patterns (디자인 패턴) - GoF (0) | 2022.01.26 |
[C++] exception (예외처리) (0) | 2022.01.10 |
[C++] cout, endl 원리, operator<< 재정의 (0) | 2022.01.02 |
댓글