Notice
Recent Posts
Recent Comments
Link
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
관리 메뉴

로또

22. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자. 본문

책/Effective C++

22. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자.

아롱로또 2023. 11. 19. 10:44

다루는 내용

데이터 멤버를 private으로 두었을 때 장점을 통해 public이면 안 되는 이유를 알아보자.

 

private 데이터 멤버의 장점

1. 문법적 일관성

데이터 멤버가 public이 아니라면, 사용자가 객체에 접근할 수 있는 유일한 수단은 멤버 함수일 것이다.

어떤 클래스의 멤버에 접근하고 싶을 때, 괄호를 붙여야 하는지 아닌지를 고민할 필요가 사라진다.

 

2. 데이터 멤버의 접근성에 대한 제어

어떤 데이터 멤버를 public으로 내놨다면, 모두가 이 멤버에 대해 읽기 및 쓰기 권한을 가진다.

하지만 private으로 두고 해당 값을 읽고 쓰는 함수가 있다면 접근 불가, 읽기 전용, 읽기 쓰기 접근을 우리가 직접 구현할 수 있다.

class AccessLevels{
public:
    int GetReadOnly() const{ return read_only; }

    void SetReadWrite(int value){ read_write = value; }
    int GetReadWrite() const{ return read_write; }

    void SetWriteOnly(int value) { write_only = value; }
private:
    int no_access; // 접근 불가능한 변수.
    int read_only; // 읽기만 가능한 변수
    int read_write; // 읽고 쓰기가 가능한 변수
    int write_only; // 쓰기만 가능한 변수
};

이러한 접근 제어는 어떤 식으로든 외부에 노출시키면 안 되는 데이터 멤버들이 존재하므로 큰 중요성을 가진다.

 

3. 캡슐화

데이터 멤버를 private으로 선언하여 함수를 통해서만 접근 가능하도록 만들면, 데이터 멤버를 추후 계산식으로 대체할 수도 있을 것이고 사용자는 절대로 이 클래스를 넘보지 못한다.

// 자동차가 지나가는 속도를 모니터링하는 클래스
class SpeedDataCollection{
public:
    void AddValue(int speed); // 새로운 데이터를 추가한다.
    double GetAverage() const; // 평균 속도를 반환한다.
};

 

GetAverage 멤버 함수를 구현하는 방법에 대해 생각해보자.

첫 번째로, 현재의 평균값을 담는 데이터 멤버를 클래스 안에 넣어둘 수 있다. 때문에 함수는 호출될 때마다 단순히 멤버 변수를 반환하기만 하면 된다. 이러한 방법은 현재의 평균값, 누적 총합, 데이터의 개수 등이 데이터의 멤버로 추가되어야 하므로 객체 하나의 크기가 증가하겠지만, 효율 면에서 큰 이득을 가져올 수 있다.

 

두 번째 방법은 호출될 때마다 평균값을 계산하는 것이다. 이는 함수 자체의 속도는 느려지겠지만 첫 번째 방법과 달리 객체의 크기는 보다 작아질 것이다. 

 

이 중 정답은 없지만, 사용 가능한 메모리가 적고 평균값이 그다지 자주 쓰이지 않는 응용프로그램을 만드는 경우에는 두 번째 방법을, 속도가 중요하며 메모리가 넉넉하고 평균값을 자주 사용한다면 첫 번째 방법을 사용하는 것이 좋을 것이다.

 

중요한 것은 평균값 접근에 멤버 함수를 사용하게 한다는 것이다.

멤버 함수를 통하게 함으로써 평균값을 구하는 내부 구현을 여러 방법으로 바꿀 수 있게 된다. 구현이 변경되더라도 사용자 입장에서는 단순히 컴파일만 다시 하면 되는 것이다.

 

또한, 캡슐화는 현재의 구현을 나중에 바꾸기로 결정할 수 있는 권한을 예약하는 것과 같다. 

기존의 public 데이터 멤버를 제거하는 경우를 떠올려보자. 해당 데이터 멤버를 다루는 모든 사용자 코드는 망가질 것이다. 이는 protected 데이터 멤버라고 해도 동일한데, 해당 클래스를 기본 클래스로 사용하는 파생 클래스 또한 망가질 것이다.

private 데이터 멤버는 우리가 수정을 가해도 사용자는 컴파일만 하면 되는데, 그 외에는 큰 파장을 불러온다.

 

데이터 멤버를 함수 인터페이스 뒤에 감추는 것은 구현 상의 융통성을 전부 누릴 수 있다. 데이터 멤버를 읽거나 쓸 때, 다른 객체에 알림 메세지를 보낸다든지, 클래스의 불변속성 및 사전조건, 사후조건을 검증한다든지, 스레딩 환경에서 동기화를 건다든지 하는 일처럼 말이다.

 

이것만은 잊지 말자!

  • 데이터 멤버는 private 멤버로 선언하자. 이를 통해 클래스 제작자는 문법적으로 일관성 있는 데이터 접근 통로를 제공할 수 있고, 필요에 따라서는 세밀한 접근 제어도 가능하며, 클래스의 불변속성을 강화할 수 있을 뿐 아니라, 내부 구현의 융통성도 발휘할 수 있다.
  • protected는 public보다 더 많이 보호받고 있는 것이 절대로 아니다.