[C++] 항목 22: 데이터 멤버가 선언될 곳은 private 영역임을 명심하자

업데이트:     Updated:

카테고리:

태그:

이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역

📦 4. 설계 및 선언

👉🏻 항목 22: 데이터 멤버가 선언될 곳은 private 영역임을 명심하자

데이터 멤버를 private에 두어야 하는 이유는 다음과 같다:

  • 문법적 일관성
  • 세밀한 접근 제어
  • 캡슐화(encapsulation)

✅ 문법적 일관성

  • 데이터 멤버가 private에만 존재한다면, 모든 접근은 반드시 public 멤버 함수를 통해서만 이루어진다.
  • 이로 인해 “직접 접근해야 할까, 함수로 접근해야 할까?” 하는 고민이 사라진다. → 접근 방식에 대한 일관성이 생긴다.

✅ 세밀한 접근 제어

데이터 멤버가 public에 선언되면:

class AccessLevels {
public:
	int value;
};
  • 외부 누구나 value에 대해 읽기와 쓰기 모두 가능하다.
  • → 접근 제어가 불가능하다.


하지만, 멤버를 private에 선언하고, 함수로 접근을 제어하면:

class AccessLevels {
public:
	int getReadOnly() const { return readOnly; }
	void setWriteOnly(int value) { writeOnly = value; }
	void setReadWrite(int value) { readWrite = value; }
	int getReadWrite() const { return readWrite; }

private:
	int noAccess;   // 접근 불가
	int readOnly;   // 읽기 전용
	int writeOnly;  // 쓰기 전용
	int readWrite;  // 읽기/쓰기
};
  • 읽기 전용, 쓰기 전용, 읽기/쓰기 등 다양한 세밀한 제어가 가능하다.
  • 단순히 접근을 막는 걸 넘어서, 의도에 맞는 명확한 인터페이스 제공이 가능하다.

✅ 캡슐화(encapsulation)

class SpeedDataCollection {
public:
	void addValue(int speed);        // 값을 추가
	double averageSoFar() const;     // 평균 계산
	...
};

👉 averageSoFar의 내부 구현 방식은 두 가지 가능

  1. addValue를 호출할 때마다 평균을 갱신해두고, averageSoFar는 그 값을 반환.
  2. averageSoFar 호출 시, 그때 평균을 계산.

→ 어떤 방식을 선택하든 외부에서는 차이가 없다.
내부 구현을 자유롭게 바꿀 수 있는 여지를 확보하게 된다.


👉 캡슐화를 통해 얻는 이점

  • 클래스의 불변속성(invariant) 을 유지할 수 있다.
  • 나중에 내부 구현을 변경해도, public 인터페이스가 변하지 않으면 외부 코드에 영향이 없다.

✅ protected는 public과 다를 바 없다

  • protected는 겉보기엔 더 안전해 보이지만, 파생 클래스에서 마음대로 접근 가능하므로 실질적으로는 public과 유사하다.
  • 누군가가 protected 멤버에 의존하는 코드를 작성하면,
    public 멤버처럼 변경 시 파급 효과가 클 수밖에 없다.

→ 캡슐화 관점에서 쓸모 있는 접근 제어는 결국 private와, private이 아닌 나머지 둘 뿐이다.


🧐 정리

  • 데이터 멤버는 private로 선언하자. 다음과 같은 이점이 있다:
    • 문법적 일관성을 확보할 수 있다.
    • 세밀한 접근 제어가 가능하다.
    • 내부 구현을 숨기고, 변경 가능성을 열어두는 캡슐화가 가능하다.
  • protectedpublic보다 결코 더 안전하지 않다.
    → 외부 의존성이 많아지면, 역시나 변경에 취약하다.

Cpp 카테고리 내 다른 글 보러가기

댓글남기기