Chúng ta có nên tránh các tính năng ngôn ngữ mà C ++ có nhưng Java thì không?


110

Giả sử tôi bị giới hạn sử dụng C ++ bởi môi trường trong dự án. Có tốt không khi ngăn chặn việc sử dụng một số tính năng ngôn ngữ mà C ++ có nhưng Java không có (ví dụ: nhiều kế thừa, quá tải toán tử)?

Tôi nghĩ lý do là:

  1. Vì Java mới hơn C ++, nếu Java không cung cấp 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 tránh sử dụng nó.
  2. 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.
  3. Bạn có thể được yêu cầu chuyển đổi mã sang Java một ngày nào đó
  4. Mã không có các tính năng cụ thể của C ++ thường dễ bảo trì hơn
  5. 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 đề.

Điều đó có đúng không?


7
Nếu bạn nhìn vào những gợi ý của mình, bạn đang nói về việc tạo ra một tiêu chuẩn mã hóa. Thực tế là bạn đang tạo và tuân theo một tiêu chuẩn thực sự là những gì sẽ làm tăng khả năng bảo trì.
Brandin

63
Mã Java cũng nên được giới hạn trong các tính năng, cũng được tìm thấy trong ngôn ngữ C ++? Vì vậy, không sử dụng ví dụ Java volatile, truy cập thành viên lớp gói riêng, phản xạ / hướng nội, khối cuối cùng, ngoại lệ được kiểm tra, v.v. Toàn bộ loại câu hỏi không có nhiều ý nghĩa ... C ++ và Java tương tự bề ngoài, nhưng cuối cùng là các ngôn ngữ rất khác nhau.
hyde

5
Làm thế nào là ngôn ngữ để phát triển nếu mọi người không muốn sử dụng các tính năng mới? Mục đích của các tính năng mới là làm cho cuộc sống của bạn dễ dàng hơn bằng cách giải quyết các vấn đề phổ biến. Nếu người dùng không sử dụng các tính năng mới, thì sẽ không có động lực cho bất cứ ai thực hiện chúng.
Matthew

72
Nếu bạn muốn Java, hãy sử dụng Java. Nếu bạn sử dụng C ++, hãy sử dụng C ++, không phải là một sự bắt chước xoắn, ghê rợn của Java với cú pháp C ++. Sử dụng C ++ nhưng giới hạn bản thân trong bộ tính năng của Java mang đến cho bạn điều tồi tệ nhất của cả hai thế giới.
Jerry Coffin

11
Bạn sẽ ngạc nhiên bởi sự khác biệt sẽ cắn bạn nhanh như thế nào (và khó khăn ). SomeObject a = previousObject;thực hiện những điều rất khác nhau trong Java và C ++. Trong Java, nó sao chép một tham chiếu, trong khi trong C ++, nó sao chép đối tượng. Trong Java, sửa đổi acũng sẽ ảnh hưởng đến đối tượng trước đó. Trong C ++, bạn có hai đối tượng riêng biệt.
Đồng hồ-Muse

Câu trả lời:


307

Không. Điều này thật tồi tệ và sai lầm khủng khiếp.

  • Các tính năng Java không bằng cách nào đó tốt hơn các tính năng C ++, đặc biệt là trong chân không.
  • Nếu lập trình viên của bạn không biết cách sử dụng một tính năng, hãy đào tạo hoặc thuê các nhà phát triển tốt hơn; giới hạn các nhà phát triển của bạn đến điều tồi tệ nhất trong nhóm của bạn là một cách nhanh chóng và dễ dàng để đánh mất các nhà phát triển giỏi của bạn.
  • YAGNI . Giải quyết vấn đề thực tế của bạn ngày hôm nay, không phải là bóng ma của một số vấn đề trong tương lai.

6
Gần đây có một câu hỏi về việc các nhà phát triển xem xét mã bằng ngôn ngữ mà họ không thường viết. Tôi nghĩ rằng sự khôn ngoan được áp dụng ở đây: một nhà phát triển giỏi sẽ phát hiện ra nhiều lỗi cơ bản về bất kỳ ngôn ngữ nào, nhưng mỗi ngôn ngữ có rất nhiều vấn đề mà lợi ích tối đa đạt được khi các nhà phát triển ngôn ngữ thực hiện đánh giá. Điều này thậm chí đúng nếu C ++ của bạn là "chỉ các tính năng Java".
corsiKa

5
+1 Ngoài điểm thứ hai của bạn. OP nên dành thời gian để đọc về "Thực tiễn tốt nhất C ++" để quyết định những tính năng nào họ nên sử dụng. Thông tin cuối cùng của tôi về C ++ là các hàm bạn bènhiều kế thừa được coi là Thực tiễn xấu . Những thứ như MẫuQuá tải toán tử là IMHO thực hành tốt nếu bạn sử dụng chúng một cách khôn ngoan.
some_coder

4
@some_coder: Tất cả chỉ là vấn đề biết khi nào và ở đâu. Khi tôi thực hiện lập trình dựa trên chính sách, tôi kế thừa từ các lớp chính sách (có thể là nhiều) để mở rộng cấu trúc của lớp máy chủ của tôi với các thành viên mà các lớp chính sách yêu cầu để hoạt động. Đó chỉ là cách nó hoạt động. Ngoài ra, operator<<( ostream &, T const & )thường được thực hiện thông qua friend. Đó là vấn đề với các tuyên bố về việc một tính năng ngôn ngữ tốt và một tính năng xấu là gì: Chúng là những lời khuyên tốt, ngoại trừ khi chúng không ...
DevSolar

142

Chỉ vì cú pháp có vẻ giống nhau trên bề mặt không có nghĩa là hai ngôn ngữ tương thích.

1, 4 và 5 thực sự là cùng một câu hỏi:

Bây giờ, tôi không phải là fan hâm mộ của C ++, nhưng nói rằng "Mã không có các tính năng cụ thể của C ++ thường dễ bảo trì hơn" thì thật là nực cười - bạn có thực sự tin rằng Java có mọi thứ đúng và đã bỏ qua tất cả các tính năng tốt trong khi bỏ qua tất cả các tính năng xấu? Bạn có thực sự tin rằng có một cái gì đó phổ biến tính năng "xấu" hoặc "tốt" không? Nếu có, tại sao chúng ta không có một ngôn ngữ hoàn toàn tốt? Và không, Java chắc chắn không phải là ngôn ngữ đó. Điều đó có nghĩa là Java và C ++ là vô dụng? Dĩ nhiên là không.

