มีคำตอบอื่น ๆ อยู่บ้าง แต่ฉันต้องการที่จะให้คำตอบที่สมบูรณ์ยิ่งขึ้นโดยตอบคำถามและข้อความของคุณทีละรายการ
หาก Java ไม่มีคุณสมบัติที่ C ++ แสดงว่าคุณสมบัตินั้นไม่ดีดังนั้นเราจึงควรป้องกันไม่ให้ใช้งาน
นี่เป็นคำตอบที่ค่อนข้างดี: Java ไม่ได้เป็น "ส่วนที่ดี" ของ C ++ และไม่มีเหตุผลที่จะคิดเช่นนั้น
โดยเฉพาะอย่างยิ่งถึงแม้ว่าข้อดีของแต่ละคุณสมบัติของ C ++ นั้นจะเป็นที่ถกเถียงกันอยู่ แต่คุณสมบัติหลายอย่างของ C ++ 11 / C ++ 14 ที่ไม่ได้เป็นส่วนหนึ่งของ Java นั้นไม่จำเป็นต้องถูกแยกออกเพราะนักออกแบบ Java คิดว่าพวกเขาคิดไม่ดี เป็นกรณีตัวอย่างจนถึงรุ่น 8, Java ไม่มี lambdas แต่ได้รับการแนะนำให้รู้จักกับ C ++ ในมาตรฐาน C ++ 11 ก่อนหน้า Java 8 ข้อสันนิษฐานของคุณว่าคุณสมบัติ C ++ ที่หายไปจาก Java นั้นขาดหายไปจากการออกแบบเพราะพวกเขา "ไม่ดี" จะบอกเป็นนัย ๆ ว่า lambdas ในฐานะที่เป็นภาษานั้น "ไม่ดี" (สำหรับ LISPers ทุกหนทุกแห่ง อาจจะน่ากลัวพอที่จะได้ยินว่าคุณชอบ Java จริงๆ) แต่ตอนนี้นักออกแบบ Java ได้ใส่ Stamp of Approval (TM) ลงในลูกแกะดังนั้นพวกเขาจึงเป็นสิ่งที่ดี
การขุดลึกลงไปอีกเล็กน้อยแม้ใน Java 8 lambdas-as-closures นั้นไม่ยืดหยุ่นเท่ากับ lambdas ของ C ++ 14 แต่สิ่งนี้อาจเกิดจากข้อ จำกัด ทางสถาปัตยกรรมของ JVMมากกว่าการตัดสินใจอย่างมีสติว่าวิธียืดหยุ่นมากกว่านั้นไม่ดีจาก มุมมองการออกแบบภาษา
รหัส C ++ พร้อมคุณสมบัติเฉพาะ C ++ (เช่น: ฟังก์ชั่นเพื่อนหลายมรดก) สามารถดูแลรักษาหรือตรวจสอบโดยโปรแกรมเมอร์ C ++ เท่านั้น แต่ถ้าเราเขียน C ++ เช่น Java (โดยไม่มีคุณสมบัติเฉพาะภาษา C ++) โค้ดนั้นสามารถรักษาหรือตรวจสอบได้โดยทั้งสอง โปรแกรมเมอร์ C ++ และ Java
นี่คือสิ่งสำคัญที่ฉันต้องการตอบสนอง
การพูดอย่างกว้าง ๆ อาจมีค่าในการรับการตรวจสอบโค้ดจากโปรแกรมเมอร์ที่ไม่คุ้นเคยกับภาษาที่คุณใช้อย่างใกล้ชิด พวกเขาสามารถให้ข้อเสนอแนะที่มีคุณค่าเกี่ยวกับความชัดเจนของชื่อฟังก์ชั่น / วิธีการและความคิดเห็นของคุณและ (ตามคำถามของคุณแสดงถึงอย่างถูกต้อง) หากภาษานั้นคล้ายกับภาษาอย่างน้อยหนึ่งภาษาที่พวกเขารู้อยู่แล้ว และอาจตรวจจับข้อผิดพลาดเชิงตรรกะ
อย่างไรก็ตามไม่ใช่กรณีที่การตรวจสอบประเภทนี้จะ "ดีเท่า" หรือ "เทียบเท่ากับ" การตรวจสอบจากนักพัฒนาซอฟต์แวร์ที่รู้ภาษาที่คุณใช้จริง ๆ โดยพื้นฐานแล้วนี่เป็นเพราะการทำให้ภาษาหนึ่งดูเหมือนภาษาอื่นมักจะซ่อนความแตกต่างเล็กน้อยขณะที่การทำให้ภาษาหนึ่งประพฤติอย่างอื่น (โดยเฉพาะอย่างยิ่งในกรณีของ C ++ และ Java) อาจไม่เป็นไปตามสำนวนภาษา สำหรับผู้ตรวจสอบ
ก่อนอื่นลองคิดดูว่ามันจะทำให้ C ++ มีลักษณะอย่างไร "Java ในกรณีง่าย ๆ คุณสามารถใช้new
เพื่อยกตัวอย่างวัตถุได้เหมือนกับใน Java:
Foo foo = new Foo();
แต่ออบเจ็กต์นั้นใช้วิธีนี้->
แทนการใช้.
เมธอด call ดังนั้นหากคุณต้องการให้เมธอดcallดูเหมือน Java คุณต้องเขียนแทน:
Foo& foo = *new Foo();
แต่นี่ไม่ใช่เรื่องจริง โดยเฉพาะอย่างยิ่งหน่วยความจำจะต้องต่อมาจะมีการทำความสะอาดขึ้นใช้delete &foo
ซึ่งบางคนมีประสบการณ์ c ++ devs อาจไม่ได้ตระหนักถึงความเป็นรหัสทางกฎหมาย ทั้งสองวิธีมีตลกสัญลักษณ์ไม่ใช่ Java เหมือนโรยตลอดดังนั้นเราจึงไม่สามารถค่อนข้างทำให้ภาษา "มีลักษณะเหมือน" Java (คุณสามารถกำจัด*new
โดยใช้#define New *new
หรือแย่กว่า#define new *new
นั้น แต่คุณแค่ขอให้เพื่อนร่วมงานของคุณเกลียดคุณ) และตามที่กล่าวไว้ข้างต้นdelete
ไม่มีอยู่ใน Java ดังนั้นไม่ว่าในกรณีใด (ตามที่กล่าวไว้ในคำตอบอื่น ) คุณไม่สามารถทำให้การใช้งานวัตถุ "ดู" อย่างที่มันทำในจาวาโดยปราศจากการรั่วไหลของหน่วยความจำ
แต่ C ++ ที่ทันสมัยนั้นรวมถึงพอยน์เตอร์ที่ใช้ร่วมกันอย่างชาญฉลาดซึ่งทำหน้าที่เหมือนกับการอ้างอิงตัวแปรที่จัดการโดยหน่วยความจำของ Java ดังนั้นทุกที่ใน Java ที่คุณสามารถเขียนFoo foo = new Foo();
คุณสามารถเขียนแทน:
std::shared_ptr<Foo> foo = std::make_shared<Foo>();
ตอนนี้คุณกำลังใช้ฟีเจอร์ภาษาที่เหมือนกับ Java อยู่ใต้กระโปรงหน้ารถ แต่ทันใดนั้นคุณมีอะไรหลายอย่างที่ต้องอธิบายให้ผู้ตรวจสอบที่ไม่ใช่ C ++: สิ่งนี้คือshared_ptr
อะไร อะไร "gotchas" ที่ละเอียดอ่อนของmake_shared
คืออะไร? (มันใช้การส่งต่อที่สมบูรณ์แบบซึ่งมีบางกรณีที่ล้มเหลวและสามารถนำไปสู่การเรียกใช้คอนสตรัคเตอร์ "ผิด") ทำไมต้องทำการเรียกเมธอดด้วย->
แต่การใช้.
กับเมธอดบางตัวอนุญาตโดยคอมไพเลอร์? ( shared_ptr
มีวิธีการของตัวเอง.) หากวิธีการที่Foo::reset(void)
มีอยู่นักพัฒนาไม่ระวังอาจจะพยายามที่จะเรียกมันด้วยfoo.reset()
ซึ่ง (ถ้ามีเพียงหนึ่งชี้ตัวชี้ที่ใช้ร่วมกันเช่นว่าFoo
เมื่อมีการโทรเกิดขึ้น) จะลบหน่วยความจำพื้นฐานและลบล้างfoo
และ นักพัฒนา Java ไม่น่าจะพบปัญหานี้
นอกจากนี้C ++มีจำนวนมากของข้อผิดพลาดที่มีเฉพาะกับภาษา. อย่างที่ฉันบอกได้ผู้พัฒนา C ++ ส่วนใหญ่เรียนรู้ที่จะจัดการกับข้อผิดพลาดเหล่านี้โดยค่อยๆพัฒนาสำนวนของตัวเองสำหรับการปฏิบัติ C + + ที่ปลอดภัยซึ่งมักจะเป็นเอกลักษณ์ของพวกเขาหรือทีมพัฒนาของพวกเขา (ดูตัวอย่างคำตอบที่มีอยู่ แนวทางปฏิบัติในการเขียนโค้ดของ Google และความคิดเห็นเกี่ยวกับเรื่องนี้ระบุว่า "ทหารผ่านศึก C ++ เก๋ามักจะปฏิเสธแนวทางการเข้ารหัสของ Google") ทุกคนอ้างว่าภาษานั้นอาจซับซ้อนเกินไปดูเหมือนว่า (อย่างน้อยประสบการณ์ของฉัน) มักจะพบกับรูปแบบของ "ดีหยุดใช้ผิดเลย" ผมทราบดีว่านี่เป็นมุมมองเชิงลบอย่างมากของ C ++ ชุมชนและมีแน่นอนพัฒนาที่มีประสบการณ์มีความเต็มใจที่จะช่วยออกภาษาเรียน แต่มีไม่ ดูเหมือนว่าจะมีการป้องกันบางอย่างเกี่ยวกับพฤติกรรมที่ไม่ได้กำหนดเช่น (ดูตัวอย่างของการสนทนาในลิงก์ 'ผิดพลาด' ของฉันด้านบน)
นักพัฒนา Java จะไม่เป็นประโยชน์ในการค้นหาและแก้ไขข้อผิดพลาดเหล่านี้ผ่านการตรวจสอบโค้ด
คุณอาจถูกขอให้แปลงรหัสเป็น Java ในบางวัน
ถูกต้องทั้งหมด - น่ายกย่องแม้ - ลองพิจารณาสิ่งที่อาจเกิดขึ้นกับรหัสของคุณในอนาคตในขณะที่คุณอยู่ในขั้นตอนการออกแบบ
แต่ก่อนอื่นข้อพิจารณานี้ดูเหมือนว่ามีความเป็นไปได้จากระยะไกล: รหัสมักจะถูกนำมาใช้ใหม่ตามที่เป็นอยู่ (ตัวอย่างเช่นคุณสามารถเสียบรหัส C ++ บางส่วนหรือทั้งหมดที่ทำงานลงในซอฟต์แวร์ Java ในอนาคตโดยใช้อินเตอร์เฟส JNI) หรือเขียนใหม่ทั้งหมด กว่า "คัดลอก" โดยตรงด้วยตนเอง
และสองคุณพูดในภายหลัง
คุณลักษณะเฉพาะภาษา C ++ ทุกตัว (เช่น: การสืบทอดหลายอย่าง) ควรมีทางเลือกที่จะนำไปใช้ใน Java ...
สิ่งนี้จะยกเลิกจุด "แปลงเป็น Java" ของคุณ หากซอฟต์แวร์เขียนด้วย idiomatic C ++ จากนั้นแปลงเป็น idiomatic Java ก็ไม่มีเหตุผลที่จะคาดหวังว่าการแปลงนี้จะทำได้ (หรือทำได้!) โดยการใช้การแมปแบบหนึ่งต่อหนึ่งที่แม่นยำของคุณสมบัติ C ++ กับคุณสมบัติ Java
รหัสที่ไม่มีคุณสมบัติเฉพาะ C ++ มักจะสามารถบำรุงรักษาได้มากกว่า
ไม่ชัดเจนว่าคุณหมายถึงอะไรที่นี่ แต่จริง ๆ แล้วฉันเห็นด้วยกับส่วนนี้: เว้นแต่คุณจะระมัดระวังมากและแม้ว่าคุณจะระมัดระวังคุณลักษณะ C ++ สามารถนำไปสู่ปัญหาการบำรุงรักษา c ++ FQA Lite (เว็บไซต์ที่สำคัญของภาษาและสมัครพรรคพวกของตนจากคนที่อย่างน้อยดูเหมือนจะเข้าใจจริงๆแล้วมันค่อนข้างดี) ระบุว่า
... 80% ของผู้พัฒนาเข้าใจมากที่สุด 20% ของภาษา มันไม่เหมือนกันกับ 20% สำหรับคนที่แตกต่างกันดังนั้นอย่าหวังให้พวกเขาเข้าใจรหัสของกันและกัน
โปรดทราบ:หากคุณเป็นแฟน C ++ และคุณมาถึงจุดนี้ในคำตอบของฉันและรู้สึกอยากจะกระโดดลงไปที่ความคิดเห็นเพื่อยืนยันว่าผู้เขียน FQA ไม่เข้าใจจริง ๆ C ++ หรือขัดแย้งกันมากในข้อโต้แย้งของเขา โปรดทราบว่า (1) สองประโยคหลังจากที่ฉันอ้างถึงเขาฉันยอมรับว่า FQA เป็นแหล่งที่มีอคติมากและ (2) ไม่สำคัญเลยสำหรับสิ่งที่ฉันพยายามจะพูดว่าผู้เขียน FQA เข้าใจ C ++ หรือไม่ และฉันไม่ได้พยายามทุบตี C ++ และคุณควรอ่านส่วนที่เหลือของโพสต์โดยไม่คิดว่าฉันต่อต้าน C-C เพียงเพราะฉันอ้างถึง FQA จบโน้ต
ในทำนองเดียวกัน Linus Torvalds เกลียด C ++ ด้วยเหตุผลนี้ (คำเตือน: ลิงก์เกี่ยวข้องกับการสบถจำนวนมากในสไตล์ Linus ที่น่าอับอายอย่างแท้จริง)
เห็นได้ชัดว่าสิ่งเหล่านี้มีความลำเอียงอย่างมากในเรื่องนี้ แต่ผู้สนับสนุน C ++ มักบอกว่าคุณไม่ควรใช้ชุดคุณลักษณะภาษาทั้งหมด (อีกครั้งดูแนวทางการเข้ารหัสของ Google เช่นกัน Bjarne Stroustrup ผู้สร้าง C ++ ได้กล่าวต่อสาธารณชนว่า "ภายใน C ++ มีภาษาที่เล็กกว่าและสะอาดกว่าที่พยายามจะออกไป")
ดังนั้นฉันคิดว่ามีข้อดีบางอย่างกับความคิดที่ว่าคุณสมบัติ C ++ อาจง่ายเกินไปที่จะใช้ในทางที่ผิดโดยเฉพาะอย่างยิ่งถ้าคุณมาจากพื้นหลัง Java นอกจากนี้ยังมีข้อดีตรงที่ความคิดในการบรรเทาปัญหาเหล่านี้ด้วยการ จำกัด ตัวเองให้เป็นบางส่วนของภาษา
อย่างไรก็ตามการตัดสินใจว่าจะใช้ชุดย่อยใดบนพื้นฐานของภาษาที่แตกต่างกันจะไม่เหมือนกับวิธีการใช้ที่ถูกต้องเว้นแต่ว่า "ภาษาที่แตกต่าง" คือ C เนื่องจากมีเซตย่อยคล้าย C ของภาษา C ++ (Linus อ้างถึงสิ่งนี้ในการพูดจาโผงผางของเขาข้างต้นและ Scott Meyers อ้างถึงเซตย่อยนี้ว่า "sub-language") กระบวนทัศน์เวลาทำงานของ Java (เก็บขยะ, ทำงานบน VM) นั้นแตกต่างอย่างมากจาก C ++ ไม่ชัดเจนว่ามีบทเรียนใด ๆ ที่มีประโยชน์ในการวาดเกี่ยวกับการใช้งาน C ++ จากมันและดังที่ได้กล่าวไว้ข้างต้นการพยายามวาดบทเรียนเกี่ยวกับ C ++ โดยตรงจาก Java สามารถนำไปสู่
ให้ลองกำหนด "ชุดย่อยที่ยอมรับได้" ของภาษาแทนเพื่อทำความเข้าใจว่าภาษานั้นสามารถใช้สำนวนได้อย่างไร หากคุณต้องการเซตย่อยที่ค่อนข้าง จำกัด ซึ่งยังคงใช้ประโยชน์จากคุณสมบัติของ C ++ มากมายนอกเหนือจาก C ที่มีให้บริการแนวทางการเขียนโค้ด Google ดังกล่าวอาจเป็นจุดเริ่มต้นที่ดี แน่นอนคุณจะได้นักพัฒนาที่บอกว่ามี "ไม่มีเหตุผลโต้แย้ง" สำหรับข้อ จำกัด บางอย่างของ Googleแต่ถ้าคุณไม่ต้องการจ้าง Alexandrescu จากงานของเขาในภาษา D (ซึ่งตัวเองควรบอกคุณบางอย่าง) นั่นคือ อาจจะไม่เป็นไร แน่นอนว่าดีกว่าการพยายามเปลี่ยน C ++ เป็น Java
จุดเริ่มต้นที่ดีอีกประการสำหรับชุดโค้ดแนวทางคือC ++ Core Guidelines ใหม่ซึ่งเป็นงานที่อยู่ระหว่างดำเนินการโดย Bjarne Stroustrup และ Herb Sutter
วิธีเดียวที่จะจัดการกับข้อบกพร่องของ C ++ คือการเลือกภาษาอื่น ดูเหมือนว่าคุณชอบ Java และคุณคิดว่ามีโอกาสที่โครงการนี้อาจถูกแปลงเป็น Java ในที่สุด ดังที่ได้กล่าวไว้ในคำตอบอื่นคุณสามารถ ... เริ่มต้นด้วย Java
มีเหตุผลสองประการที่คุณอาจจำเป็นต้องใช้สิ่งอื่นที่ไม่ใช่ Java จริงๆ:
- คุณต้องการประสิทธิภาพการทำงานจริงๆ ในกรณีนี้การรักษา C ++ เหมือน Java อาจจะไม่ช่วยคุณได้จริง ๆ เพราะเทคนิคเหมือน Java เช่นตัวชี้ที่ใช้ร่วมกันจะทำให้ประสิทธิภาพการใช้งานของคุณลดลง
- คุณต้องใช้ซอฟต์แวร์เพื่อทำงานบนแพลตฟอร์มที่ไม่ชัดเจนซึ่งยังไม่รองรับ JVM ในกรณีนี้คุณอาจติดอยู่กับภาษาที่มีส่วนหน้าของ GCC หรือ Clang C และ C ++ เป็นตัวเลือกที่ชัดเจน แต่คุณสามารถดูได้เหมือนสนิม (ปลั๊กด่วน: ฉันไม่ได้ใช้ Rust อย่างกว้างขวาง แต่มันก็ดูดีมากและฉันกระตือรือร้นที่จะทำงานในโครงการ Rust ที่สำคัญโดยเร็วที่สุดเท่าที่จะทำได้และฉันคิดว่าทุกคนที่พิจารณาเริ่มโครงการ C ++ ควรพิจารณา Rust เป็นทางเลือก)
คุณลักษณะเฉพาะภาษา C ++ ทุกตัว (เช่น: การสืบทอดหลายอย่าง) ควรมีทางเลือกที่จะนำไปใช้ใน Java หากไม่เป็นเช่นนั้นหมายความว่ารูปแบบการออกแบบหรือสถาปัตยกรรมรหัสเป็นปัญหา
ฉันพูดถึงเรื่องนี้มาบ้างแล้ว แต่ฉันตั้งใจทิ้งประโยคที่สองของคุณไว้
ฉันไม่มั่นใจว่าสิ่งที่ชอบconstexpr
ซึ่งจะไม่สมเหตุสมผลในภาษา JIT บางส่วนเช่น Java เป็นตัวบ่งชี้สถาปัตยกรรมที่ไม่ถูกต้อง ฉันเปิดกว้างต่อความคิดที่ว่าการใช้เทมเพลตเมตาการเขียนโปรแกรมที่มากเกินไปอาจมีปัญหามากกว่าที่ควรเป็นโดยเฉพาะตอนนี้ที่constexpr
มีอยู่สำหรับการประเมินฟังก์ชั่นคอมไพล์เวลา แต่มันชัดเจนจากกรณีconstexpr
ที่ไม่มีข้อบกพร่องในการออกแบบคุณกำลังใช้งานอยู่: คุณเพียงแค่ทำให้แน่ใจว่าการคำนวณบางอย่างเกิดขึ้นก่อนที่จะเรียกใช้รหัสซึ่งเป็นการเพิ่มประสิทธิภาพที่ยอดเยี่ยม (ดูตัวอย่างสำหรับรายการนี้สำหรับปัญหา n-body ของ The Benchmark Gameซึ่งมีประสิทธิภาพเหนือกว่าทุกรายการยกเว้นรายการอื่น เขียนใน C ++