복사 생성자에서 개인 변수에 액세스 할 수있는 이유는 무엇입니까?


88

클래스의 get-function을 통해서만 private 변수에 액세스 할 수 없다는 것을 배웠습니다. 그런데 왜 복사 생성자에서 액세스 할 수 있습니까?

예:

Field::Field(const Field& f)
{
  pFirst = new T[f.capacity()];

  pLast = pFirst + (f.pLast - f.pFirst);
  pEnd  = pFirst + (f.pEnd - f.pFirst);
  std::copy(f.pFirst, f.pLast, pFirst);
}

내 선언 :

private:
  T *pFirst,*pLast,*pEnd;

복사 생성자는 기본적으로 클래스 멤버이므로 다른 멤버도 마찬가지입니다.
DumbCoder 2010

+ 53 / -0? 누가 투표 했습니까? 어떻게 복사 할까요?!? (비 대안을 폭로하자 : 각 개인 구성원에 대해 공개 참조 게터를 만드시겠습니까? 그러면 전혀 비공개가 아닙니다. const&각각에 대해 공개 또는 값별 게터를 만드 시겠습니까? 그런 다음 그들은 '쓰기-개인'일뿐입니다. & 가치를 위해 자원을 낭비하고 복사 할 수없는 회원에게는 실패합니다.) 나는 그것이 의미하는 바를 완전히 무시하면서 복사 구성에 대해 묻는 그런 공허한 질문의 성공에 당혹 스럽습니다. 그리고 그것을 반박하기 위해 기본 논리를 사용하는 대답은 없습니다. 그들은 건조 교칙을 설명하지만, 훨씬 더 간단한 대답이 편협 질문에있다
underscore_d

8
@underscore_d, "어떻게 복사 하시겠습니까?" 제 생각에는 매우 이상한 반응입니다. "중력은 어떻게 작동합니까?"라고 대답하는 것과 같습니다. "그렇지 않으면 어떻게 될까요!" 클래스 수준 캡슐화와 개체 수준 캡슐화를 혼동하는 것은 사실 매우 일반적입니다. 그것이 어리석은 질문이고 대답이 분명해야한다고 생각하는 것처럼 보이는 것은 재밌습니다. Smalltalk (아마도 전형적인 OO 언어)의 캡슐화는 실제로 객체 수준에서 작동한다는 점을 명심하십시오.
aioobe

@aioobe 좋은 지적, 감사합니다. 내 의견은 다소 극단적입니다. 아마도 그날 커피 머신이 고장 났을 것입니다. 이 질문이 왜 인기가 있는지 지적 해주셔서 감사합니다. 특히 다른 (그리고 아마도 더 많은) OO 언어에서 온 사람들 사이에서 그렇습니다. 사실, 내가 대부분 C ++로 프로그래밍하는 사람의 관점에서 글을 쓰고 있었기 때문에 내 의견이 "깜빡 거리는"것이라고 주장 할 수 있습니다. 또한 중력 비유를 좋아하십시오!
underscore_d

답변:


33

IMHO, 기존 답변은 "이유"를 설명하는 데 실패했습니다. 행동이 유효한지 반복하는 데 너무 많은 초점을 맞추고 있습니다. "액세스 수정자는 객체 수준이 아닌 클래스 수준에서 작동합니다." -그래, 그런데 왜?

여기서 가장 중요한 개념은 원하는 OO 캡슐화를 이해하고 구현을 조정할 권한이있는 클래스를 설계, 작성 및 유지 관리하는 프로그래머 (들)라는 것입니다. 따라서을 작성 class X하는 경우 개별 X x객체가 액세스 권한이있는 코드 에서 개별 객체를 사용 하는 방법뿐만 아니라 다음 방법도 인코딩 합니다.

  • 파생 클래스는 (선택적으로 순수한 가상 기능 및 / 또는 보호 된 액세스를 통해) 상호 작용할 수 있습니다.
  • 고유 한 X개체가 협력 하여 의도 된 동작을 제공하는 동시에 디자인의 사후 조건과 불변성을 존중합니다.

복사 생성자 뿐만이 아닙니다. 많은 작업이 클래스의 두 개 이상의 인스턴스를 포함 할 수 있습니다. 비교, 추가 / 곱하기 / 나누기, 복사 생성, 복제, 할당 등을 수행하는 경우 종종 해당됩니다. 단순히 다른 개체의 개인 및 / 또는 보호 된 데이터에 대한 액세스 권한이 있거나 더 간단하고 빠르거나 일반적으로 더 나은 기능 구현을 허용하기를 원합니다.

