비공개 변수가 공개적으로 액세스 가능한 헤더 파일에 설명 된 이유는 무엇입니까?


11

자, 이것이 프로그래머에게는 주관적인 충분한 질문이지만, 여기에갑니다. 언어 및 소프트웨어 엔지니어링 실무에 대한 지식을 지속적으로 넓히고 있습니다. 그리고 저는 전혀 이해가되지 않는 무언가에 부딪 쳤습니다.

C ++에서 클래스 선언은 private:헤더 파일에 메소드 및 매개 변수를 포함 합니다. 이론적으로는 사용자가 lib로 만들면 포함하도록 사용자에게 전달합니다.

Objective-C에서 @interfaces는 거의 똑같이 수행하여 개인 구성원을 나열해야합니다 (적어도 구현 파일에서 개인 메소드를 얻는 방법이 있습니다).

내가 알 수있는 것에서 Java와 C #을 사용하면 공개적으로 액세스 가능한 모든 속성 / 메소드를 선언하고 코더 가 구현 파일에서 모든 구현 세부 정보 를 숨길 수있는 인터페이스 / 프로토콜을 제공 할 수 있습니다 .

왜? 캡슐화는 OOP의 주요 원칙 중 하나입니다. 왜 C ++과 Obj-C에 이러한 기본 기능이 부족합니까? 모든 구현 을 숨기는 Obj-C 또는 C ++에 대한 모범 사례 해결 방법이 있습니까?

감사,


4
네 아픔이 느껴져. 클래스에 개인 필드를 처음 추가 할 때 C ++에서 비명을 지르고 사용 된 모든 것을 다시 컴파일해야했습니다.
Larry Coleman

@Larry, 나는 그것을별로 신경 쓰지 않지만 훌륭한 OO 언어로 예고 된 것처럼 보이지만 "적절하게"캡슐화 할 수도 없습니다.
Stephen Furlani

2
과대 광고를 믿지 마십시오. 정적 및 동적 타이핑 캠프에서 OO를 수행하는 더 좋은 방법이 있습니다.
래리 콜맨

그것은하지만 때문에 (C) 상 시뮬 67의 접목되어 그 OO 능력,의, 어떤면에서는 좋은 언어입니다
데이빗 쏜리

C 프로그래밍을해야합니다. 그러면 Java C # 등을 포함하여 이러한 언어가 왜 사용되는지 이해해야합니다.
Henry

답변:


6

문제는 컴파일러가 객체의 크기를 알아야하는지 여부입니다. 그렇다면 컴파일러는 개인 멤버를 계산하기 위해 개인 멤버에 대해 알아야합니다.

Java에는 기본 유형과 객체가 있으며 모든 객체가 별도로 할당되며이를 포함하는 변수는 실제로 포인터입니다. 따라서 포인터는 크기가 고정 된 객체이므로 컴파일러는 지정된 객체의 실제 크기를 모르면서 변수가 나타내는 크기를 알고 있습니다. 생성자는 그 모든 것을 처리합니다.

C ++에서는 객체를 로컬 또는 힙에 표시 할 수 있습니다. 따라서 컴파일러는 객체의 크기를 알아야 로컬 변수 또는 배열을 할당 할 수 있습니다.

때때로 클래스 기능을 공용 인터페이스와 다른 모든 개인 인터페이스로 나누는 것이 바람직하며, 여기에서 PIMPL (Pointer to IMPLementation) 기술이 사용됩니다. 그.


컴파일러 가이 정보를 얻기 위해 객체 라이브러리를 찾을 수 없습니까? 이 정보를 사람이 읽을 수있는 대신 기계로 읽을 수없는 이유는 무엇입니까?
Stephen Furlani

@Stephen : 컴파일 할 때 반드시 객체 라이브러리가있을 필요는 없습니다. 객체의 크기는 컴파일 된 코드에 영향을주기 때문에 링크 타임이 아니라 컴파일 타임에 알려야합니다. 또한 Ah가 클래스 A를 정의하고 Bh가 클래스 B를 정의하고 A.cpp의 함수 정의가 클래스 B의 오브젝트를 사용하거나 그 반대로도 가능합니다. 이 경우 객체 코드에서 객체 크기를 가져 오는 경우 각 A.cpp 및 B.cpp를 먼저 컴파일해야합니다.
David Thornley

컴파일 중에 링크를 수행 할 수 없습니까? 그 깊이에서 세부 사항을 알지 못한다고 고백하지만 객체의 인터페이스가 내용을 노출하면 동일한 내용을 라이브러리 또는 다른 기계 판독 가능 구성 요소에서 노출 할 수 없습니까? 공개적으로 액세스 가능한 헤더 파일에 정의 되어야 합니까? 나는이 C 언어의 대부분의 일부 이해하지만, 그것은 않는 그렇게 할 수 있나요?
Stephen Furlani

