Java có thúc đẩy sự tách biệt giữa các định nghĩa và triển khai lớp, như C ++ không?


10

Tôi có bài tập về nhà và tôi cần đánh giá cách tiếp cận nào tốt hơn theo GRASP "Biến được bảo vệ". Tôi đã tìm thấy một câu hỏi trên Stack Overflow về việc tách các tệp tiêu đề và mã trong C ++ .

Tuy nhiên, điều tôi muốn biết tại sao Java không tuân theo C ++ trong việc thúc đẩy sự tách biệt giữa các định nghĩa lớp và việc triển khai lớp. Có bất kỳ lợi thế nào với phương thức Java, so với phương thức C ++ không?


Nếu bạn muốn hỏi "Tại sao Java không sử dụng các tệp tiêu đề", thì hãy hỏi điều đó và loại bỏ những thứ "tốt hơn" - như bạn đã thấy, chúng tôi dị ứng với điều đó;) Cũng tìm kiếm, tôi Tôi khá chắc chắn điều này (hoặc ít nhất là các câu hỏi liên quan chặt chẽ) đã được đưa ra trước đây.

Rất tiếc, liên kết không hoạt động. Tôi sẽ điều chỉnh lại, điều mà tôi muốn biết về cơ bản, là sự khác biệt giữa cả hai và cái nào có xu hướng dễ sử dụng lại mã hơn hoặc để mở rộng.
Etienne Noël

1
C (và bởi phần mở rộng C ++) thực sự không có lựa chọn nào khác ngoài việc tách các tệp tiêu đề khỏi các tệp thực hiện, do công nghệ trình biên dịch một lượt hạn chế tại thời điểm C được tạo.
Kênh72

2
Java có thể có các Giao diện có thể tách biệt định nghĩa lớp và triển khai lớp, nếu lớp được đề cập thực hiện giao diện. Không hoàn toàn giống như C ++.
Thất vọngWithFormsDesigner

1
Ngoài ra, các tệp tiêu đề C ++ cho thấy việc thực hiện nhiều hơn đáng kể so với tôi muốn, trừ khi bạn sử dụng thành ngữ PIMPL. Cần phải liệt kê tất cả các thành viên dữ liệu, ngay cả khi private, vì vậy việc triển khai sẽ biết kích thước và các privatechức năng thành viên cũng vậy.
David Thornley

Câu trả lời:


13

Có bao nhiêu dòng mã trong chương trình sau đây?

#include <iostream>

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

Bạn có thể đã trả lời 7 (hoặc 6 nếu bạn không đếm dòng trống hoặc 4 nếu bạn không đếm số lần niềng răng).

Trình biên dịch của bạn, tuy nhiên, thấy một cái gì đó rất khác nhau:

~$ cpp hello.cpp | wc
  18736   40822  437015

Vâng, đó là 18,7 KLOC chỉ cho một "Xin chào, thế giới!" chương trình. Trình biên dịch C ++ phải phân tích tất cả điều đó. Đây là một lý do chính tại sao quá trình biên dịch C ++ mất nhiều thời gian so với các ngôn ngữ khác và tại sao các ngôn ngữ hiện đại lại tránh các tệp tiêu đề.

Một câu hỏi tốt hơn sẽ là

Tại sao không C ++ có tập tin tiêu đề?

C ++ được thiết kế để trở thành siêu bộ của C, vì vậy nó phải giữ các tệp tiêu đề để tương thích ngược.

OK, vậy tại sao C có tệp tiêu đề?

Bởi vì mô hình biên dịch riêng biệt nguyên thủy của nó. Các tệp đối tượng được tạo bởi trình biên dịch C không bao gồm bất kỳ thông tin loại nào, vì vậy để ngăn ngừa lỗi loại, bạn cần đưa thông tin này vào mã nguồn của mình.

~$ 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

Thêm khai báo kiểu thích hợp sẽ sửa lỗi:

~$ 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

Lưu ý rằng không có #includes. Nhưng khi bạn sử dụng một số lượng lớn các chức năng bên ngoài (mà hầu hết các chương trình sẽ làm), việc khai báo chúng theo cách thủ công sẽ trở nên tẻ nhạt và dễ bị lỗi. Sử dụng tập tin tiêu đề dễ dàng hơn nhiều.

Làm thế nào là ngôn ngữ hiện đại có thể tránh các tập tin tiêu đề?

Bằng cách sử dụng một định dạng tệp đối tượng khác nhau bao gồm thông tin loại. Ví dụ, định dạng tệp Java *. Class bao gồm "mô tả" chỉ định các loại trường và tham số phương thức.

Đây không phải là một phát minh mới. Trước đó (1987), khi Borland thêm các "đơn vị" được biên dịch riêng cho Turbo Pascal 4.0, nó đã chọn sử dụng *.TPUđịnh dạng mới thay vì Turbo C *.OBJđể loại bỏ nhu cầu về tệp tiêu đề.


