Java는 C ++처럼 클래스 정의와 구현 사이의 분리를 촉진합니까?


10

숙제를 배정 받았으며 GRASP "Protected Variation"에 따라 어떤 접근법이 더 나은지 평가해야합니다. C ++에서 헤더와 코드 파일의 분리에 대한 Stack Overflow에 대한 질문을 찾았 습니다 .

그러나 클래스 정의와 클래스 구현 간의 분리를 촉진하는 데 Java가 C ++을 따르지 않는 이유를 알고 싶습니다. C ++ 메소드에 비해 Java 메소드의 장점이 있습니까?


"Java가 헤더 파일을 사용하지 않는 이유"를 물어 보려면 그냥 물어 보면 "더 나은"항목을 사용하지 말아야합니다. 이것은 (또는 적어도 밀접하게 관련된 질문들)이 전에 제기 된 것이 확실합니다.

죄송합니다. 링크가 작동하지 않았습니다. 기본적으로 알고 싶었던 것은 두 가지의 차이점과 코드를 재사용하기가 더 쉬운 또는 확장성에 대한 차이점입니다.
Etienne Noël

1
C (및 확장명 C ++)는 C가 생성 될 때 제한된 원 패스 컴파일러 기술로 인해 구현 파일과 헤더 파일을 분리하는 것 외에는 선택의 여지가 없었습니다.
Channel72

2
Java는 문제의 클래스가 인터페이스를 구현하는 경우 클래스 정의와 클래스 구현을 분리 할 수있는 인터페이스를 가질 수 있습니다. C ++과 동일하지는 않습니다.
FrustratedWithFormsDesigner

1
또한 C ++ 헤더 파일은 PIMPL 관용구를 사용하지 않는 한 내가 좋아하는 것보다 훨씬 많은 구현을 제공합니다. 경우에도 모든 데이터 멤버를 나열해야 private하므로 구현시 크기와 private멤버 함수도 알 수 있습니다.
David Thornley

답변:


13

다음 프로그램에는 몇 줄의 코드가 있습니까?

#include <iostream>

int main()
{
   std::cout << "Hello, world!\n";
   return 0;
}

아마도 7 (또는 빈 줄을 세지 않으면 6, 중괄호를 세지 않으면 4)이라고 대답했을 것입니다.

그러나 컴파일러는 매우 다른 것을 봅니다.

~$ cpp hello.cpp | wc
  18736   40822  437015

그렇습니다. "Hello, world!" 프로그램. C ++ 컴파일러는이 모든 것을 파싱 해야합니다. 이것이 C ++ 컴파일이 다른 언어에 비해 오래 걸리는 이유와 현대 언어가 헤더 파일을 피하는 이유입니다.

더 좋은 질문은

않는 C 헤더 파일을 가지고 ++?

C ++는 C의 상위 집합이되도록 설계되었으므로 이전 버전과의 호환성을 위해 헤더 파일을 유지해야했습니다.

그렇다면 왜 C에 헤더 파일이 있습니까?

원시적 인 별도의 컴파일 모델로 인해. C 컴파일러가 생성 한 객체 파일에는 유형 정보가 포함되어 있지 않으므로 유형 오류를 방지하려면 소스 코드에이 정보를 포함시켜야합니다.

