본문 바로가기

Effective C++/2. 생성자, 소멸자 및 대입 연산자

항목 6: 컴파일러가 만들어낸 함수가 필요없으면 확실히 이들의 사용을 금해 버리자.

부동산 거래 프로그램을 만든다. 그래서 class HomeforSale 만드는데, 부동산 중개 업자가 신신당부한 말이 있다. 모든 자산은 세상에 하나밖에 없다!!

 

그럼 HomeForSale 사본자체를 만들 없게 해야 한다. 그러다 보니 HomeForSale 객체를 복사하려 하면 컴파일 에러가 뜨게 하고 싶다.

 

 

일반적으로 어떤 클래스에서 특정한 종류의 기능을 지원하지 않았으면 하는 의도를 반영할려면, 그런 기능을 제공하는 함수를 선언하지 않으면 되는데, 복사 생성자와 복사 대입 연산자의 경우는 선언하지 않으면 컴파일러가 자동으로 선언해버리는게 문제다.

 

 

해결의 열쇠 : 기본 복사 생성자, 기본 복사 대입 연산자는 public member 선언된다!!

 

=> private으로 바꿔버리면 => 외부에서 호출 자체가 불가능, 하지만 내부에서는 호출 가능, friend 함수도 호출이 가능하다.

 

=> 그럼 private으로 선언하되, 정의를 하지 않으면? => 외부에서는 호출 자체가 불가능, 내부에서는 호출해봤자 undefined 에러

 

 

 

선언에서는 매개변수 이름도 필요없음(type identifier 컴파일러에게 알려주는 것이기 때문이다.)

 

방법에 유일한 단점이라면 내부 호출 undefined 에러는 링크 시점 에러라는 점이다. 에러는 syntax error 제일 좋다.

 

=> 복사 생성자와 복사 대입 연산자를 private 넣는건 동일, 이것을 HomeForSale 자체에 넣지 말고 base class 하나 만들어서 거기에 선언해놓고, HomeForSale 이를 상속받는 derived class 만들어 버리는 것이다.  base class 복사 방지만 맡는다는 특별한 의미를 부여한다.(이름을 uncopyable 등으로 지으면 좋겠다.)

 

 

이러면 HomeForSale 맴버함수나 friend 함수에서 copy 할려고 하면 HomeForSale에는 복사 생성자나 복사 대입 연산자가 없으니 기본 복사 생성자, 기본 복사 대입 연산자를 만들려고 탠데, 이때 컴파일러는 base class 대응 버전을 호출하게 되어있다.(항목 12에서 다룸)

 

 

public = 어디서든 접근이 가능.

protected = 상속관계일 때 접근이 가능

private = 해당 클래스에서만 접근이 가능

 

 

출처: <https://hwan-shell.tistory.com/25>

 

 

 

 

그러나 public이든 private이든 protected이든 derived class 맴버들은 base class private 맴버에 접근 자체가 불가능함 => 링크 시점 에러가 아닌, 컴파일 시점 에러가 난다.

 

 

 

 

몇가지 짚고 넘어가자면, public으로 상속받든 private으로 상속받든 상관없는데, 이러면 굳이 public보단 private 낫다.

 

또한 Uncopyable 소멸자는 가상 소멸자가 아니어도 된다.(항목 7 참조)

또한 Uncopyable 클래스는 데이터 맴버가 전혀 없기 때문에, 항목 39에서 공부 기본 클래스 최적화(empty base class optimization, EBO) 기법이 먹혀들 여지가 있는데, Uncopyable base class 기법을 사용하면 다중 상속으로 가능성이 있다.(항목 40 참조)

 

그럼 다중 상속일 때가 문제가 되는데, 때는 EBO 돌아가지 못할 때가 있다.(항목 39 참조). 근데 이런건 대충 무시하고 살아도 . 왠만하면 의도한대로 돌아가기 때문이다.

 

부스트 라이브러리(항목 55 참조) 보면 Uncopyable 똑같은 구실을 하는 클래스가 있음(noncopyable)

 

 

  • 컴파일러에서 자동으로 제공하는 기능을 하용치 않으려면, 대응되는 맴버 함수를 private으로 선언한 구현은 하지 않은 채로 두자. 또는 Uncopyable 비슷한 기본 클래스를 쓰는 것도 방법이다.(링크 타임 에러를 컴파일 타임 에러로 당기는 방법임)