Đã có một số điểm tốt trong các câu trả lời khác, nhưng tôi muốn cung cấp một câu trả lời đầy đủ hơn, giải quyết các câu hỏi và câu hỏi của bạn một cách riêng lẻ.
Nếu Java không cung cấp một tính năng mà C ++ có, điều đó có nghĩa là tính năng này không tốt, vì vậy chúng ta nên ngăn chặn việc sử dụng nó.
Điều này đã được trả lời khá tốt: Java không phải là "phần tốt" của C ++, cũng không có lý do nào để nghĩ như vậy.
Đặc biệt, mặc dù giá trị của từng tính năng C ++ riêng lẻ vẫn còn gây tranh cãi, nhiều tính năng của C ++ 11 / C ++ 14 không phải là một phần của Java không nhất thiết bị loại trừ vì các nhà thiết kế Java nghĩ rằng chúng là một ý tưởng tồi. Như một ví dụ, cho đến phiên bản 8, Java không có lambdas, nhưng chúng đã được giới thiệu về C ++ trong tiêu chuẩn C ++ 11. Trước Java 8, giả định của bạn rằng các tính năng C ++ bị thiếu trong thiết kế bị thiếu bởi vì chúng "không tốt" sẽ ngụ ý rằng lambdas như một tính năng ngôn ngữ là "không tốt" (đối với sự kinh dị của LISPers ở mọi nơi, mặc dù chúng có lẽ đủ kinh hoàng khi nghe rằng bạn rõ ràng thực sự thích Java). Nhưng bây giờ, các nhà thiết kế Java đã đưa Dấu chấp thuận (TM) của họ lên lambdas, vì vậy giờ đây họ là một điều tốt.
Để tìm hiểu sâu hơn một chút, ngay cả trong Java 8, các đóng cửa của lambdas không linh hoạt như lambdas của C ++ 14, nhưng điều này có thể là do các hạn chế về kiến trúc của JVM chứ không phải là một quyết định có ý thức rằng cách tiếp cận linh hoạt hơn là xấu quan điểm thiết kế ngôn ngữ.
Mã C ++ với các tính năng cụ thể của C ++ (ví dụ: hàm bạn bè, nhiều kế thừa) chỉ có thể được duy trì hoặc xem xét bởi các lập trình viên C ++, nhưng nếu chúng ta chỉ viết C ++ như Java (không có tính năng cụ thể của ngôn ngữ C ++), thì cả hai mã đều có thể được duy trì hoặc xem xét Lập trình viên C ++ và Java.
Đây là điều chính tôi muốn trả lời.
Nói rộng hơn, có thể có một số giá trị để nhận được đánh giá mã từ các lập trình viên, những người không quen thuộc với ngôn ngữ bạn đang sử dụng. Họ có thể cung cấp cho bạn thông tin phản hồi có giá trị về sự rõ ràng của tên và nhận xét về chức năng / phương thức của bạn và (như câu hỏi của bạn ngụ ý chính xác) nếu ngôn ngữ giống với một hoặc nhiều ngôn ngữ họ đã biết, họ có thể theo luồng chương trình cơ bản và có khả năng bắt lỗi logic.
Tuy nhiên, không phải trường hợp nào loại đánh giá này sẽ là "tốt như" hoặc "tương đương" với đánh giá từ các nhà phát triển thực sự biết ngôn ngữ bạn đang sử dụng. Về cơ bản, điều này là do làm cho một ngôn ngữ trông giống ngôn ngữ khác thường sẽ che giấu sự khác biệt tinh tế, trong khi làm cho một ngôn ngữ hoạt động giống ngôn ngữ khác (đặc biệt là trong trường hợp của C ++ và Java) có thể không thành ngữ đối với ngôn ngữ và / hoặc vẫn có thể quá khó hiểu cho các nhà phê bình.
Đầu tiên, chúng ta hãy nghĩ về ý nghĩa của việc làm cho C ++ "trông giống như" Java. Như một trường hợp đơn giản, bạn có thể sử dụng new
để khởi tạo các đối tượng, giống như trong Java:
Foo foo = new Foo();
Nhưng các đối tượng khởi tạo theo cách này sử dụng ->
thay vì .
gọi các phương thức, vì vậy nếu bạn muốn các lệnh gọi phương thức trông giống như Java, thay vào đó bạn phải viết:
Foo& foo = *new Foo();
Nhưng điều này là không thành ngữ; đặc biệt, bộ nhớ sau đó phải được dọn sạch bằng cách sử dụng delete &foo
, điều mà một số nhà phát triển C ++ có kinh nghiệm thậm chí có thể không nhận ra là mã hợp pháp . Dù bằng cách nào, có những biểu tượng không giống Java vui nhộn được rắc khắp nơi, vì vậy chúng ta hoàn toàn không thể làm cho ngôn ngữ "trông giống như" Java. (Bạn có thể loại bỏ *new
sử dụng #define New *new
, hoặc tệ hơn, #define new *new
nhưng sau đó bạn chỉ cần cầu xin cho các nhà phát triển đồng bào của bạn để ghét bạn.) Và, như đã đề cập ở trên, delete
không tồn tại trong Java, vì vậy trong mọi trường hợp (như đã đề cập trong câu trả lời khác ) bạn thực sự không thể làm cho việc sử dụng đối tượng "nhìn" theo cách mà Java thực hiện mà không bị rò rỉ bộ nhớ.
Nhưng C ++ hiện đại bao gồm các con trỏ chia sẻ thông minh, hoạt động rất giống các tham chiếu biến được quản lý bộ nhớ của Java. Vì vậy, ở mọi nơi trong Java mà bạn có thể viết Foo foo = new Foo();
, thay vào đó bạn có thể viết:
std::shared_ptr<Foo> foo = std::make_shared<Foo>();
Bây giờ bạn đang sử dụng một tính năng ngôn ngữ thực sự rất giống với Java. Nhưng đột nhiên bạn có rất nhiều điều để giải thích cho những người đánh giá không phải C ++: shared_ptr
công cụ này là gì? Các "gotchas" tinh tế là make_shared
gì? (Nó sử dụng chuyển tiếp hoàn hảo, có một số trường hợp lỗi và có thể dẫn đến hàm tạo "sai" được gọi.) Tại sao các phương thức cần phải được gọi với ->
, nhưng sử dụng .
với một số phương thức được trình biên dịch cho phép? ( shared_ptr
có các phương thức riêng của nó.) Nếu phương thức Foo::reset(void)
tồn tại, một nhà phát triển không cố ý có thể cố gắng gọi nó bằng foo.reset()
, (nếu chỉ có một con trỏ chia sẻ trỏ đến trường hợp đó Foo
khi cuộc gọi xảy ra) sẽ xóa bộ nhớ bên dưới và vô hiệu hóa foo
, và Các nhà phát triển Java không có khả năng bắt gặp vấn đề này.
Hơn nữa, C ++ có rất nhiều các cạm bẫy mà cụ thể với ngôn ngữ. Theo cách tốt nhất tôi có thể nói, hầu hết các nhà phát triển C ++ học cách đối phó với những cạm bẫy này bằng cách dần dần phát triển thành ngữ riêng của họ cho các thực tiễn C ++ "an toàn", thường hơi độc đáo đối với họ hoặc với nhóm phát triển của họ (ví dụ: câu trả lời hiện có đề cập đến Thực tiễn mã hóa của Google và nhận xét về nó nói rằng "Các cựu chiến binh C ++ dày dạn thường từ chối các nguyên tắc mã hóa của Google"). Tất cả các tuyên bố rằng ngôn ngữ có thể quá phức tạp, dường như (theo kinh nghiệm của tôi, ít nhất), thường được đáp ứng với một số biến thể của "tốt, ngừng sử dụng sai." Tôi nhận ra đây là một cái nhìn rất tiêu cực của C ++ cộng đồng, và chắc chắn có các nhà phát triển có kinh nghiệm sẵn sàng để giúp đỡ ngôn ngữ học, nhưng có không dường như là một sự bảo vệ nhất định về ví dụ như hành vi không xác định (ví dụ như phần lớn cuộc thảo luận trong liên kết 'cạm bẫy' của tôi ở trên).
Các nhà phát triển Java đơn giản sẽ không hữu ích trong việc tìm kiếm và sửa chữa những cạm bẫy này thông qua việc xem xét mã.
Bạn có thể được yêu cầu chuyển đổi mã sang Java một ngày nào đó.
Nó hoàn toàn hợp lệ - đáng khen ngợi, thậm chí - để cố gắng tính đến những gì có thể xảy ra với mã của bạn trong tương lai khi bạn đang trong giai đoạn thiết kế.
Nhưng, trước tiên, sự xem xét cụ thể này có vẻ như là một khả năng từ xa: mã thường được sử dụng lại như cũ (ví dụ: bạn có thể cắm một số hoặc tất cả mã C ++ đang hoạt động vào một số phần mềm Java trong tương lai bằng giao diện JNI) hoặc viết lại hoàn toàn hơn là "phiên âm" trực tiếp bằng tay.
Và, thứ hai, sau này bạn nói,
Mỗi tính năng cụ thể của ngôn ngữ C ++ (ví dụ: nhiều kế thừa) nên có các lựa chọn thay thế được triển khai trong Java ....
Điều này về cơ bản hủy bỏ điểm "chuyển đổi sang Java" của bạn. Nếu phần mềm được viết bằng C ++ thành ngữ và sau đó được chuyển đổi thành Java thành ngữ, không có lý do gì để hy vọng rằng việc chuyển đổi này sẽ (hoặc có thể!) Được thực hiện bằng cách áp dụng ánh xạ chính xác một tính năng của C ++ cho các tính năng Java.
Mã không có các tính năng cụ thể của C ++ thường dễ bảo trì hơn.
Không rõ ý của bạn ở đây là gì, nhưng tôi thực sự phần nào đồng ý với một phần của điều này: trừ khi bạn rất cẩn thận và ngay cả khi bạn cẩn thận, các tính năng của C ++ có thể dẫn đến các vấn đề về bảo trì. Các C ++ FQA Lite (một trang web quan trọng của ngôn ngữ và tín đồ của nó từ một người ít nhất xuất hiện để thực sự hiểu nó khá tốt) khẳng định rằng
... 80% các nhà phát triển hiểu tối đa 20% ngôn ngữ. Nó không giống nhau 20% cho những người khác nhau, vì vậy đừng tin tưởng vào họ để hiểu mã của nhau.
XIN LƯU Ý: Nếu bạn là một người hâm mộ C ++ và bạn nhận được điểm này trong câu trả lời của tôi và cảm thấy có xu hướng nhảy xuống nhận xét để cho rằng tác giả của FQA không thực sự hiểu C ++ hoặc không đồng ý trong hầu hết các lập luận của anh ấy , lưu ý rằng (1) chính xác hai câu sau khi tôi trích dẫn anh ấy Tôi thừa nhận rằng FQA là một nguồn rất thiên vị và (2) nó không thực sự quan trọng đối với những gì tôi đang cố gắng nói liệu tác giả FQA có hiểu C ++ hay không , và tôi không cố gắng bash C ++, và bạn nên đọc phần còn lại của bài đăng mà không cho rằng tôi chống C ++ chỉ vì tôi đã trích dẫn FQA. Kết thúc ghi chú.
Tương tự, Linus Torvalds ghét C ++ vì lý do này (cảnh báo: liên kết liên quan đến nhiều lời chửi thề, theo kiểu Linus khét tiếng thực sự).
Rõ ràng, đây là những vấn đề rất thiên vị về vấn đề này, nhưng ngay cả những người đề xuất C ++ thường nói rằng bạn không nên sử dụng toàn bộ bộ tính năng ngôn ngữ (một lần nữa, hãy xem hướng dẫn mã hóa của Google; Bjarne Stroustrup, người tạo ra C ++ , đã công khai tuyên bố, "Trong C ++, có một ngôn ngữ nhỏ hơn và gọn gàng hơn đang vật lộn để thoát ra").
Vì vậy, tôi nghĩ rằng có một số giá trị cho ý tưởng rằng các tính năng C ++ có thể quá dễ sử dụng, đặc biệt là nếu bạn đến từ nền Java. Hơn nữa, có công cho ý tưởng giảm bớt những vấn đề này bằng cách giới hạn bản thân bạn trong một số tập hợp con của ngôn ngữ.
Tuy nhiên, quyết định đó tập hợp con để sử dụng dựa trên một ngôn ngữ khác nhau không không có vẻ như là cách tiếp cận đúng, trừ trường hợp "ngôn ngữ khác nhau" là C, vì có thực sự là một tập hợp con C giống như của ngôn ngữ C ++. (Linus đề cập đến điều này trong câu nói của anh ta ở trên, và Scott Meyers thậm chí còn gọi tập hợp con này là "ngôn ngữ phụ". không rõ ràng có bất kỳ bài học hữu ích nào để rút ra về việc sử dụng C ++ từ nó và như đã lưu ý ở trên, cố gắng rút ra bài học về C ++ trực tiếp từ Java có thể dẫn đến mã rất không thành ngữ.
Thay vào đó, hãy cố gắng xác định "tập hợp con có thể chấp nhận" của ngôn ngữ theo cách hiểu về cách ngôn ngữ có thể được sử dụng một cách thành ngữ. Nếu bạn muốn một tập hợp con khá hạn chế vẫn tận dụng được nhiều tính năng của C ++ ngoài những gì C cung cấp, hướng dẫn Mã hóa Google đã nói ở trên có thể là một nơi tốt để bắt đầu. Chắc chắn, bạn sẽ nhận được các nhà phát triển nói rằng "không có lý lẽ hợp lý" đối với một số hạn chế của Google , nhưng trừ khi bạn đang muốn thuê Alexandrescu khỏi công việc của mình bằng ngôn ngữ D (chính nó sẽ cho bạn biết điều gì đó), đó là có lẽ ổn Chắc chắn tốt hơn là cố gắng biến C ++ thành Java.
Một điểm khởi đầu tốt khác cho một bộ hướng dẫn mã là Nguyên tắc cốt lõi C ++ mới , một tiến trình làm việc của Bjarne Stroustrup và Herb Sutter.
Cách duy nhất khác để đối phó với những thiếu sót của C ++ là chọn một ngôn ngữ khác. Nghe có vẻ như bạn thích Java và bạn nghĩ có khả năng dự án này có thể được chuyển đổi thành Java. Như đã lưu ý trong một câu trả lời khác, bạn có thể ... bắt đầu với Java.
Có hai lý do tại sao bạn thực sự cần phải sử dụng một cái gì đó ngoài Java:
- Bạn thực sự cần hiệu suất thời gian chạy. Trong trường hợp này, việc đối xử với C ++ như Java có lẽ sẽ không thực sự giúp ích cho bạn, bởi vì các kỹ thuật giống như Java như con trỏ dùng chung làm giảm hiệu suất thời gian chạy của bạn.
- Bạn cần phần mềm để hoạt động trên nền tảng tối nghĩa chưa hỗ trợ JVM. Trong trường hợp này, bạn có thể bị mắc kẹt với các ngôn ngữ có giao diện GCC hoặc Clang. C và C ++ là những ứng cử viên rõ ràng, nhưng bạn cũng có thể nhìn vào một cái gì đó như Rust. (Quick cắm: Tôi đã không được sử dụng Rust rộng rãi, nhưng có vẻ tuyệt vời và tôi mong muốn làm việc trên một dự án Rust lớn trong thời gian sớm nhất có thể, và tôi nghĩ rằng tất cả mọi người xem xét bắt đầu một ++ Dự án C nên xem xét Rust như một sự thay thế.)
Mỗi tính năng cụ thể của ngôn ngữ C ++ (ví dụ: nhiều kế thừa) nên có các lựa chọn thay thế được triển khai trong Java. Nếu không, điều đó có nghĩa là mẫu thiết kế hoặc kiến trúc mã có vấn đề.
Tôi đã giải quyết điều này phần nào, nhưng tôi cố tình bỏ qua câu thứ hai của bạn.
Tôi không tin rằng một cái gì đó như constexpr
, sẽ không có ý nghĩa gì trong ngôn ngữ JIT một phần như Java, là một dấu hiệu của kiến trúc không hợp lệ. Tôi cởi mở hơn với ý tưởng rằng việc sử dụng quá mức lập trình meta mẫu có thể gặp nhiều rắc rối hơn giá trị của nó, đặc biệt là hiện constexpr
có để thực hiện đánh giá chức năng thời gian biên dịch, nhưng rõ ràng constexpr
là không có lỗi thiết kế nào nếu bạn Đang sử dụng nó: bạn chỉ cần đảm bảo rằng một số tính toán xảy ra trước cả khi chạy mã, đây là một sự tăng hiệu suất tuyệt vời (ví dụ: mục này cho vấn đề cơ thể của The Benchmark Game , vượt trội hơn mọi mục khác trừ một mục khác được viết bằng C ++,