아래 코드를 보면 클래스 A의 foo()라는 함수는 private로 선언이 되어 있습니다.
class A { private: void foo(); }; class B : public A { public: void bar() { foo(); // 'A::foo' : cannot access private member declared in class 'A' } };
당연한 얘기이지만 본 foo()라는 함수는 class A 내부에서만 사용을 할 수가 있을 뿐, 그 상속 클래스(B)에서도 사용을 하지 못합니다. 원래 private라는 놈이 그런 이유로 만들어 진 거죠.
그런데 constructor와 destructor를 private로 선언하게 되면 조금 다른 역할까지 하게 됩니다.
class A { private: A(); virtual ~A(); }; class B : public A // 'A::A' : cannot access private member declared in class 'A' // 'A::~A' : cannot access private member declared in class 'A' { };
대부분의 OOP language에서는 constructor 및 destructor는 다음과 같아 호출이 되게 됩니다.
객체가 생성이 될 때에는 상위 클래스(A)에서부터 하위 클래스(B) 순으로 constructor가 불려 져야 한다.
객체가 해제가 될 때에는 하위 클래스(B)에서부터 상의 클래스(A) 순으로 destructor가 불려 져야 한다.
즉 하위 클래스에서는 반드시 상위 클래스의 constructor 및 destructor의 visibility가 반드시 보장되어야 합니다. 이것이 바로 일반 member function이랑 다른 점입니다. 상위 클래스에서 constructor 및 destructor를 private으로 선언을 하게 되면 하위 클래스에서는 상위 클래스의 constructor와 destructor의 접근권을 가지지 못하기 때문에 하위 클래스를 만들 수 없다는 결론을 도출할 수가 있습니다.
여기에서 재미있는 예외 상황을 보도록 하겠습니다. destructor를 빼고 constructor만 private으로 선언을 합니다.
class A { private: A(); }; static A* a = 0; class B : public A { public: B() : A(*a) {} };
A 클래스에서는 constructor를 private으로 선언해 주었음에도 불구하고 B 클래스는 A 클래스를 상속받을 수가 있게 되어 버립니다. 자세히 보면 B 클래스의 constructor에서는 A 클래스의 copy constructor를 호출하고 있는 것을 알 수가 있습니다. 즉 B 클래스의 constrcutor에서는 A 클래스의 nullary constructor는 호출을 못하지만, A 클래스의 copy constructor를 호출함으로 해서 constructor 호출을 대신하고 있음을 알 수 있습니다.
클래스 설계시에 nullary constructor(copy constructor 포함) 및 destructor는 명시를 하지 않으면 기본적으로 public입니다. non-nullary constructor는 명시하지 않으면 존재하지 않기 때문에 패스~~~.
결론적으로 상속을 막는 방법은 다음과 같이 결론지을 수 있습니다.
1. destructor를 private로 선언을 한다.
혹은
2. 모든 constructor(non-nullary, nullary, copy)를 private로 선언을 한다.
1번 방법이 더 간단하겠죠? ^^
답변 감사합니다.
인터넷을 검색해 보니 여러가지 방법이 있네요.
http://stackoverflow.com/questions/2184133/prevent-class-inheritance-in-c
[ps]
1. boost::noncopyable과 같이 상속을 금지하는 별도의 모듈을 만들어 보려고 했는데 잘 안되더군요.
2. constructor나 destructor를 private으로 선언을 하게 되면 클래스의 상속을 방지함과 동시에 instance를 직접 생성하지 못한다는 side effect도 생기므로, 이 경우 별도의 method를 통해서 객체의 생성이나 접근 방법을 제공해 줘야 합니다.
3. Delphi Pascal에서는 상위 클래스의 concstructor나 destructor를 explicit하게 호출해 주도록 코드를 작성해 줘야 합니다. 상위 클래스의 constructor or destructor가 implicit하게 호출되지 않습니다.