private 접근 지정자 활용하기
// Dog.h //
// 비어있는 클래스
class Dog {...}
// main.cpp //
#include "Dog.h"
int main()
{
Dog dog1;
Dog dog2(dog1); // 기본 복사 생성자 호출
dog1 = dog2; // 기본 복사 대입 연산자 호출
return 0;
}
사용자가 복사 생성자와 복사 대입 연산자를 따로 정의하지않으면
컴파일러가 자동으로 생성해주기 때문에 호출할 수 있게 됩니다.
이를 막고 싶을 때 함수의 접근 지정자 private을 활용합니다.
// Dog.h //
class Dog
{
public:
{...}
private:
Dog(const CDog&); // 선언만 한다.
Dog& operator = (const Dog&); // 선언 시 매개변수의 이름은 없어도 된다.
};
// main.cpp //
#include "Dog.h"
int main()
{
Dog dog1;
// CDog dog2(dog1); // 컴파일 에러 발생 !!
// dog1 = dog2; // 컴파일 에러 발생 !!
return 0;
}
복사 생성자와 복사 대입 연산자가 외부에서 호출되는 것을 막을 수 있게 되었습니다.
// Dog.h //
class Dog
{
// friend 지정
private:
friend class Friend;
public:
{...}
private:
Dog& operator = (const CDog&);
private:
void Func()
{
CDog dog1;
CDog dog2;
dog2 = dog1; // 컴파일 허용
}
};
// Friend.h //
#include "Dog.h"
class Friend
{
private:
void Func()
{
Dog dog1;
Dog dog2;
dog2 = dog1; // 컴파일 허용
}
};
하지만 friend 함수로 인해 확실하게 막을 수 없게 되었네요.
이럴 땐 별도의 파생 클래스를 생성해서 확실하게 막을 수 있습니다.
// Dog.h //
class Uncopyable
{
// 파생된 객체의 생성과 소멸을 허용한다.
protected:
Uncopyable()
{
}
~Uncopyable()
{
}
private:
// 하지만 복사 대입 연산자를 방지한다.
Uncopyable& operator = (const Uncopyable&);
};
// 별도로 생성한 파생 클래스로부터 private 상속
class Dog : private Uncopyable
{
private:
friend class Friend;
public:
{...}
private:
// 복사 대입 연산자를 파생된 클래스에 선언한다.
// Dog& operator = (const Dog&);
private:
void Func()
{
Dog dog1;
Dog dog2;
// dog2 = dog1; // 컴파일 에러 발생 !!
}
};
// Friend.h //
#include "Dog.h"
class Friend
{
private:
void Func()
{
Dog dog1;
Dog dog2;
// dog2 = dog1; // 컴파일 에러 발생 !!
}
};
확실하게 복사 대입 연산자가 외부에서 호출 되는 것을 막을 수 있게 되었습니다.
실제로 이와 같은 방법을 제공하는 부스트 라이브러리의 noncopyable 클래스가 존재한다는군요.
'Effective C++ 정리' 카테고리의 다른 글
08. 소멸자와 예외 처리 (0) | 2020.01.03 |
---|---|
07. 다형성을 가진 기본 클래스 소멸자는 반드시 가상 소멸자로 선언하자 (0) | 2019.12.29 |
05. 컴파일러가 자동으로 생성하는 함수 (0) | 2019.12.20 |
04. 멤버 초기화 리스트 (0) | 2019.12.15 |
03. const 키워드 (0) | 2019.12.14 |