Điều gì xảy ra nếu các nhà lãnh đạo của bạn quyết định rằng bạn sẽ chuyển sang C #, thay vì Java? C # không chỉ hỗ trợ ghi đè các toán tử, mà còn là mặc định - nếu bạn sẽ yêu cầu mọi người sử dụng, ví dụ như obj.Equals(obj2)thay vì obj == obj2, mọi người sẽ luôn mắc lỗi. Ngay cả khi bạn chỉ giữ các đặc điểm chung của hai ngôn ngữ, vẫn có những kỳ vọng khác nhau , một nền văn hóa khác nhau. Nếu bạn làm một cái gì đó giống như if (myField == null)trong C ++, mọi người sẽ thấy bạn là người mới ngay lập tức. Nếu bạn sử dụng if (null == myField)trong C #, mọi người sẽ thấy bạn chưa thực sự là người bản địa C # - lý do các nhà phát triển C đã học cách sử dụng biến thể "lật" không còn tồn tại trong C #.

Sử dụng logic của bạn, chúng ta nên bị mắc kẹt với mã máy hoặc lắp ráp hoặc COBOL, bởi vì tại sao lại thay đổi thành một thứ như Pascal, khi nó chỉ thêm các tính năng mới mà các lập trình viên của bạn sẽ phải học? Tại sao chúng ta sẽ sử dụng một cái gì đó như SQL, khi nó thậm chí không có vòng lặp ? Tại sao chúng ta sẽ sử dụng một cái gì đó khác với SQL, khi SQL không có vòng lặp và X thì có?

Mã C ++ chắc chắn không thể được duy trì bởi các lập trình viên Java. Tôi không thể hiểu bạn đã có ý tưởng này ở đâu - chính xác là gì khi bạn giới hạn C ++ chỉ với các tính năng hoạt động chính xác như trong Java? Bạn thậm chí sẽ không nhận được các cuộc gọi phương thức - thậm chí không có chức năng gọi. Một lần nữa, chỉ vì cả hai langau sử dụng dấu ngoặc nhọn, không có nghĩa là các ngôn ngữ có thể hoán đổi cho nhau.

Việc chuyển đổi mã C ++ giống như Java sẽ cực kỳ dễ bị lỗi cho dù bạn có làm gì đi nữa. Có quá nhiều sự khác biệt. Nếu bạn quan tâm đến việc phải viết lại ứng dụng của mình bằng một ngôn ngữ khác, hãy nghĩ về những cách hợp lý để mô đun hóa mọi thứ, để bạn có thể thay thế các bộ phận mà không phá vỡ toàn bộ. Nhưng cuối cùng, YAGNI - bất kể bạn làm gì, sẽ có một chi phí đáng kể để làm cho mã của bạn "sẵn sàng để chuyển đổi sang Java". Đó là thời gian rất có thể tốt hơn dành cho việc thêm hoặc cải thiện các tính năng của bạn.

Chúng tôi sử dụng các ngôn ngữ khác nhau vì chúng cung cấp cho chúng tôi một bộ công cụ khác nhau để giải quyết vấn đề. Nếu bạn cần các tệp thực thi hoạt động "ở mọi nơi", hãy dùng Java. Nếu bạn muốn mã biên dịch "ở mọi nơi", C ++ hoạt động tốt. Nếu bạn muốn mã dễ hiểu và phân tích cú pháp, hãy đi với LISP hoặc bất cứ điều gì. Nhưng tôi có thể nói với bạn một điều - viết mã bằng một ngôn ngữ như thể bạn viết nó bằng ngôn ngữ khác luôn là một sai lầm, và bạn sẽ phải chịu đựng. Chưa kể rằng khi bạn thực sự thuê một anh chàng C ++, anh ta sẽ chạy lần thứ hai anh ta thấy mã "tương thích Java-ish". Và ... anh chàng Java cũng sẽ làm như vậy. Bạn biết đấy, thậm chí "biết" cả C ++ và Java, tôi sẽ chạy như địa ngục :)

Tôi thực sự phải làm việc với mã C (đơn giản) được viết bởi một nhà phát triển Pascal, người dường như nghĩ giống như bạn. Anh ta đã sử dụng #defines để xác định lại C để trông và cảm thấy giống Pascal hơn, hoàn thành với những thứ như "BEGIN dịch thành {". Kết quả khá dễ đoán - mã mà cả nhà phát triển C và Pascal đều không thể hiểu được, và đầy lỗi là kết quả của sự "trừu tượng hóa" của Pascal trên đầu C. Và Pascal và C gần như giống hệt với quan điểm ngày nay. Ngay cả việc đi C <-> C ++ cũng có nhiều sự khác biệt và đó vẫn là đậu phộng cho một cái gì đó như C ++ <-> Java.


9
"Nếu bạn muốn mã dễ hiểu và phân tích cú pháp, hãy đi với LISP hoặc bất cứ điều gì." Tôi sẽ không đồng ý với điều đó. Lisp là tầm thường để phân tích, nhưng chính xác là vì điều này - bởi vì nó được tạo ra vào thời mà kiến ​​thức về các trình phân tích cú pháp và các nguyên tắc đằng sau việc xây dựng chúng một cách hiệu quả vẫn còn ở giai đoạn sơ khai, và vì vậy họ đã chơi khăm và đi theo thứ đơn giản nhất một cách lố bịch điều đó có thể có thể làm việc - bạn không nhận được nhiều lợi ích cú pháp của các ngôn ngữ hiện đại. Vì vậy, nó dễ dàng phân tích, nhưng không dễ hiểu chút nào . Có một lý do mà mọi người gọi nó là "Mất trong ngoặc đơn không cần thiết".
Mason Wheeler

