아래 코드를 보면 클래스 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번 방법이 더 간단하겠죠? ^^