Mặc dù thú vị, tôi khá chắc chắn rằng bạn có thể đặt Turbo Pascal thành OBJcác tệp đầu ra thay vì TPU...
một CVn

7

Java có các giao diện để xác định hợp đồng. Điều này mang lại mức độ trừu tượng cao hơn so với những gì người gọi cần và việc thực hiện thực tế. tức là người gọi không cần biết lớp triển khai, nó chỉ cần biết hợp đồng mà nó hỗ trợ.

Giả sử bạn muốn viết một phương thức làm chậm tất cả các khóa / giá trị trong Bản đồ.

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

Phương thức này có thể gọi entryset () trên một giao diện trừu tượng được loại bỏ khỏi lớp thực hiện nó. Bạn có thể gọi phương thức này với.

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

1
Chào mừng bạn đến với Lập trình viên ở đó Peter - nghĩ rằng tôi đã nhận ra tên :-). Tôi sẽ nói thêm rằng một số người sẽ lập luận rằng các lớp cơ sở Trừu tượng trong Java cũng xác định một hợp đồng - nhưng đó có lẽ là một đối số cho một luồng riêng biệt.
Martijn Verburg

Xin chào @MartijnVerburg, bổ sung tốt đẹp. Tôi nghĩ rằng các lớp trừu tượng làm mờ sự khác biệt giữa các giao diện mà không cần triển khai và các lớp cụ thể. Các phương pháp mở rộng sẽ làm mờ sự khác biệt hơn nữa. Tôi có xu hướng thích sử dụng một giao diện nếu tôi có thể vì chúng đơn giản hơn.
Peter Lawrey

Vâng Java sẽ bắt đầu đi xuống con đường Scala có nhiều cách để xác định hợp đồng công khai - Tôi không chắc đó có phải là điều tốt hay chưa :-)
Martijn Verburg

-1 Điều này cũng có thể có trong C ++, với một cách đơn giản #define interface class.
Sjoerd

@Sjoerd Tôi không biết các phương thức C ++ không còn cần phải sử dụng virtualtừ khóa để có được tính đa hình và điều này không có hình phạt về hiệu năng nếu bạn chỉ sử dụng một hoặc hai loại cụ thể, giống như chúng có trong Java. Bạn có thể chỉ cho tôi bất kỳ tài liệu nào về cách thức hoạt động trong C ++ này không?
Peter Lawrey

5

Tiêu đề tồn tại, khá thẳng thắn, như một tai nạn lịch sử. Đó là một hệ thống cực kỳ nghèo nàn, không có ngôn ngữ nào khác có thứ gì đó quá khủng khiếp và bất cứ ai không phải đối phó với chúng cũng nên vui mừng.


3

Tiêu đề là ở đó để cho phép biên dịch riêng biệt. Bằng cách bao gồm các tiêu đề, trình biên dịch không cần biết gì về cấu trúc nhị phân của mã C ++ đã biên dịch và có thể để công việc đó cho một trình liên kết riêng. Java không sử dụng một trình liên kết riêng với trình biên dịch của nó và vì các tệp. Class được xác định nghiêm ngặt, trình biên dịch có thể đọc chúng để xác định tất cả các thành viên của chúng với tất cả các loại của chúng, mà không cần phải khai báo lại chúng trong mỗi đơn vị biên dịch.

Bạn có thể bao gồm tất cả việc thực hiện trong một tiêu đề C ++, nhưng nó khiến trình biên dịch biên dịch lại nó mỗi khi nó bị loại bỏ, buộc trình liên kết phải sắp xếp và loại bỏ các bản sao trùng lặp.


0

Java không thúc đẩy phân tách định nghĩa và thực hiện lớp, nó chỉ phụ thuộc vào nơi bạn đang tìm kiếm.

Khi bạn là tác giả của một lớp Java, bạn có thể thấy định nghĩa của lớp cũng như việc triển khai nó trong một tệp. Điều này đơn giản hóa quá trình phát triển vì bạn chỉ đi đến một nơi để duy trì lớp, bạn không phải chuyển đổi giữa hai tệp (.h và .cpp như trong C ++). Tuy nhiên, khi bạn là người tiêu dùng của lớp, bạn chỉ xử lý định nghĩa, thông qua tệp. Class được đóng gói trong .jar hoặc độc lập. Class.

C ++ cho phép bạn tách biệt định nghĩa và triển khai, nhưng đó là đặc biệt. Ví dụ, không có gì ngăn bạn viết nội tuyến phương thức trong tệp tiêu đề và đối với các lớp mẫu, điều này là bắt buộc. Tệp tiêu đề cũng liệt kê bất kỳ biến thành viên nào, bất kỳ ai nhìn vào tệp tiêu đề, mặc dù chúng là một chi tiết triển khai của lớp và không liên quan đến người tiêu dùng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.