9
@MasonWheeler Đó là vấn đề của hương vị - Các lập trình viên C gọi nó như vậy, không phải LISPers: P. Đếm các dấu ngoặc đơn - có khoảng nhiều như trong chương trình C ++ điển hình của bạn. Sự khác biệt thực sự là vị trí của họ ( myFunc()so với (myFunc)), và đó có một lý do rất tốt. Các ngôn ngữ dựa trên LISP vẫn rất phổ biến, đặc biệt là với những người học toán / vật lý. Điều chính thực sự là các ngôn ngữ LISPy rất xa lạ với các lập trình viên kiểu C hiện đại - nhưng đó không phải là lý do để bỏ qua nó. Lược đồ, Clojure và ở một mức độ nào đó, các ngôn ngữ dựa trên ML (OCaml, F # ...) thực sự rất LISPy.
Luaan

4
@Luaan Tôi có thể nói với bạn chắc chắn rằng LISP KHÔNG phổ biến trong vật lý. Hai ngôn ngữ chính trong lĩnh vực này là FORTRAN và C ++. FORTRAN là 'phổ biến' vì rất nhiều mã cũ đã được viết trong đó, nhưng hầu như tất cả các chương trình mới đều được viết bằng C ++. Là một nhà vật lý nghiên cứu, tôi chưa một lần bắt gặp hoặc thậm chí nghe nói về chương trình LISP. Không nói rằng chúng không tồn tại, nhưng ngôn ngữ chắc chắn không phổ biến .
James Matta

4
@Luaan Chúng tôi có thể hoặc không cần thêm nhà phát triển phần mềm. Chúng tôi chắc chắn không cần nhiều sinh viên tốt nghiệp CS. Điều đó giống như nói rằng "chúng ta cần nhiều kỹ sư kết cấu hơn, vì vậy chúng ta cần nhiều sinh viên tốt nghiệp vật lý lý thuyết hơn."
Tuyến Miles

4
@ user1717828 Đó là để tránh những tác động thú vị của đánh nhầm if (myField == null)như if (myField = null), mà sẽ biên dịch tốt C / C ++, nhưng có lẽ không làm những gì bạn dự định. Mặt khác, if (null = myField)sẽ đưa ra một lỗi, vì bạn không thể gán cho hằng số.
Wlerin

94

Tôi sẽ trả lời câu hỏi của bạn theo thứ tự.

  1. 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ó.

Có, bất kỳ tính năng nào không có trong Java là anathema trên ổ cứng. Nó phải được ghi từ cơ sở mã của bạn. Những người không vâng lời sẽ bị thu thập, linh hồn của họ dùng để xoa dịu các vị thần RAID.

  1. 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.

Khi nghi ngờ, hãy viết mã cho thành viên ít có thẩm quyền nhất trong nhóm của bạn. Mã được đọc thường xuyên hơn nhiều so với mã được viết và mã thông minh như bạn có thể viết là quá thông minh để đọc. Mã đánh giá mà nhân viên lễ tân của bạn sẽ không hiểu nên bị từ chối. Để giúp đỡ, hãy dạy họ cách lập trình trực quan 2.0 cơ bản vào cuối tuần, sau đó mô phỏng phong cách mã hóa của họ bằng bất kỳ ngôn ngữ nào bạn đang sử dụng.

  1. Bạn có thể được yêu cầu chuyển đổi mã sang Java một ngày nào đó

Thật! Nhưng tại sao dừng lại ở Java? Bạn có thể được yêu cầu chuyển đổi mã thành cơ bản, trình biên dịch và / hoặc perl một ngày. Vì có các thông dịch viên perl trong mọi ngôn ngữ ngoài kia, chỉ cần viết chương trình của bạn dưới dạng một chuỗi perl dài và các đối số thống nhất vào đó bằng ngôn ngữ được lựa chọn.

Bây giờ khi bạn cần thay đổi ngôn ngữ, chỉ cần viết lại mã gói chuỗi perl.

  1. Mã không có các tính năng cụ thể của C ++ thường dễ bảo trì hơn

Đúng là mã sử dụng ít tính năng sẽ dễ bảo trì hơn. Và vì tất cả các ngôn ngữ đều tương đương với Máy Turing và Máy Turing có ít tính năng nhất của bất kỳ ngôn ngữ lập trình nào, có trình thông dịch perl ở trên thực sự chạy Máy Turing (băng và tất cả) giải quyết vấn đề của bạn.

  1. 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 đề.

Các tính năng cụ thể của ngôn ngữ C ++ thực sự có giá trị sử dụng. Vì chúng không phải là Java, chúng là anathema và những người sử dụng nó có thể là những kẻ dị giáo có thương hiệu. Nếu C ++ không có các tính năng ngôn ngữ đó, bạn sẽ không thể tìm thấy những thứ bạn cần hy sinh. Tính năng ngôn ngữ C ++ giải quyết vấn đề!


Hãy nhìn xem, C ++ và Java có một bộ khả năng khác nhau. Lập trình trong giao điểm của C ++ và Java dẫn đến mã đã loại bỏ hầu hết các lợi thế của cả hai ngôn ngữ.

Java được phát triển một phần như là một phản ứng đối với việc lạm dụng các tính năng C ++. Điều này không có nghĩa là phản ứng đã được chứng minh, đặc biệt là nhiều năm sau đó khi các tính năng đã hoàn thiện.

Bạn có thể làm những điều khủng khiếp với quá tải toán tử; nhưng không ngôn ngữ nào có thể ngăn chặn mã khủng khiếp được viết bằng ngôn ngữ, trừ khi nó ngăn tất cả mã được viết bằng ngôn ngữ.

Và bạn cũng có thể làm những điều rất thanh lịch với quá tải toán tử. Những điều đơn giản, như một số phức hoặc lớp ma trận hoạt động như số phức hoặc ma trận.

Cần thận trọng khi sử dụng các tính năng C ++ không có trong Java. Chỉ vì nhóm nhà phát triển hiện tại của bạn ở cấp kỹ năng hiện tại của họ không hiểu một tính năng không có nghĩa là nó không bao giờ nên được sử dụng; đồng thời, chỉ vì bạn có thể sử dụng một tính năng, không có nghĩa là bạn nên làm vậy. Tuy nhiên, trong một cửa hàng nặng về Java, tỷ lệ cược là sức đề kháng sẽ mạnh hơn so với các tính năng không phải của Java.

Chuyển đổi mã giữa các ngôn ngữ được thực hiện tốt nhất bằng cách viết lại, bất kể chúng có cấu trúc tương tự nhau như thế nào. Bất kỳ nỗ lực để làm như vậy mà không viết lại như vậy sẽ thất bại thảm hại.

Nhiều tính năng cụ thể của C ++ là kỳ quan để bảo trì. Kiểu xóa (như std::function) cho phép bạn tách rời các cấu trúc phân cấp, làm giảm sự phụ thuộc. Con trỏ thông minh và tuổi thọ xác định và RAII làm giảm những bất ngờ trong thời gian chạy và di chuyển tài nguyên nồi hơi ra khỏi đường đi. Kiểm tra kiểu tĩnh nặng có nghĩa là mã không biên dịch, thay vì không hoạt động. Mix-in giảm trùng lặp mã. ADL cho phép mở rộng giao diện độc lập đặc biệt giữa các cấu trúc phân cấp. Lambda cho phép bạn viết mã bên cạnh nơi nó được sử dụng. Chuyển tiếp và di chuyển làm giảm các bản sao và làm cho chương trình theo phong cách chức năng (không có tác dụng phụ) hiệu quả. Quá tải toán tử làm giảm nhiễu dòng và làm cho mã trông giống như toán học mà nó đang tạo mô hình.

Cẩn thận với hố Turing Tar. Bạn có thể triển khai mọi thứ bằng bất kỳ ngôn ngữ nào (bao gồm cả Máy Turing thô có Băng), nhưng điều đó không có nghĩa là bạn nên làm . Mô phỏng các tính năng C ++ bằng cách sử dụng các cấu trúc Java-esque trong C ++ là một ý tưởng khủng khiếp; nó sẽ dẫn đến mã không thể nhầm lẫn mà không ai có thể đọc hoặc hiểu.

Bạn có thể lấy cảm hứng từ các thiết kế Java và chuyển chúng sang C ++. Tôi là một fan hâm mộ lớn của việc sử dụng các tính năng ngôn ngữ Python và triển khai chúng trong C ++, vì tôi thích cú pháp. Nhưng điều đó không có nghĩa là tôi viết các phương thức lớp của mình dưới dạng các phương thức tĩnh tự nhận rõ ràng, sau đó viết một trình bao bọc chuyển tiếp phương thức không tĩnh gọi nó.

C ++ hiện đại không giống với ngôn ngữ mà Java mô phỏng và bị từ chối. Đừng bị khóa bởi các tính năng của một ngôn ngữ; không có "một ngôn ngữ thực sự". Tìm hiểu về ngôn ngữ mới và các tính năng của chúng, và tiếp thu tính khác biệt của chúng.


1
-1, dài dòng và không rõ ràng.
djechlin

4
-1 tranh cai, rơm-người đàn ông lý luận
user949300

28
+1, giải mã đúng các câu hỏi được hỏi và tôi đã cười :)
con mèo