1
@Stephen : 모든 적절한 구성 요소가있는 경우 컴파일하는 동안에 만 링크를 수행 할 수 있습니다. 그럼에도 불구하고 부분 컴파일 (객체 크기를 제외한 모든 것), 부분 링크 (객체 크기를 얻기 위해), 최종 컴파일 및 링크를 포함하는 복잡한 프로세스가 될 것입니다. C와 C ++가 비교적 오래된 언어라는 점을 감안하면 그저 일어나지 않을 것입니다. 아마도 누군가 헤더 파일없이 새로운 언어를 디자인 할 수 있었지만 C ++은 아니 었습니다.
David Thornley

14

C ++의 설계로 인해 스택에 객체를 만들려면 컴파일러가 얼마나 큰지 알아야합니다. 이렇게하려면 헤더 필드에 컴파일러가 볼 수있는 모든 필드가 있어야 헤더 파일에 모든 필드가 있어야합니다.

예를 들어 클래스를 정의하면

class Foo {
    public int a;
    private int b;
};

그때 sizeof(Foo)sizeof(a) + sizeof(b)입니다. 개인 필드를 분리하는 메커니즘이 있다면 헤더에

class Foo {
    public int a;
};

sizeof(Foo) = sizeof(a) + ???.

개인 데이터를 실제로 숨기려면 pimpl 관용구를 사용해보십시오.

class FooImpl;
class Foo {
    private FooImpl* impl;
}

헤더에 있고 의 구현 파일 FooImpl에만 해당 Foo됩니다.


오. 나는 이것이 사실인지 전혀 몰랐다. Java, C # 및 Obj-C와 같은 언어에 "클래스 오브젝트"가있는 이유는 무엇입니까?
Stephen Furlani

4
개인 구현에 대한 포인터 pimpl을 사용해보십시오. 모든 클래스 포인터의 크기가 동일하므로 구현 클래스를 정의 할 필요가 없으며 선언 만하면됩니다.
Scott Wales

나는 그것이 의견이 아닌 대답이어야한다고 생각합니다.
Larry Coleman

1

이 모든 것은 디자인 선택에 달려 있습니다.

C ++ 또는 Objective-C 클래스의 개인 구현 세부 사항을 숨기려면 클래스가 지원하는 하나 이상의 인터페이스 (C ++ 순수 가상 클래스, Objective-C @protocol)를 제공하거나 클래스를 작성하십시오. 정적 팩토리 메소드 또는 클래스 팩토리 오브젝트를 제공하여 자체 구성 할 수 있습니다.

개인 변수가 헤더 파일 / 클래스 선언 / @ 인터페이스에 노출되는 이유는 클래스의 소비자가 새 인스턴스를 작성해야 하고 클라이언트 코드에서 new MyClass()또는 [[MyClass alloc]init]MyClass의 크기를 이해하기 위해 컴파일러가 필요하기 때문입니다. 개체는 할당을 수행하기위한 것입니다.

Java와 C #에는 클래스에 개인 변수가 자세히 설명되어 있습니다. 예외는 아니지만 IMO 인터페이스 패러다임은 해당 언어와 훨씬 더 일반적입니다. 각 경우에 소스 코드가 없을 수 있지만 컴파일 된 / 바이트 코드에이 정보를 추론하기에 충분한 메타 데이터가 있습니다. C ++ 및 Objective-C에는이 메타 데이터가 없으므로 유일한 옵션은 class / @ interface의 실제 세부 사항입니다. C ++ COM 세계에서는 클래스가 순수한 가상이기 때문에 클래스의 개인 변수를 공개하지 않고 헤더 파일을 제공 할 수 있습니다. 실제 인스턴스를 생성하기 위해 클래스 팩토리 객체가 등록되어 있으며 다양한 형태의 메타 데이터가 있습니다.

C ++ 및 Objective-C에서는 추가 interface / @ protocol 파일을 작성하고 유지 관리하는 것과 비교하여 헤더 파일을 전달하는 작업이 줄어 듭니다. 이것이 개인 구현이 너무 자주 노출되는 이유 중 하나입니다.

C ++의 또 다른 이유는 템플릿입니다. 컴파일러는 제공된 매개 변수에 특화된 해당 클래스의 버전을 생성하기 위해 클래스의 세부 사항을 알아야합니다. 클래스 멤버의 크기는 매개 변수화에 따라 다르므로이 정보가 필요합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.