~$ cat sqrtdemo.c 
int main(void)
{
    /* implicit declaration int sqrt(int) */
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm -Dsqrt= sqrtdemo.c
sqrtdemo.c: In function main’:
sqrtdemo.c:5:5: warning: implicit declaration of function printf [-Wimplicit-function-declaration]
sqrtdemo.c:5:5: warning: incompatible implicit declaration of built-in function printf [enabled by default]
~$ ./a.out 
2.000000

적절한 형식 선언을 추가하면 버그가 수정됩니다.

~$ cat sqrtdemo.c 
#undef printf
#undef sqrt

int printf(const char*, ...);
double sqrt(double);

int main(void)
{
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm sqrtdemo.c
~$ ./a.out 
1.414214

#includes 가 없습니다 . 그러나 많은 수의 외부 함수 (대부분의 프로그램에서 사용)를 사용하면 수동으로 선언하면 지루하고 오류가 발생하기 쉽습니다. 헤더 파일을 사용하는 것이 훨씬 쉽습니다.

현대 언어는 어떻게 헤더 파일을 피할 수 있습니까?

유형 정보가 포함 된 다른 객체 파일 형식을 사용합니다. 예를 들어, Java * .class 파일 형식 에는 필드 유형 및 메소드 매개 변수를 지정하는 "설명자"가 포함됩니다.

이것은 새로운 발명이 아닙니다. Borland (1987)는 Borland가 별도로 컴파일 한 "장치"를 Turbo Pascal 4.0에 추가 할 때 헤더 파일의 필요성을 제거하기 위해 *.TPUTurbo C 대신 새로운 형식 을 사용하기로했습니다 *.OBJ.


흥미롭게도, 나는 당신이 터보 파스칼을 설정 OBJ하지 않고 파일 을 출력하도록 설정할 수 있다고 확신합니다 TPU.
CVn

7

Java에는 계약을 정의하기위한 인터페이스가 있습니다. 이것은 호출자가 필요로하는 것과 실제 구현에서 더 높은 수준의 추상화를 제공합니다. 즉, 호출자는 구현 클래스를 알 필요가 없으며 지원하는 계약 만 알면됩니다.

지도의 모든 키 / 값을 늦추는 방법을 작성한다고 가정 해보십시오.

public static <K,V> void printMap(Map<K,V> map) {
    for(Entry<K,V> entry: map.entrySet())
        System.out.println(entry);
}

이 메소드는 구현하는 클래스에서 제거 된 추상 인터페이스에서 entrySet ()을 호출 할 수 있습니다. 이 메소드를 호출 할 수 있습니다.

printMap(new TreeMap());
printMap(new LinkedHashMap());
printMap(new ConcurrentHashMap());
printMap(new ConcurrentSkipListMap());

1
Peter의 프로그래머에 오신 것을 환영합니다.-이름을 인식했습니다. 일부 사람들은 Java의 추상 기본 클래스도 계약을 정의한다고 주장하지만, 아마도 별도의 스레드에 대한 인수 일 것입니다.
Martijn Verburg

안녕하세요 @MartijnVerburg, 니스 추가. 추상 클래스는 구현이없는 인터페이스와 구체적인 클래스 사이의 구별을 흐리게한다고 생각합니다. 확장 방법은 구별을 더욱 흐리게합니다. 가능한 한 인터페이스를 사용하는 것이 더 쉽습니다.
Peter Lawrey

예, Java는 공개 계약을 정의하는 여러 가지 방법을 갖는 스칼라 길을 향하고 있습니다.-그것이 좋은지 아직 확실하지 않습니다 :-)
Martijn Verburg

-1 간단한 C ++에서도 가능합니다 #define interface class.
Sjoerd

@ Sjoerd 나는 C ++ 메소드가 더 이상 virtual키워드 를 사용하여 다형성을 얻을 필요가 없다는 것을 몰랐 으며 Java에서와 같이 하나 또는 두 개의 구체적인 유형 만 사용하면 성능이 저하되지 않습니다. 이것이 C ++에서 어떻게 작동하는지에 대한 문서를 알려 주실 수 있습니까?
피터 로리

5

우연히도 우연히 역사적 사고로 존재합니다. 그것은 엄청나게 열악한 시스템이며, 다른 언어에는 끔찍한 것이 없으며, 그것을 다루지 않아도되는 사람은 기뻐해야합니다.


3

별도의 컴파일을 가능하게하는 헤더가 있습니다. 헤더를 포함하여 # 컴파일러는 컴파일 된 C ++ 코드의 이진 구조에 대해 아무것도 알 필요가 없으며 해당 작업을 별도의 링커에 맡길 수 있습니다. Java는 컴파일러와 함께 별도의 링커를 사용하지 않으며 .class 파일이 엄격하게 정의되어 있으므로 컴파일러는 각 컴파일 단위에서 다시 선언 할 필요없이 모든 유형의 모든 멤버를 판별하기 위해 해당 멤버를 읽을 수 있습니다.

모든 구현을 C ++ 헤더에 포함 할 수 있지만, #include 될 때마다 컴파일러가이를 다시 컴파일하게하여 링커가 중복 된 사본을 정렬하여 버립니다.


0

Java는 클래스 정의와 구현의 분리를 촉진하며, 원하는 위치에 따라 다릅니다.

Java 클래스의 작성자 인 경우 클래스 정의와 하나의 파일에서 해당 클래스의 정의를 볼 수 있습니다. 이렇게하면 클래스를 유지하기 위해 한 곳으로 이동하기 만하면 개발 프로세스가 간소화되므로 두 파일 (C ++에서와 같이 .h와 .cpp)을 전환 할 필요가 없습니다. 그러나 클래스의 소비자 인 경우 .jar 또는 독립 실행 형 .class에 패키지 된 .class 파일을 통해서만 정의를 처리합니다.

C ++을 사용하면 정의와 구현을 분리 할 수 ​​있지만 임시입니다. 예를 들어, 헤더 파일 내에서 메소드를 인라인으로 작성하는 것을 막을 것은 없으며 템플릿 클래스의 경우 필수입니다. 헤더 파일에는 클래스의 구현 세부 정보이고 소비자와 관련이 없지만 헤더 파일을 보는 모든 사람에게 표시되는 모든 멤버 변수가 나열됩니다.

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