11
+1. Vui nhộn nhưng giữ quan điểm. Rất rõ ràng cho những người thực sự đọc nó.
Luis Masuelli

14
"Lập trình trong giao điểm của C ++ và Java dẫn đến mã đã loại bỏ hầu hết các lợi thế của cả hai ngôn ngữ." Nhấn đinh trên đầu! +1
Ajedi32

56

Tôi sẽ trả lời lý do của bạn:

  1. Tôi không hiểu làm thế nào bạn đi đến kết luận đó. Các ngôn ngữ khác nhau có các tính năng khác nhau. Phụ thuộc vào phạm vi, kiến ​​trúc của ngôn ngữ, đôi khi sở thích của người sáng tạo và nhiều lý do khác. Một số tính năng của ngôn ngữ có thể xấu, nhưng khái quát của bạn hoàn toàn sai IMHO.
  2. Viết C ++ giống như Java có thể dẫn đến mã kém hơn. Ví dụ, ngày nay với C ++ 11 tôi tránh sử dụng new / xóa, nhưng sử dụng các con trỏ chia sẻ. Trong kịch bản của bạn, tôi sẽ chỉ dựa vào mới / xóa. Nếu lập trình viên của bạn chỉ hiểu Java, hãy đào tạo họ hoặc thuê những người giỏi hơn.
  3. Điều đó có khả năng sẽ xảy ra không? Tại sao bạn không viết bằng Java ở nơi đầu tiên? Tôi nghĩ rằng viết lại các chương trình từ đầu bằng một ngôn ngữ mới nói chung là một ý tưởng tồi và bạn sẽ cần một lời biện minh thực sự tốt cho rủi ro như vậy.
  4. Đây chỉ là một giả định.
  5. Phụ thuộc IMHO cao vào kịch bản hoặc trường hợp sử dụng của bạn.

27
Và lập trình viên Java cũng không sử dụng delete.
Paŭlo Ebermann

8
Tôi đã phải sửa lỗi rò rỉ bộ nhớ do các lập trình viên Java không biết delete. Từ những gì tôi nhớ lại, trong ít nhất một trong những trường hợp đó, phân bổ động ( new) cũng không cần thiết.
Ethan Kaminski

16
@EthanK Vitaminki Vâng, đó là cách bạn có thể dễ dàng phát hiện ra một người mới C ++, đặc biệt là một người đến từ nền tảng Java hoặc tương tự. Ngừng sử dụng mới cho mọi thứ, chết tiệt!
Luaan

1
@ PaŭloEbermann Vâng, thậm chí còn tệ hơn.
Simon

1
"Trong kịch bản của bạn, tôi sẽ chỉ dựa vào mới / xóa" - buồn cười, tôi đã nghĩ rằng một thành ngữ "Java (giống như) chỉ sử dụng" thành ngữ C ++ sẽ được sử dụng riêng make_shared.
Kyle Strand

26

Java có các tính năng mà C ++ không có, như trình thu gom rác tích hợp, nhanh, đáng tin cậy, phân cấp đối tượng gốc đơn và hướng nội mạnh mẽ.

Các tính năng khác của Java được thiết kế để hoạt động cùng với các tính năng độc quyền của Java và nhiều thiếu sót về các tính năng C ++ của Java là có thể vì các tính năng mới bù đắp cho sự thiếu hụt. Ví dụ, Java không có các đối tượng được phân bổ ngăn xếp với các hàm hủy xác định, nhưng cuối cùng cũng có các khối (và thử với các tài nguyên kể từ Java 7) và trình thu gom rác để bù đắp cho sự thiếu hụt này.

C ++ cuối cùng không có khối hoặc bộ sưu tập rác. Nếu bạn không sử dụng các hàm hủy vì chúng không tồn tại trong Java (tôi không tính các công cụ hoàn thiện), thì bạn ở cấp độ quản lý tài nguyên C (tức là tất cả thủ công), ngoại trừ việc bạn thậm chí không thể nhóm dọn dẹp vào một khối dọn dẹp mà bạn goto đến, bởi vì Java cũng không có goto. Bạn có thực sự nghĩ rằng cải thiện khả năng bảo trì?

Java có một hệ thống phân cấp đối tượng bao quát, trong đó mọi lớp cuối cùng đều xuất phát từ Object và một vài kiểu nguyên thủy cũng có thể được tự động đóng hộp vào các lớp như vậy. Điều này cho phép ghi các thùng chứa các đối tượng một lần, để giữ các con trỏ tới Object. Java 5 đã giới thiệu các khái quát, loại bỏ các phôi mà các thùng chứa như vậy bắt buộc, nhưng vẫn biên dịch thành khá nhiều mã giống nhau.

C ++ không có hệ thống phân cấp như vậy. Để thuận tiện cho việc viết các container hoạt động cho nhiều loại, bạn sử dụng các mẫu, đó là các bản thiết kế được trình biên dịch khởi tạo khi cần thiết cho các loại khác nhau. Bạn sẽ cấm sử dụng các mẫu (và macro) và đi theo lộ trình C của việc viết cùng một mã vùng chứa cho các loại khác nhau hay sử dụng các con trỏ void? (Đợi đã, Java không có con trỏ trống!) Bạn có chắc chắn điều này sẽ tăng khả năng bảo trì không?

Một ngôn ngữ tốt có vô số tính năng được thiết kế để làm việc cùng nhau. Bằng cách cấm các tính năng từ ngôn ngữ A vì ngôn ngữ B không có chúng, bạn đang làm tê liệt ngôn ngữ A, bởi vì bạn không đồng thời thêm các tính năng từ B làm cho B trở thành một tổng thể mạch lạc.

