- 데이터 멤버는 private 멤버로 선언해라. 이를 통해 제작자는 문법적으로 일관성 있는 데이터 접근 통로를 제공할 수 있고, 필요에 따라서는 세밀한 접근 제어도 가능하며, 클래스의 불변속성을 강화할 수 있을 뿐 아니라, 내부 구현의 융통성도 발휘할 수 있다.
- protected는 public보다 더 많이 보호받고 있는 것이 아니다.
데이터 멤버는 private 영역에
데이터 멤버는 private 영역에 선언하는 것이 좋다.
이에 따른 이점을 살펴보자.
- 문법적 일관성
데이터 멤버가 public이라면, 사용자 쪽에서 어떤 객체를 접근할 수 있는 유일한 수단은 멤버 함수이다.
어떤 클래스에 공개 인터페이스가 전부 함수라면 클래스 멤버에 접근하고 싶을 때 괄호를 붙여야 하는지 여부를 일치시키기 쉽다. - 함수를 사용하여 데이터 멤버의 접근성 제어
데이터 멤버가 public이면 멤버에 대해 읽기, 쓰기 접근권한을 갖게 되지만 멤버를 모두 private으로 선언하고 함수를 통해서만 접근할 수 있게 된다.
class AccessLevels {
public:
...
int getReadOnly() const { return readOnly; }
void setReadWrite(int value) { readWrite = value; }
int getReadWrite() const { return readWrite; }
void setWriteOnly(int value) { writeOnly = value; }
private:
int noAccess;
int readOnly;
int readWrite;
int writeOnly;
};
세밀한 접근 제어는 캡슐화에 중요한 부분이다.
예를 들어, 자동화 장치를 사용해서 자동차가 지나가는 속도를 모니터링하는 프로그램을 만드는 상황이다.
프로그램이 실행되면, 자동차가 지나갈 때마다 속도를 계산한 후 데이터 집합에 추가한다.
class SpeedDataCollection {
...
public:
void addValue(int speed); // 데이터 추가
double averageSoFar() const; // 평균 속도 반환
...
};
averageSoFar 멤버 함수를 구현할 때, 지금까지 수집한 속도 데이터 전체의 평균값을 담는 어떤 데이터 멤버를 클래스에 넣어두는 방법이 있다. averageSoFar 함수는 호출될 때마다 그 데이터 멤버의 값을 반환하기만 하면 된다.
또 다른 방법으로는 호출될 때마다 평균값을 계산하는 방법이 있다.
첫 번째 방법을 사용하면, 객체 하나의 크기가 커진다. 평균값을 유지하기 위한 공간을 할당해야 하기 때문이다
크기가 커지기는 하지만 효율면에서는 나쁘지 않다.
두 번째 방법을 사용하면, 객체의 크기는 그대로이지만 속도가 느려진다.
사용환경에 따라 최적의 방법은 다르겠지만 중요한 포인트는 평균값에 접근하려면 멤버 함수를 통해서만 가능하게 하는 것이다. 이렇게 구현하면 내부 로직은 언제든지 변경할 수 있다.
- 불변속성 강화
데이터 멤버를 private로 선언하면(캡슐화) 클래스의 불변속성을 유지하기 쉬워진다.
불변속성을 보여줄 통로가 멤버 함수밖에 없다. 그뿐 아니라 캡슐화는 현재의 구현을 나중에 언제든지 바꿀 수 있는 권한을 갖게 되는 셈이다. 만약 public으로 되어있다면 이를 사용한 사용자들의 코드가 깨질 수 있기 때문에 쉽게 바꿀 수 없게 된다.
- 구현상 융통성
데이터 멤버를 읽거나 쓸 때 다른 객체에 알림 메시지를 보낸다든지, 클래스의 불변속성 및 사전조건, 사후조건을 검증하든지, 스레딩 환경에서 동기화를 건다든지하는 일을 간편히 할 수 있다.
public과 protected
protected 데이터 멤버의 경우도 public과 비슷하다.
문법적 일관성과 세밀한 접근 제어 부분에서는 public 데이터 멤버처럼 protected 데이터 멤버에도 그대로 적용된다.
또한, 캡슐화 부분에서도 똑같다.
어떤 것이 바뀌면 깨질 가능성을 가진 코드가 늘어날 때 캡슐화의 정도는 그에 반비례하여 작아진다.
어떤 클래스에 public 데이터 멤버가 있고, 이것을 제거한다고 가정해 보자.
이 멤버를 사용한 모든 코드는 망가질 것이다.
그렇다면 protected 데이터 멤버를 제거하면 이 멤버를 사용한 파생 클래스들이 망가질 것이다.
정도의 차이는 있을 수 있다. 하지만, 두 경우 모두 무수히 많은 문제를 발생시킬 것이다.
정리하자면, 데이터 멤버는 private에 선언하는 것이 좋고, 그 외에는 모두 비슷하다.