특히, 이러한 작업은 다음과 같은 작업을 수행하기 위해 권한있는 액세스를 활용할 수 있습니다.

  • (복사 생성자) 이니셜 라이저 목록에서 "rhs"(오른쪽) 개체의 전용 멤버를 사용하여 멤버 변수가 기본 생성 (적법한 경우라도) 대신 복사 생성 된 다음 다시 할당되도록합니다 (다시, 합법적 인 경우)
  • 리소스 공유-파일 핸들, 공유 메모리 세그먼트, shared_ptr참조 데이터 등
  • 사물의 auto_ptr<>소유권을 가져옵니다. 예를 들어 소유권을 건설중인 객체로 "이동"합니다.
  • 새 개체를 처음부터 다시 생성 할 필요없이 최적으로 사용 가능한 상태로 새 개체를 구성하는 데 필요한 개인 "캐시", 보정 또는 상태 구성원 복사
  • 복사 / 액세스 진단 / 추적 정보는 복사되는 객체에 보관되어 있으며 공개 API를 통해 액세스 할 수는 없지만 이후의 예외 객체 또는 로깅에서 사용될 수 있습니다 (예 : "원본"비 복사 구성 인스턴스가 발생하는 시간 / 상황에 대한 정보) 건설되었습니다)
  • 일부 데이터의보다 효율적인 복사를 수행합니다. 예를 들어 객체는 예를 들어 unordered_map멤버를 가질 수 있지만 공개적으로 만 노출 begin()end()반복자 만 가질 수 있습니다. 직접 액세스하여 더 빠른 복사 를 수행 size()할 수 reserve있습니다. 더 나쁜 아직 그들은 단지 노출하는 경우 at()insert()그렇지 않은 경우와 throw....
  • 클라이언트 코드에 대해 알 수 없거나 쓰기 전용 일 수있는 상위 / 조정 / 관리 개체에 대한 참조를 다시 복사합니다.

2
가장 큰 '이유'는 액세스 수정자가 객체 수준에서 작동하는 경우 this == other액세스 other.x할 때마다 확인 해야하는 런타임 오버 헤드가 엄청나다는 것입니다 .
aioobe

2
@aioobe 나는 당신의 대답이 훨씬 더 눈에 띄어 야한다고 생각합니다. Tony의 대답은 정말 훌륭하고 개념적이지만, 내가 베팅 맨이라면 당신의 대답이 선택의 실제 역사적 이유라고 확신합니다. 성능이 더 우수 할뿐만 아니라 훨씬 간단합니다. Bjarne에게 좋은 질문이 될 것입니다!
Nir Friedman

나는 그것을 배경 설명 때문에, 답을 표시 한)
demonking

@demonking, 나는이 답변에 주어진 이유 가 개인 데이터를 다른 개체에 공개하는 것이 편리한 이유를 다루고 있다고 생각 합니다. 그러나 액세스 수정자는 데이터를 충분히 "공개적으로"만들기위한 것이 아닙니다. 오히려 캡슐화 를 위해 데이터를 충분히 닫을 수 있습니다. ( 편의성 측면에서 개인 변수가 공개되면 더 좋을 것입니다 !) 실제 이유를 더 잘 다루는 섹션으로 답변을 업데이트했습니다 .
aioobe 2017-06-29

@aioobe : 오래된 의견, 어쨌든 ... "체크하면 this == other사용자가 액세스마다 other.x"- 지점 미스 - 경우 other.x에 경우에 해당하는 실행시에 받아 들여졌다 this.x, 많은 포인터 쓰기가 없을 것이다 other.x처음부터; 컴파일러는 if (this == other) ...this.x...당신이 무엇을하려고 하던지 작성하도록 강요 할 수도 있습니다 . 귀하의 "편의성 (개인 변수가 공용 인 경우 더욱)" 개념도 요점을 놓칩니다. 표준의 정의 방식은 적절한 캡슐화 를 허용 할만큼 제한적 이지만 불필요하게 불편하지는 않습니다.
Tony Delroy

108

액세스 수정자는 객체 수준이 아닌 클래스 수준 에서 작동 합니다 .

즉, 동일한 클래스의 두 개체가 서로 개인 데이터에 액세스 할 수 있습니다.

왜:

주로 효율성 때문입니다. 액세스 수정자가 객체 수준에서 작동 하는지 확인해야 this == other할 때마다 액세스 other.x할 때마다 확인하는 것은 무시할 수없는 런타임 오버 헤드 입니다.

범위 지정 측면에서 생각해 보면 의미 론적으로도 논리적입니다. "개인 변수를 수정할 때 염두에 두어야 할 코드 부분은 얼마나됩니까?" – 전체 클래스의 코드를 염두에 두어야하며 이는 런타임에 존재하는 객체와 직교합니다.

그리고 복사 생성자와 할당 연산자를 작성할 때 매우 편리합니다.


35

다른 인스턴스의 경우에도 클래스 내에서 클래스의 전용 멤버에 액세스 할 수 있습니다.


10

답을 이해하기 위해 몇 가지 개념을 상기시키고 싶습니다.

  1. 생성 한 객체의 수에 관계없이 해당 클래스의 메모리에는 하나의 함수 복사본이 하나만 있습니다. 함수는 한 번만 생성된다는 의미입니다. 그러나 변수는 클래스의 각 인스턴스에 대해 별개입니다.
  2. this 포인터는 호출 될 때 모든 함수에 전달됩니다.

이제 this포인터로 인해 함수가 특정 인스턴스의 변수를 찾을 수 있습니다. 그것이 공공의 사적이든 상관 없습니다. 해당 함수 내에서 액세스 할 수 있습니다. 이제 동일한 클래스의 다른 객체에 대한 포인터를 전달하면. 이 두 번째 포인터를 사용하여 개인 멤버에 액세스 할 수 있습니다.

이것이 귀하의 질문에 답하기를 바랍니다.


6

복사 생성자는 클래스의 멤버 함수이므로 'private'로 선언 된 경우에도 클래스의 데이터 멤버에 액세스 할 수 있습니다.


3
언어를 아는 사람으로서 당신이 의미하는 바를 이해합니다. 그러나 내가 언어를 몰랐다면 당신이 그 질문을 내게 되풀이하는 것이라고 생각했을 것입니다.
San Jacinto
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.