Điều đó không có nghĩa là bạn không được hạn chế các tính năng được phép của C ++. C ++ là một ngôn ngữ lớn, phát triển trong lịch sử, nhấn mạnh cho phép lập trình viên thực hiện những gì anh ta muốn trên sự an toàn và dễ sử dụng, và không phải tất cả các tính năng của nó trong tất cả sự linh hoạt của họ là cần thiết để xây dựng các chương trình tốt. Có nhiều tiêu chuẩn mã hóa hạn chế sử dụng một số tính năng; ví dụ: các nguyên tắc của Google chủ yếu cấm nhiều kế thừa, các mẫu phức tạp và ngoại lệ (mặc dù đó là nguyên tắc cuối cùng là vì lý do lịch sử). Nhưng không có tính năng nào bị cấm "vì Java không có tính năng này"; các tính năng được xem xét trong khuôn khổ của C ++.


27
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. C ++ hiện đại chính xác hơn rất nhiều vì nó sử dụng các tính năng đó. Vâng, nó làm cho nó thậm chí khác nhau hơn.
Jan Hudec

17
Lưu ý rằng C ++ cuối cùng không có khối, nhưng nó có RAII, tốt hơn cho hầu hết các trường hợp. Và, một lần nữa, khác nhau.
Jan Hudec

7
Java Objectlà khá nhiều void*cho hầu hết các sử dụng - Tuy nhiên, yuck.
Quentin

1
Ngoài sự lựa chọn của các tính năng, còn có vấn đề về phong cách và thành ngữ. Các chương trình thường dễ đọc và duy trì hơn nếu chúng sử dụng các thành ngữ thông thường cho ngôn ngữ mà chúng được viết. Ngay cả khi người ta có thể viết một phần của chương trình C ++ chỉ sử dụng các tính năng giống như Java, thì kết quả sẽ là C ++ kỳ lạ, cứng nhắc.
Patricia Shanahan

2
Tôi sẽ đưa ra câu trả lời này để đi đúng hướng ("không làm điều đó"), nhưng tôi không thể chịu được tiền đề cơ bản rằng Java bằng cách nào đó "tiến bộ hơn" so với C ++. C ++ không cần trình thu gom rác hoặc phân cấp đối tượng một gốc, giống như cách Java không cần ... err ... xin lỗi tôi không biết làm thế nào để kết thúc câu, vì tôi bỏ lỡ các hàm hủy xác định trong Java và finallykhông phải là một sự thay thế cho họ. Hai ngôn ngữ chỉ khác nhau về cơ bản .
DevSolar

25

Tôi đã tranh luận về việc có nên đăng một câu trả lời khác hay không khi bạn đã có một con số đạt được kết luận dường như hoàn toàn hợp lý: ý tưởng của bạn về cơ bản là một thảm họa đang chờ xảy ra. Tôi nghĩ, tuy nhiên, họ đã không chỉ ra một số lý do có liên quan cao đằng sau kết luận đó.

Sự khác biệt giữa Java và C ++ chạy nhiều sâu hơn các chi tiết trên đó bạn dường như đã tập trung.

Ví dụ, bạn nói về việc cấm nhiều kế thừa trong C ++. Đầu tiên, tôi sẽ chỉ ra rằng điều này chỉ đơn giản là thiếu điểm. Java định nghĩa "giao diện" là những thứ riêng biệt với "các lớp". Một lớp kế thừa từ chỉ một lớp khác, nhưng có thể thực hiện một số lượng giao diện tùy ý.

C ++ không tách rời hai khái niệm theo cách đó. C ++ tương tự gần nhất cung cấp để thực hiện một giao diện trong Java đang kế thừa từ một lớp khác. Như vậy, để giữ cho hai liên kết hợp lý hoàn toàn, bạn có thể cần phải sử dụng nhiều kế thừa trong C ++, nhưng bạn muốn hạn chế một số các lớp cơ sở đó theo cách tương tự như Java hạn chế giao diện so với một lớp (về cơ bản là nó chỉ định chữ ký hàm, nhưng, ít nhất là, không triển khai).

Điều đó hầu như không làm trầy xước bề mặt của sự khác biệt thực sự giữa hai người. Trong thực tế, nơi mã Java có khả năng xác định các giao diện và các lớp thực hiện các giao diện đó, mã C ++ có nhiều khả năng xác định một số mẫu sẽ hoạt động với bất kỳ lớp nào đáp ứng các yêu cầu của nó (không chỉ các lớp được xác định cụ thể để thực hiện giao diện (s) nó chỉ định).

Nếu bạn thực sự muốn mã về cơ bản là "Java sử dụng cú pháp C ++", bạn gần như chắc chắn sẽ phải cấm mọi thứ và mọi thứ tương tự như sau. Bạn sẽ cần hạn chế việc sử dụng các mẫu của mình ở mức gần bằng "thùng chứa T" mà các tổng quát Java hỗ trợ. Thật không may, làm điều đó sẽ dẫn đến mã C ++ là một mớ hỗn độn mà không ai có thể duy trì nó như hiện tại, chưa kể đến khả năng lâu dài là dịch nó sang một số ngôn ngữ lập trình khác.

Nếu bạn thực sự muốn mã có thể được chuyển đổi sang một số ngôn ngữ khác trong tương lai, hãy cố gắng làm cho nó sạch và dễ đọc nhất có thể. Lý tưởng là viết mã giả và vẫn thực thi nó. Các cách tiếp cận C ++ hiện đại được viết tốt, lý tưởng chặt chẽ hơn nhiều so với tập hợp con mà bạn đề xuất. Bất kể bạn viết nó như thế nào, nếu bạn từng dịch sang Java, bạn sẽ phải thực sự dịch mã, không chỉ là cú pháp của các câu lệnh riêng lẻ.


Nhiều tính năng C ++ có thể được sử dụng theo một số cách ánh xạ độc đáo đến các khái niệm Java và các cách khác không có. Một số phần của chương trình sẽ yêu cầu một cái gì đó nằm ngoài tập hợp con chồng chéo của chức năng của các ngôn ngữ và cố gắng viết các phần như "Java sử dụng cú pháp C ++" sẽ mang lại một mớ hỗn độn khủng khiếp. Mặt khác, nhiều phần khác của mã có thể cần bất cứ thứ gì ngoài tập hợp con được chia sẻ và cố gắng ở trong phần được chia sẻ cho các phần của mã mà không có lý do thuyết phục nào để đi ra ngoài nó có thể hữu ích.
supercat

Có lẽ là nơi bạn nói "có thể cần", bạn thực sự có nghĩa là: "có thể không cần"? Giả sử như vậy, thì tôi có xu hướng đồng ý.
Jerry Coffin

Vâng Nếu cần hỗ trợ một nền tảng hỗ trợ Java nhưng không phải C ++, các phần của mã gần như chắc chắn sẽ phải được viết lại từ đầu và sẽ không có vấn đề gì nếu các phần đó được viết bằng một số kỹ thuật thân thiện với Java, vì chúng ' Dù sao cũng sẽ được viết lại. Có thể viết các phần khác, tuy nhiên, theo cách cho phép chúng được di chuyển mà không cần viết lại đầy đủ, và trong một số trường hợp, chi phí thêm cần thiết để làm như vậy có thể là tối thiểu.
supercat

4
@supercat: OTOH, với số lượng nền tảng hỗ trợ Java nhưng không phải C ++, điều này gây ấn tượng với tôi gần như hoàn toàn là một giải pháp trong việc tìm kiếm một vấn đề.
Jerry Coffin

Trong một thời gian, hỗ trợ trình duyệt cho các applet Java tốt hơn so với các applet C ++. Tuy nhiên, hỗ trợ trình duyệt cho JavsScript (không liên quan đến Java), tuy nhiên, đã cải thiện đủ để về cơ bản nó được tiếp quản từ cả hai.
supercat

11

Nếu bạn định viết mã bằng ngôn ngữ X, hãy dành thời gian để học ngôn ngữ đúng cách và sử dụng tất cả các tính năng mà nó cung cấp để giúp bạn giải quyết vấn đề. Những điều tồi tệ xảy ra khi bạn cố gắng thực hiện một bản dịch "từ cho từ" từ ngôn ngữ này sang ngôn ngữ khác, cho dù đó là tiếng Nhật sang tiếng Anh hay Java sang C ++. Tốt hơn hết là bắt đầu với một sự hiểu biết tốt về vấn đề và diễn đạt giải pháp theo cách tự nhiên nhất cho ngôn ngữ đang được sử dụng.

Cách đây nhiều năm, tôi thấy một chương trình C không có thụt đầu dòng và mọi câu lệnh bắt đầu trong cột 7, bởi vì tác giả của mã là một lập trình viên Fortran tình cờ sử dụng C. Các lập trình viên Fortran khác lo lắng về những điều mới lạ này được gọi là con trỏ. Tôi không muốn nhắc đến con trỏ đến con trỏ, tôi nghĩ họ sẽ bị ngất ngay tại chỗ.

Hãy tưởng tượng việc thuê ai đó để duy trì mã này trong tương lai. Nếu đó là mã C ++ tốt, bạn sẽ có thể thuê một nhà phát triển C ++ có năng lực và họ sẽ có thể tìm đường. Nếu đó là "Java trong C ++", thì cả nhà phát triển C ++ và Java sẽ không dễ hiểu mã.


7

Tất cả lý do của bạn có thể bị từ chối:

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 đó không có nghĩa là tính năng này không tốt (không có tính năng nào có thể xấu cả). Nó chỉ có nghĩa là tính năng này thường xuyên bị sử dụng sai (hoặc không thể thực hiện do các khái niệm cơ bản, như con trỏ trực tiếp so với bộ sưu tập rác). Java theo định nghĩa là nhằm mục đích dễ dàng hơn và thân thiện với lập trình viên hơn, do đó loại bỏ các tính năng tự chứng minh là dễ sử dụ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.

Ồ có thể chứ? Hãy xem mã C ++ đơn giản nhất:

int len = mystring->size();

Rất tiếc, không có tính năng "đặc thù ngôn ngữ" nào được sử dụng, nhưng nó đã không thể nhận ra bởi các nhà phát triển Java! Bởi vì trong Java, bạn phải tuân theo "." trong khi ở đây là "->.

Bạn có thể được yêu cầu chuyển đổi mã sang Java một ngày nào đó

Hoặc C #. Hoặc Haskell. Hoặc Python. Hoặc Ruby. Hoặc COBOL (vâng, bạn có thể!). Làm thế nào bạn có thể nói với tương lai?

Mã không có các tính năng cụ thể của C ++ thường dễ bảo trì hơn.

Hoàn toàn ngược lại. Mỗi tính năng được giới thiệu để làm cho việc lập trình dễ dàng hơn do đó dễ bảo trì hơn. Vd: lấy một chương trình hoạt động trên phao. Bây giờ nâng cấp nó để xử lý số phức. Người vận hành quá tải để giải cứu!

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 đề.

Nhưng Java DOES có nhiều kế thừa! Nó được gọi là "giao diện". Việc triển khai Java là một cách giải quyết có vấn đề để tránh viên kim cương đáng sợ gây ra bởi mọi thứ bắt nguồn từ đó Object. Nó được thực hiện bằng cách giới thiệu interfacemục đích duy nhất là trở thành thứ gì đó không xuất phát từ đó Object. C ++ không bao giờ có vấn đề này - không có cơ sở chung bắt buộc để mọi lớp có thể hoạt động như một giao diện mà không cần kim cương đáng sợ.

Lưu ý bên lề: Java gần đây đã giới thiệu ... các phương thức cụ thể trong các giao diện. Đã thêm một tính năng C ++ luôn phải giải quyết một vấn đề chưa từng có.

Bạn cũng chỉ đề cập rất ít "những thứ mà C ++ có nhưng Java thì không". Một trong những khác biệt lớn nhất giữa C ++ và Java là kiểm soát bố cục bộ nhớ. Bạn có thể tạo mảng con trỏ tới các đối tượng (giống như trong Java) HOẶC bạn có thể tạo khối bộ nhớ liền kề. Bây giờ, nếu tôi lo lắng về một tính năng C ++ có thể đánh lừa các nhà phát triển Java, thì thứ gì đó ẩn và tinh tế như cái này sẽ xếp hạng trong danh sách của tôi cao hơn nhiều so với những điều rõ ràng và dễ nhận biết trước tiên như nhiều toán tử thừa kế hoặc quá tải.

Dòng dưới cùng: Mã sạch là mã sạch. Java hoặc C ++ - sự khác biệt giống nhau. Chỉ cần giữ cho nó đơn giản. Các biến chứng không cần thiết là nguyên nhân hàng đầu của mã xấu.


Java cung cấp một số tính năng và đảm bảo sẽ không thể hỗ trợ bằng ngôn ngữ cung cấp tất cả các tính năng của C ++. Ví dụ, một ngôn ngữ không thể cho phép tải kiểu động và toàn bộ phạm vi bảo toàn danh tính của Java trong khi cung cấp các hình thức tổng quát của nhiều kế thừa có trong C ++.
supercat

@supercat Tôi không hiểu tại sao bạn lại nói điều này ở đây. Câu hỏi không phải là về các tính năng Java không thể được sao chép trong C ++, mà là về các tính năng C ++ mà Java đã loại bỏ.
Đặc vụ_L

Quan điểm của tôi là một số tính năng trong Java không có trong C ++, mà là một số tính năng của Java về cơ bản không tương thích với các tính năng khác có trong C ++, vì vậy không ngôn ngữ nào có thể có loại hỗ trợ cả hai ngôn ngữ như C ++ / CLI có các loại hỗ trợ các tính năng C ++ và các loại hỗ trợ các tính năng Java-ish, nhưng chúng có hiệu quả cư trú trong các vũ trụ riêng biệt với khả năng tương tác hạn chế).
supercat

6

Không, nói chung bạn không nên viết C ++ như Java và bạn chắc chắn không nên bỏ qua các tính năng ngôn ngữ C ++ không có trong Java.

Đối với một điều, Java là rác được thu thập và do đó không có từ khóa "xóa" C ++. Được rồi, vì vậy bạn thực hiện một chương trình mà không xóa, bởi vì theo quy tắc của bạn, nó không được phép.

Xin chúc mừng, bây giờ bạn có một rò rỉ bộ nhớ;). Đó cũng không phải là lý thuyết - Tôi đã thấy tình huống chính xác này xảy ra trong một trò chơi nguồn mở.

Tương tự, Java không có bất cứ thứ gì khá giống như con trỏ C ++, quy định rất nhiều quy ước gọi hàm phổ biến.

Có những tính năng của C ++ mà bạn có thể nên tránh (xem bên dưới), nhưng "không có trong Java" không phải là một thử nghiệm giấy quỳ tốt.


Hướng dẫn tốt hơn sẽ là như sau:

  1. Viết mã phù hợp với ngôn ngữ, môi trường và công cụ của bạn.
  2. Viết mã mà nhóm của bạn có thể hiểu.
  3. Hãy chắc chắn rằng nhóm của bạn có thẩm quyền trong lĩnh vực nhất định.

Mục (3) có nghĩa là bạn không nên có mã lập trình viên Java trong C ++ mà không đào tạo họ về C ++. Có một số khác biệt tinh tế nhưng rất quan trọng mà chúng có thể không học được nếu chúng cố gắng coi nó như một phương ngữ kỳ lạ của Java.

Mục (2) có nghĩa là, nếu nhóm của bạn đặc biệt không thoải mái với nhiều kế thừa (ví dụ) và nếu có một giải pháp thích hợp không sử dụng nó, thì tốt nhất nên sử dụng giải pháp thay thế đó. Tuy nhiên, điều này phụ thuộc vào nhóm của bạn cụ thể. Mặt khác, nếu nhóm của bạn khó chịu hơn với giải pháp thay thế đó hơn là với nhiều kế thừa, hãy sử dụng nhiều kế thừa!


Cuối cùng, có các tính năng ngôn ngữ của C ++ mà người ta nên tránh. Nếu bạn muốn biết những thứ này là gì, hãy hỏi các lập trình viên C ++ , thay vì lập trình viên của một ngôn ngữ khác. Một số ví dụ để bắt đầu là số học con trỏ (không có sự đồng thuận phổ quát) và goto.


6

Đã 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ỏ *newsử dụng #define New *new, hoặc tệ hơn, #define new *newnhư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, deletekhô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_ptrcông cụ này là gì? Các "gotchas" tinh tế là make_sharedgì? (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_ptrcó 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 đó Fookhi 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 ++rất nhiều các cạm bẫycụ 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:

  1. 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.
  2. 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 constexprcó để thực hiện đánh giá chức năng thời gian biên dịch, nhưng rõ ràng constexprlà 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 ++,


5
Tác giả FQA chắc chắn rơi vào nhóm "hiểu tối đa 20% ngôn ngữ". Có một vài câu trả lời thực sự sai, và cả đống câu nữa chỉ bỏ lỡ điểm, được minh họa bằng ống hút sau ống hút.
Ben Voigt

2
Nhiều (hầu hết tất cả?) Khiếu nại trong C ++ FQA là vô nghĩa. Ngôn ngữ hiện đại là rất lớn. C ++ khá nhỏ so với Python, Ruby, Perl và vâng, Java. Đặt một câu hỏi cơ bản trong các ngôn ngữ đó trên stackoverflow và câu trả lời đầu tiên gần như không thể tránh khỏi dọc theo dòng "Tại sao bạn không import SomeVeryBasicPackagevà chỉ làm điều này ?" Đặt một câu hỏi nâng cao và câu trả lời đầu tiên gần như chắc chắn dọc theo dòng "Tại sao bạn không import SomeMagicalPackagevà chỉ làm điều đó ?"
David Hammen

1
@DavidHammen Tôi nghĩ rằng phân tách 80/20 đề cập đến các tính năng ngôn ngữ cốt lõi, không chỉ các thành phần thư viện tiêu chuẩn, trong trường hợp các ngôn ngữ bạn đề cập, ngoại trừ Perl, thực sự không có vẻ lớn và phức tạp như C ++. Trong mọi trường hợp, đó là một phần rất nhỏ trong câu trả lời của tôi và tôi thừa nhận rằng đó là một nguồn thiên vị.
Kyle Strand

1
VM / ngôn ngữ được quản lý rõ ràng phức tạp hơn nhiều dưới bề mặt, nhưng ý tôi là phức tạp từ góc độ sử dụng.
Kyle Strand

1
Tôi không biết lý thuyết của bạn có đúng không, mặc dù trong trường hợp của tôi, tôi chắc chắn đã học riêng C ++ và C, và lớp C ++ của tôi thực sự khá kỹ lưỡng. Nhưng báo giá đầy đủ về 20/80 split là mỗi lập trình viên biết một khác nhau 20% ngôn ngữ, trong đó sẽ không thể được giải thích bởi hầu hết các lập trình viên được giảng dạy phần C của ngôn ngữ một cách độc lập. Dù sao, nếu bạn muốn giải thích chi tiết về cách C ++ cho phép lập trình mạnh mẽ hơn (tôi khẳng định tôi đã thấy trước đây nhưng không hiểu), có lẽ chúng ta nên làm điều đó trong phòng trò chuyện hoặc một cái gì đó thay vì trong các nhận xét ở đây .
Kyle Strand

5

Giả sử tôi bị giới hạn sử dụng C ++ bởi môi trường trong dự án. Có tốt không khi ngăn chặn việc sử dụng một số tính năng ngôn ngữ mà C ++ có nhưng Java không có (ví dụ: nhiều kế thừa, ghi đè toán tử)?

Không.

Nếu "theo môi trường của dự án", bạn bị giới hạn sử dụng C ++, thì có rất ít, nếu có, thậm chí nghĩ về bất kỳ công nghệ nào khác, bất kể bạn có thể thích / hy vọng sử dụng / truyền giáo nó đến mức nào.
Cho dù "Technology X" hay "Y" có hỗ trợ bất kỳ tính năng cụ thể nào không nên mang bất cứ điều gì trên con đường bạn xây dựng ứng dụng C ++ của mình.
Đó là một ứng dụng C ++, có lẽ là vì một số "Lý do chính đáng" (hiện tại hoặc trong quá khứ) vì vậy bạn nên viết nó dưới dạng một ứng dụng C ++, sử dụng bất cứ thứ gì mà "hộp công cụ" cụ thể cung cấp.

Nếu và khi có Yêu cầu chuyển ứng dụng sang một số công nghệ khác thì (và chỉ sau đó), bạn có thể xem xét các tính năng trên các nền tảng khác. Không có lý do gì "cắt mũi để làm cay khuôn mặt của bạn" nếu không có khả năng điều gì đó có thể xảy ra. Tuy nhiên, hãy nhớ rằng viết lại bán buôn là một hoạt động tốn kém, rủi ro mà Quản lý khó có thể thực hiện nếu không có Lý do rất chính đáng để làm điều đó.

Có một cuộc tranh luận tương tự ("sử dụng hay không sử dụng") vài năm trước trong Thế giới Visual Basic [.Net], nơi Ai đó có ý tưởng sáng sủa rằng bạn nên viết các ứng dụng Visual Basic mà không cần sử dụng bất kỳ [ngôn ngữ cốt lõi] nào chức năng được cung cấp bởi không gian tên Microsoft.VisualBasic. Nó giống như cố gắng viết một ứng dụng C ++ mà không có không gian tên std ::; OK, điều đó là có thể nhưng tại sao trên trái đất, bất cứ ai trong tâm trí của họ sẽ bận tâm làm điều đó?


1
Đến điểm cuối cùng của bạn về Visual Basic: Vấn đề với các thư viện nhà cung cấp như vậy là chúng là độc quyền. Sử dụng chúng có nghĩa là xâu chuỗi bản thân với nhà cung cấp đó. Nhà cung cấp sẽ thích bạn bị xiềng xích, nhưng về lâu dài bạn sẽ không sử dụng: Bạn không thể sử dụng phần mềm của nhà cung cấp khác mà không viết lại mọi thứ liên quan đến chức năng cụ thể của nhà cung cấp. Bạn càng sử dụng chức năng cụ thể của nhà cung cấp, chi phí thay đổi nhà cung cấp càng cao, trao quyền cho nhà cung cấp của bạn để buộc thay đổi đối với bạn. Đó là một trong những lý do tại sao phần mềm miễn phí (như tự do!) Là một vấn đề lớn như vậy.
cmaster

Điều Microsoft.VisualBasickhông gian tên là một chút của một căng. Đã nhiều năm kể từ lần cuối tôi sử dụng nó, nhưng ít nhất là vào lúc đầu, nó chủ yếu nhằm mục đích tương thích ngược với VB6 (và / hoặc để làm cho các lập trình viên VB6 cảm thấy "ở nhà"); nó chủ yếu cung cấp chức năng đã có sẵn trong phần còn lại của khung ở dạng hiện đại hơn (và tích hợp tốt hơn), vì vậy trong các dự án mới, hiếm khi có ý nghĩa sử dụng nó. Ngược lại, std::không gian tên là nơi chứa toàn bộ thư viện tiêu chuẩn - tránh nó sẽ giống như tránh toàn bộ BCL trong .NET.
Matteo Italia

2

Tất cả các câu trả lời hiện tại đều nói rằng đây là một điều tồi tệ, vì bạn nên tận dụng ngôn ngữ bạn đang sử dụng và cũng giải thích lý do tại sao một tính năng C ++ không phải là Bad bad chỉ vì nó không hoạt động. Tôi sẽ trả lời điều này từ một góc độ khác.

Đó là một điều để tránh tính năng C ++ phức tạp như nhiều kế thừa, toán tử quá tải và xác định mẫu của riêng bạn.

Nhưng bất kỳ vấn đề nào làm nhiều hơn nhiệm vụ đơn giản nhất:

  • phân bổ bộ nhớ,
  • kết nối số tiền đó với nhau bằng điểm
  • xây dựng cấu trúc dữ liệu
  • sau đó cho phép bộ nhớ được sử dụng lại khi an toàn để làm như vậy

Không có một tập hợp con phổ biến nào của Java và C ++ cho phép ở trên, do đó, những gì bạn đang yêu cầu là không thể thực hiện được. (Nếu bạn hỏi về Java và C #, bạn sẽ có cơ hội tốt hơn rất nhiều, vì cả hai đều sử dụng công cụ thu gom rác.)

Tuy nhiên, bạn có thể yêu cầu mã được viết để nhà phát triển Java có thể hiểu những gì được thực hiện (nhưng không phải là "cách thức" chi tiết) và điều này sẽ hợp lý.

Bạn cũng có thể thiết kế ngôn ngữ của riêng mình mà bạn đã triển khai trong cả C ++ và JAVA .....


0

Không ai nên viết bất kỳ mã nào mà các lập trình viên khác không hiểu. Nếu bạn nghĩ khóa ngôn ngữ là một vấn đề, hãy đợi cho đến khi bạn có khóa nhà phát triển. Một người có nhiều khả năng giữ bạn làm con tin hơn người kia.

Thực sự không có lý do kỹ thuật. Những gì bạn đã tạo là một kịch bản trong đó một ngôn ngữ được sử dụng vì bất kỳ lý do gì, nhưng nhiều nhà phát triển hiện tại và có thể trong tương lai không thực sự hiểu nó.

Tôi đoán là, các nhà phát triển Java có khả năng viết C ++ theo cách họ viết bằng Java, vậy tại sao lại biến nó thành quy tắc. Bạn có thể khám phá một số tính năng cụ thể của C ++, dễ thực hiện và duy trì hơn với một tài liệu / hướng dẫn C ++ nhỏ cho các nhà phát triển Java của bạn so với quả bóng lớn của mớ hỗn độn Java mà họ sẽ bị mắc kẹt.

Đây là một cuộc tranh luận về các vấn đề của các lập trình viên BASIC chuyển sang các ngôn ngữ hướng đối tượng. Không phải là họ thực hiện các thực hành OOP gây bất lợi cho các nhà phát triển mới, những người không hiểu nó, mà là họ không thực hiện nó. Nếu họ làm, họ thường nhận được nó sai. Nếu một cái gì đó được thực hiện kém, nó cần phải được loại bỏ bất kể lý do.

Khác với ai đó chỉ sao chép và dán mã một cách mù quáng, họ sẽ làm điều đó trong nhiều lĩnh vực mà họ không hiểu.

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.