อะไรคือความแตกต่างระหว่างชนิด“ ทั่วไป” ใน C ++ และ Java


153

Java มี generics และ C ++ ให้รูปแบบการเขียนโปรแกรมที่แข็งแกร่งมากกับtemplates ดังนั้นอะไรคือความแตกต่างระหว่าง C ++ และ Java generics?


คำตอบ:


144

มีความแตกต่างใหญ่ระหว่างพวกเขา ใน C ++ คุณไม่จำเป็นต้องระบุคลาสหรือส่วนต่อประสานสำหรับประเภททั่วไป นั่นเป็นเหตุผลที่คุณสามารถสร้างฟังก์ชั่นและชั้นเรียนทั่วไปอย่างแท้จริงด้วยการพิมพ์ที่มีข้อบกพร่อง

template <typename T> T sum(T a, T b) { return a + b; }

วิธีการข้างต้นจะเพิ่มวัตถุสองชนิดที่เหมือนกันและสามารถใช้กับประเภท T ใด ๆ ที่มีเครื่องหมาย "+" อยู่

ใน Java คุณต้องระบุประเภทหากคุณต้องการเรียกใช้เมธอดบนวัตถุที่ส่งผ่านสิ่งที่ต้องการ:

<T extends Something> T sum(T a, T b) { return a.add ( b ); }

ใน C ++ ฟังก์ชั่น / คลาสทั่วไปสามารถกำหนดได้เฉพาะในส่วนหัวเนื่องจากคอมไพเลอร์สร้างฟังก์ชั่นที่แตกต่างกันสำหรับประเภทที่แตกต่างกัน (ที่มันถูกเรียกด้วย) ดังนั้นการรวบรวมจึงช้าลง ใน Java การคอมไพล์ไม่มีการลงโทษที่สำคัญ แต่ Java ใช้เทคนิคที่เรียกว่า "การลบ" ซึ่งประเภททั่วไปจะถูกลบที่ runtime ดังนั้นที่ runtime Java กำลังเรียก ...

Something sum(Something a, Something b) { return a.add ( b ); }

ดังนั้นการเขียนโปรแกรมทั่วไปใน Java จึงไม่มีประโยชน์จริงๆมันเป็นเพียงน้ำตาล syntactic เพียงเล็กน้อยเพื่อช่วยในการสร้าง foreach ใหม่

แก้ไข:ความเห็นข้างต้นเกี่ยวกับประโยชน์ถูกเขียนโดยตัวเองที่อายุน้อยกว่า ข้อมูลทั่วไปของ Java ช่วยด้วยประเภทความปลอดภัยแน่นอน


27
เขาถูกต้องอย่างสมบูรณ์ว่ามันเป็นเพียงน้ำตาล syntactic ที่ซับซ้อน
alphazero

31
มันไม่ใช่น้ำตาลซินแทคติค คอมไพเลอร์ใช้ข้อมูลนี้เพื่อตรวจสอบประเภท แม้ว่าข้อมูลจะไม่สามารถใช้งานได้ในขณะทำงาน แต่ฉันจะไม่เรียกสิ่งที่คอมไพล์ใช้เพียงอย่างเดียวว่า "syntactic sugar" ถ้าคุณจะเรียกมันว่าดีแล้ว C ก็แค่น้ำตาล syntactic เพื่อประกอบและนั่นก็แค่น้ำตาล syntactic สำหรับรหัสเครื่อง :)
dtech

42
ฉันคิดว่าน้ำตาลทรายมีประโยชน์
poitroae

5
คุณพลาดจุดสำคัญของความแตกต่างสิ่งที่คุณสามารถใช้เพื่อยกตัวอย่างทั่วไป ใน c ++ เป็นไปได้ที่จะใช้เทมเพลต <int N> และรับผลต่างกันสำหรับหมายเลขใด ๆ ที่ใช้ในการสร้างอินสแตนซ์ มันถูกใช้สำหรับการรวบรวม meta progaming เวลา เช่นเดียวกับคำตอบใน: stackoverflow.com/questions/189172/c-templates-turing-complete
stonemetal

2
คุณไม่ต้อง 'ระบุชนิด' ในรูปแบบของทั้งสองหรือextends superคำตอบไม่ถูกต้อง
มาร์ควิสแห่ง Lorne

124

Java Generics นั้นแตกต่างอย่างมากกับเทมเพลต C ++

โดยทั่วไปในเทมเพลต C ++ นั้นเป็นชุด preprocessor / มาโครที่ได้รับการยกย่อง ( หมายเหตุ:เนื่องจากบางคนดูเหมือนจะไม่สามารถเข้าใจความคล้ายคลึงได้ฉันไม่ได้บอกว่าการประมวลผลเทมเพลตเป็นมาโคร) ในจาวาพวกมันจะใช้น้ำตาลซินแทคติคเพื่อลดการหล่อของวัตถุ นี่คือที่ดีงามรู้เบื้องต้นเกี่ยวกับภาษา C ++ แม่ VS generics

หากต้องการอธิบายรายละเอียดเกี่ยวกับประเด็นนี้: เมื่อคุณใช้เทมเพลต C ++ คุณจะต้องสร้างสำเนาอีกชุดหนึ่งเหมือนกับว่าคุณใช้#defineมาโคร สิ่งนี้อนุญาตให้คุณทำสิ่งต่าง ๆ เช่นมีintพารามิเตอร์ในข้อกำหนดเทมเพลตที่กำหนดขนาดของอาร์เรย์และเช่น

Java ไม่ทำงานอย่างนั้น ใน Java วัตถุทั้งหมดมีขอบเขตจากjava.lang.Objectดังนั้น pre-Generics คุณจะต้องเขียนโค้ดดังนี้:

public class PhoneNumbers {
  private Map phoneNumbers = new HashMap();

  public String getPhoneNumber(String name) {
    return (String)phoneNumbers.get(name);
  }

  ...
}

เพราะประเภทคอลเลกชัน Java ทั้งหมดใช้ Object เป็นประเภทฐานเพื่อให้คุณสามารถใส่อะไรก็ได้ Java 5 หมุนไปรอบ ๆ และเพิ่มชื่อสามัญเพื่อให้คุณสามารถทำสิ่งต่าง ๆ เช่น:

public class PhoneNumbers {
  private Map<String, String> phoneNumbers = new HashMap<String, String>();

  public String getPhoneNumber(String name) {
    return phoneNumbers.get(name);
  }

  ...
}

และนั่นคือ Java Generics ทั้งหมด: wrappers สำหรับการคัดเลือกวัตถุ นั่นเป็นเพราะ Java Generics ไม่ได้รับการขัดเกลา พวกเขาใช้ลบประเภท การตัดสินใจนี้เกิดขึ้นเพราะ Java Generics เข้ามาช้าในส่วนที่พวกเขาไม่ต้องการทำลายความเข้ากันได้แบบย้อนหลัง (a Map<String, String>สามารถใช้งานได้ทุกครั้งที่มีการMapเรียกใช้) เปรียบเทียบสิ่งนี้กับ. Net / C # โดยที่ไม่ได้ใช้การลบประเภทซึ่งนำไปสู่ความแตกต่างทุกประเภท (เช่นคุณสามารถใช้ประเภทดั้งเดิมและIEnumerableและIEnumerable<T>ไม่เกี่ยวข้องกัน)

และคลาสที่ใช้ generics ที่คอมไพล์ด้วยคอมไพเลอร์ Java 5+ นั้นสามารถใช้งานได้บน JDK 1.4 (สมมติว่ามันไม่ใช้ฟีเจอร์หรือคลาสอื่นที่ต้องใช้ Java 5+)

นั่นเป็นเหตุผลที่ Java Generics เรียกว่าน้ำตาลซินแทคติ

แต่การตัดสินใจเกี่ยวกับวิธีการทำ generics นี้มีผลกระทบอย่างลึกซึ้งดังนั้นคำถามที่พบบ่อยเกี่ยวกับ Java Generics (สุดยอด) ได้เด้งขึ้นมาเพื่อตอบคำถามจำนวนมากที่ผู้คนมีเกี่ยวกับ Java Generics

เท็มเพลต C ++ มีคุณสมบัติจำนวนมากที่ Java Generics ไม่มี:

  • การใช้อาร์กิวเมนต์ชนิดดั้งเดิม

    ตัวอย่างเช่น:

    template<class T, int i>
    class Matrix {
      int T[i][i];
      ...
    }
    

    Java ไม่อนุญาตให้ใช้อาร์กิวเมนต์ชนิดดั้งเดิมใน generics

  • ใช้อาร์กิวเมนต์ชนิดเริ่มต้นซึ่งเป็นคุณลักษณะหนึ่งที่ฉันพลาดใน Java แต่มีเหตุผลด้านความเข้ากันได้ย้อนหลังสำหรับสิ่งนี้

  • Java อนุญาตการ จำกัด ขอบเขตของอาร์กิวเมนต์

ตัวอย่างเช่น:

public class ObservableList<T extends List> {
  ...
}

จำเป็นต้องเน้นว่าการเรียกใช้เทมเพลตที่มีอาร์กิวเมนต์ต่างกันเป็นประเภทที่แตกต่างกันจริงๆ พวกเขาไม่ได้แบ่งปันสมาชิกแบบคงที่ ใน Java นี่ไม่ใช่กรณี

นอกเหนือจากความแตกต่างกับยาชื่อสามัญเพื่อความสมบูรณ์นี่คือการเปรียบเทียบพื้นฐานของ C ++ และ Java (และอีกหนึ่ง )

และฉันยังสามารถแนะนำคิดใน Java ในฐานะโปรแกรมเมอร์ C ++ แนวคิดจำนวนมากเช่นวัตถุจะเป็นลักษณะที่สองอยู่แล้ว แต่ก็มีความแตกต่างกันเล็กน้อยดังนั้นมันจึงคุ้มค่าที่จะมีข้อความเกริ่นนำแม้ว่าคุณจะอ่านส่วน

สิ่งที่คุณจะได้เรียนรู้มากมายเมื่อเรียนรู้ Java คือไลบรารีทั้งหมด (ทั้งมาตรฐาน - สิ่งที่มาใน JDK - และไม่เป็นมาตรฐานซึ่งรวมถึงสิ่งที่ใช้กันทั่วไปเช่น Spring) ไวยากรณ์ของ Java เป็น verbose มากกว่า C ++ ไวยากรณ์และไม่มีคุณลักษณะ C ++ มากมาย (เช่นตัวดำเนินการมากไป, การรับมรดกหลายครั้ง, กลไกการทำลายล้าง ฯลฯ ) แต่นั่นก็ไม่ได้ทำให้ C ++ เป็นชุดย่อยอย่างเคร่งครัด


1
พวกเขาจะไม่เทียบเท่าในแนวคิด ตัวอย่างที่ดีที่สุดคือรูปแบบเทมเพลตที่เกิดขึ้นซ้ำ ๆ การออกแบบเชิงนโยบายที่ดีที่สุดอันดับสองคือ สิ่งที่ดีที่สุดที่สามคือความจริงที่ว่า C ++ อนุญาตให้มีการรวมตัวเลขจำนวนหนึ่งในวงเล็บเหลี่ยม (myArray <5>)
Max Lybbert

1
ไม่พวกเขาไม่เท่าเทียมกันในแนวคิด มีแนวคิดทับซ้อนกันบ้าง แต่ไม่มาก ทั้งสองอย่างอนุญาตให้คุณสร้างรายการ <T> แต่มันเกี่ยวกับเท่าที่จะทำได้ เทมเพลต C ++ ดำเนินต่อไปได้อีกมาก
jalf

5
Map map = new HashMap<String, String>สิ่งสำคัญที่จะทราบว่าประเภทการลบปัญหาวิธีการมากกว่าเพียงแค่ความเข้ากันได้ย้อนหลังสำหรับ หมายความว่าคุณสามารถปรับใช้รหัสใหม่ใน JVM เก่าและจะทำงานเนื่องจากความคล้ายคลึงกันใน bytecode
Yuval Adam

1
คุณจะทราบว่าฉันพูดว่า "โดยพื้นฐานแล้วเป็น preprocessor / แมโครที่ได้รับเกียรติ" มันเป็นการเปรียบเทียบเนื่องจากการประกาศเทมเพลตแต่ละรายการจะสร้างรหัสเพิ่มเติม (ตรงข้ามกับ Java / C #)
cletus

4
รหัสแม่แบบมากแตกต่างจากการคัดลอกและวาง หากคุณคิดในแง่ของการขยายตัวมาโครไม่ช้าก็เร็วคุณจะได้รับผลกระทบจากบั๊กที่ละเอียดอ่อนเช่นอันนี้: womble.decadentplace.org.uk/c++//
Nemanja Trifunovic

86

C ++ มีเทมเพลต Java มีข้อมูลทั่วไปซึ่งดูเหมือน sorta เหมือนแม่แบบ C ++ แต่พวกเขาแตกต่างกันมาก

เทมเพลตทำงานตามชื่อที่แสดงโดยจัดเตรียมเทมเพลตคอมไพเลอร์ด้วย (รอให้มัน ... ) ที่สามารถใช้ในการสร้างรหัสประเภทที่ปลอดภัยโดยการกรอกพารามิเตอร์ของเทมเพลต

Generics อย่างที่ฉันเข้าใจพวกมันทำงานในลักษณะอื่น ๆ : คอมไพเลอร์พารามิเตอร์ถูกใช้โดยคอมไพเลอร์เพื่อตรวจสอบว่าโค้ดที่ใช้พวกเขานั้นปลอดภัยต่อการพิมพ์ แต่โค้ดผลลัพธ์ถูกสร้างขึ้นโดยไม่มีประเภทเลย

คิดว่าเทมเพลต C ++ เป็นระบบมาโครที่ดีจริงๆและ Java generics เป็นเครื่องมือสำหรับสร้าง typecasts โดยอัตโนมัติ

 


4
นี่เป็นคำอธิบายที่กระชับดี หนึ่งบิดที่ฉันอยากจะทำคือ Java generics เป็นเครื่องมือสำหรับการสร้าง typecasts โดยอัตโนมัติที่รับประกันว่าปลอดภัย (มีเงื่อนไขบางอย่าง) ในบางวิธีที่พวกเขากำลังที่เกี่ยวข้องกับ c ++ const's วัตถุใน C ++ จะไม่ถูกแก้ไขผ่านconstตัวชี้ยกเว้นว่าconst-ness ถูก cast ออกไป ทำนองเดียวกันการปลดเปลื้องโดยนัยที่สร้างขึ้นโดยประเภททั่วไปใน Java รับประกันว่าจะ "ปลอดภัย" เว้นแต่ว่าพารามิเตอร์ประเภทจะถูกโยนทิ้งด้วยตนเองที่ใดที่หนึ่งในรหัส
Laurence Gonsalves

16

คุณสมบัติอื่นที่แม่แบบ C ++ มี Java generics ที่ไม่ได้เป็นความเชี่ยวชาญ ที่ช่วยให้คุณมีการใช้งานที่แตกต่างกันสำหรับประเภทที่เฉพาะเจาะจง ตัวอย่างเช่นคุณสามารถมีเวอร์ชันที่ปรับให้เหมาะสมสูงสุดสำหรับintในขณะที่ยังคงมีเวอร์ชันทั่วไปสำหรับประเภทที่เหลือ หรือคุณสามารถมีรุ่นที่แตกต่างกันสำหรับประเภทของตัวชี้และชนิดที่ไม่ใช่ตัวชี้ สิ่งนี้มีประโยชน์ถ้าคุณต้องการใช้งานกับวัตถุที่มีการลงทะเบียนเมื่อส่งตัวชี้


1
1 แม่แบบเชี่ยวชาญเป็นสิ่งสำคัญอย่างเหลือเชื่อสำหรับ metaprogramming รวบรวมเวลา - แตกต่างในตัวเองทำให้ generics Java ที่มีศักยภาพมากน้อย
Faisal Vali

13

มีคำอธิบายที่ดีของหัวข้อนี้ในJava Generics and Collections โดย Maurice Naftalin, Philip Wadler ฉันขอแนะนำหนังสือเล่มนี้ อ้างถึง:

Generics ใน Java คล้ายกับแม่แบบใน C ++ ... ไวยากรณ์นั้นคล้ายกันอย่างจงใจและความหมายต่างกันอย่างจงใจ ... Semantically, Java generics ถูกกำหนดโดยการลบโดยที่ C ++ template ถูกกำหนดโดยการขยาย

โปรดอ่านคำอธิบายที่เต็มรูปแบบที่นี่

ข้อความแสดงแทน
(ที่มา: oreilly.com )


5

โดยพื้นฐานแล้วเทมเพลต AFAIK, C ++ จะสร้างสำเนาของรหัสสำหรับแต่ละประเภทขณะที่ Java generics ใช้รหัสเดียวกันทั้งหมด

ใช่คุณสามารถพูดได้ว่าเทมเพลต C ++ เทียบเท่ากับแนวคิดทั่วไปของ Java (แม้ว่าจะเหมาะสมกว่าที่จะกล่าวว่าเจเนอร์จีของ Java นั้นเทียบเท่ากับแนวคิด C ++)

หากคุณคุ้นเคยกับกลไกแม่แบบของ C ++ คุณอาจคิดว่า generics นั้นคล้ายกัน แต่ความคล้ายคลึงกันนั้นเป็นเพียงผิวเผิน Generics ไม่ได้สร้างคลาสใหม่สำหรับแต่ละความเชี่ยวชาญและพวกเขาไม่อนุญาตให้ "เทมเพลต metaprogramming"

จาก: Java Generics


3

ชื่อสามัญ Java (และ C #) ดูเหมือนจะเป็นกลไกการทดแทนชนิดรันไทม์อย่างง่าย
เทมเพลต C ++ เป็นคอมไพล์เวลาคอมไพล์ซึ่งให้วิธีการแก้ไขภาษาให้เหมาะกับความต้องการของคุณ พวกเขาเป็นภาษาที่ใช้งานได้จริงซึ่งคอมไพเลอร์ทำงานในระหว่างการคอมไพล์


3

ข้อดีอีกประการของเทมเพลต C ++ ก็คือความเชี่ยวชาญ

template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }
Special sum(const Special& a, const Special& b) { return a.plus(b); }

ตอนนี้ถ้าคุณโทรหาผลรวมด้วยพอยน์เตอร์วิธีที่สองจะถูกเรียกถ้าคุณเรียกใช้ผลรวมกับวัตถุที่ไม่ใช่ตัวชี้วิธีแรกจะถูกเรียกและถ้าคุณโทรsumด้วยSpecialวัตถุวิธีที่สามจะถูกเรียก ฉันไม่คิดว่านี่เป็นไปได้กับ Java


2
อาจเป็นเพราะ Java ไม่มีตัวชี้ .. !! คุณสามารถอธิบายด้วยตัวอย่างที่ดีกว่าได้ไหม
Bhavuk Mathur

2

ฉันจะรวมเป็นประโยคเดียว: เทมเพลตสร้างชนิดใหม่, ข้อมูลทั่วไป จำกัด ประเภทที่มีอยู่


2
คำอธิบายของคุณสั้นมาก! และเหมาะสมอย่างยิ่งสำหรับผู้ที่เข้าใจหัวข้อดี แต่สำหรับคนที่ยังไม่เข้าใจมันก็ไม่ได้ช่วยอะไรมาก (เป็นกรณีของใครถามคำถามเกี่ยวกับ SO ได้หรือไม่)
Jakub

1

@Keith:

รหัสนั้นผิดจริงและนอกเหนือจากความผิดพลาดเล็ก ๆ น้อย ๆ ( templateเว้นไว้, ความเชี่ยวชาญด้านไวยากรณ์ที่มีลักษณะแตกต่างกัน), ความเชี่ยวชาญเฉพาะบางส่วนไม่สามารถใช้งานได้กับฟังก์ชั่นเทมเพลต, เฉพาะในเทมเพลตชั้นเรียน อย่างไรก็ตามรหัสจะทำงานได้โดยไม่มีความเชี่ยวชาญเฉพาะแม่แบบบางส่วนแทนที่จะใช้การทำเกินพิกัดแบบเดิมธรรมดา:

template <typename T> T sum(T a, T b) { return a + b; }
template <typename T> T sum(T* a, T* b) { return (*a) + (*b); }

2
ทำไมนี่เป็นคำตอบและไม่ใช่ความคิดเห็น
Laurence Gonsalves

3
@ Laurence: หนึ่งครั้งเพราะโพสต์นานก่อนที่ความคิดเห็นจะถูกนำไปใช้กับ Stack Overflow สำหรับคนอื่นเพราะมันไม่ได้เป็นเพียงแค่ความคิดเห็น แต่ยังเป็นคำตอบสำหรับคำถาม: บางอย่างเช่นโค้ดด้านบนเป็นไปไม่ได้ใน Java
Konrad Rudolph

1

คำตอบด้านล่างมาจากหนังสือCracking The Coding Interview Solutions ถึงบทที่ 13 ซึ่งฉันคิดว่าดีมาก

การนำ Java generics มาใช้นั้นมีรากฐานมาจากแนวคิด "การลบประเภท: 'เทคนิคนี้กำจัดประเภทพารามิเตอร์เมื่อแปลซอร์สโค้ดไปเป็น bytecode Java Virtual Machine (JVM) ตัวอย่างเช่นสมมติว่าคุณมีโค้ด Java ด้านล่าง:

Vector<String> vector = new Vector<String>();
vector.add(new String("hello"));
String str = vector.get(0);

ระหว่างการรวบรวมรหัสนี้จะถูกเขียนใหม่ลงใน:

Vector vector = new Vector();
vector.add(new String("hello"));
String str = (String) vector.get(0);

การใช้ Java generics ไม่ได้เปลี่ยนความสามารถของเราไปมากนัก มันทำให้สิ่งต่าง ๆ น่าสนใจยิ่งขึ้น ด้วยเหตุนี้บางครั้ง Java generics จึงถูกเรียกว่า "syntactic sugar: '

สิ่งนี้ค่อนข้างแตกต่างจาก C ++ ใน C ++ เทมเพลตเป็นชุดแมโครที่ได้รับการยกย่องเป็นหลักโดยคอมไพเลอร์สร้างสำเนาใหม่ของรหัสเทมเพลตสำหรับแต่ละประเภท ข้อพิสูจน์เรื่องนี้คือข้อเท็จจริงที่ว่าอินสแตนซ์ของ MyClass จะไม่แชร์ตัวแปรคงที่กับ MyClass อย่างไรก็ตามอินสแตนซ์ของ MyClass จะใช้ตัวแปรแบบสแตติกร่วมกัน

/*** MyClass.h ***/
 template<class T> class MyClass {
 public:
 static int val;
 MyClass(int v) { val v;}
 };
 /*** MyClass.cpp ***/
 template<typename T>
 int MyClass<T>::bar;

 template class MyClass<Foo>;
 template class MyClass<Bar>;

 /*** main.cpp ***/
 MyClass<Foo> * fool
 MyClass<Foo> * foo2
 MyClass<Bar> * barl
 MyClass<Bar> * bar2

 new MyClass<Foo>(10);
 new MyClass<Foo>(15);
 new MyClass<Bar>(20);
 new MyClass<Bar>(35);
 int fl fool->val; // will equal 15
 int f2 foo2->val; // will equal 15
 int bl barl->val; // will equal 35
 int b2 bar2->val; // will equal 35

ใน Java ตัวแปรแบบคงที่จะถูกแชร์ข้ามอินสแตนซ์ของ MyClass โดยไม่คำนึงถึงพารามิเตอร์ชนิดต่าง ๆ

Java generics และเท็มเพลต C ++ มีความแตกต่างอื่น ๆ อีกจำนวนหนึ่ง เหล่านี้รวมถึง:

  • เทมเพลต C ++ สามารถใช้ประเภทดั้งเดิมเช่น int Java ไม่สามารถและต้องใช้ Integer แทน
  • ใน Java คุณสามารถ จำกัด พารามิเตอร์ประเภทของเทมเพลตให้เป็นประเภทที่แน่นอน ตัวอย่างเช่นคุณอาจใช้ generics เพื่อสร้าง CardDeck และระบุว่าพารามิเตอร์ type ต้องขยายจาก CardGame
  • ใน C ++ พารามิเตอร์ type สามารถสร้างอินสแตนซ์ได้ในขณะที่ Java ไม่สนับสนุนสิ่งนี้
  • ใน Java พารามิเตอร์ประเภท (เช่น Foo ใน MyClass) ไม่สามารถใช้สำหรับวิธีการคงที่และตัวแปรเนื่องจากสิ่งเหล่านี้จะถูกใช้ร่วมกันระหว่าง MyClass และ MyClass ใน C ++ คลาสเหล่านี้มีความแตกต่างกันดังนั้นพารามิเตอร์ type สามารถใช้สำหรับเมธอดและตัวแปรแบบสแตติก
  • ใน Java อินสแตนซ์ทั้งหมดของ MyClass ไม่ว่าพารามิเตอร์ชนิดใดเป็นประเภทเดียวกัน พารามิเตอร์ชนิดจะถูกลบเมื่อรันไทม์ ใน C ++ อินสแตนซ์ที่มีพารามิเตอร์ประเภทต่างกันเป็นประเภทไดเรนต์

0

เทมเพลตคืออะไรนอกจากระบบมาโคร น้ำตาลทราย พวกเขาจะขยายอย่างเต็มที่ก่อนที่จะรวบรวมจริง

ตัวอย่าง:

สมมติว่าเราต้องการสองฟังก์ชัน ฟังก์ชั่นหนึ่งใช้สองลำดับ (รายการ, อาร์เรย์, เวกเตอร์, อะไรก็ตามที่ไป) ของตัวเลขและส่งคืนผลิตภัณฑ์ภายในของพวกเขา ฟังก์ชั่นอื่นใช้ความยาวสร้างสองลำดับของความยาวนั้นผ่านไปยังฟังก์ชันแรกและส่งคืนผลลัพธ์ จับได้ว่าเราอาจทำผิดในฟังก์ชั่นที่สองเพื่อให้ฟังก์ชั่นทั้งสองนี้ไม่ได้มีความยาวเท่ากัน เราต้องการคอมไพเลอร์เพื่อเตือนเราในกรณีนี้ ไม่ใช่เมื่อโปรแกรมกำลังทำงาน แต่เมื่อกำลังรวบรวม

ใน Java คุณสามารถทำสิ่งนี้:

import java.io.*;
interface ScalarProduct<A> {
    public Integer scalarProduct(A second);
}
class Nil implements ScalarProduct<Nil>{
    Nil(){}
    public Integer scalarProduct(Nil second) {
        return 0;
    }
}
class Cons<A implements ScalarProduct<A>> implements ScalarProduct<Cons<A>>{
    public Integer value;
    public A tail;
    Cons(Integer _value, A _tail) {
        value = _value;
        tail = _tail;
    }
    public Integer scalarProduct(Cons<A> second){
        return value * second.value + tail.scalarProduct(second.tail);
    }
}
class _Test{
    public static Integer main(Integer n){
        return _main(n, 0, new Nil(), new Nil());
    }
    public static <A implements ScalarProduct<A>> 
      Integer _main(Integer n, Integer i, A first, A second){
        if (n == 0) {
            return first.scalarProduct(second);
        } else {
            return _main(n-1, i+1, 
                         new Cons<A>(2*i+1,first), new Cons<A>(i*i, second));
            //the following line won't compile, it produces an error:
            //return _main(n-1, i+1, first, new Cons<A>(i*i, second));
        }
    }
}
public class Test{
    public static void main(String [] args){
        System.out.print("Enter a number: ");
        try {
            BufferedReader is = 
              new BufferedReader(new InputStreamReader(System.in));
            String line = is.readLine();
            Integer val = Integer.parseInt(line);
            System.out.println(_Test.main(val));
        } catch (NumberFormatException ex) {
            System.err.println("Not a valid number");
        } catch (IOException e) {
            System.err.println("Unexpected IO ERROR");
        }
    }
}

ใน C # คุณสามารถเขียนได้เกือบเหมือนกัน ลองเขียนใหม่ใน C ++ และมันจะไม่คอมไพล์โดยบ่นเกี่ยวกับการขยายเท็มเพลตที่ไม่สิ้นสุด


โอเคนี่อายุ 3 ปีแล้ว แต่ฉันกำลังตอบกลับอยู่ดี ฉันไม่เห็นประเด็นของคุณ เหตุผลทั้งหมดที่ Java สร้างข้อผิดพลาดสำหรับ Line ที่แสดงความคิดเห็นนั้นเป็นเพราะคุณจะเรียกฟังก์ชั่นที่คาดหวังว่า A สองตัวที่มีอาร์กิวเมนต์ที่แตกต่างกัน (A และ Cons <A>) และนี่เป็นพื้นฐานจริงๆ C ++ ก็เช่นกัน นอกจากนั้นรหัสนี้ยังทำให้ฉันเป็นมะเร็งเพราะมันน่ากลัวจริงๆ อย่างไรก็ตามคุณจะต้องทำเช่นนั้นใน C ++ คุณต้องแก้ไขแน่นอนเพราะ C ++ ไม่ใช่ Java แต่นั่นไม่ใช่ diaadvantage ของเทมเพลต C ++
clocktown

@clocktown ไม่คุณไม่สามารถทำได้ใน C ++ ไม่มีการแก้ไขใด ๆ ที่จะอนุญาต และนั่นคือข้อเสียของแม่แบบ C ++
MigMit

สิ่งที่รหัสของคุณควรจะทำ - เตือนเกี่ยวกับความยาวที่แตกต่างกัน - มันไม่ได้ทำ ในตัวอย่างความคิดเห็นของคุณจะสร้างข้อผิดพลาดเท่านั้นเนื่องจากอาร์กิวเมนต์ที่ไม่ตรงกัน ใช้งานได้ใน C ++ เช่นกัน คุณสามารถพิมพ์รหัสที่เทียบเท่าความหมายและวิธีที่ดีกว่าระเบียบนี้ใน C ++ และใน Java
clocktown

มันทำ อาร์กิวเมนต์ไม่ตรงกันเนื่องจากความยาวแตกต่างกัน คุณไม่สามารถทำได้ใน C ++
MigMit

0

ฉันต้องการเสนอราคาข้อแตกต่างที่นี่:

ความแตกต่างที่สำคัญระหว่าง C ++ และ Java นั้นขึ้นอยู่กับการพึ่งพาแพลตฟอร์ม ในขณะที่ C ++ เป็นภาษาที่ขึ้นกับแพลตฟอร์ม Java เป็นภาษาอิสระของแพลตฟอร์ม

ข้อความข้างต้นคือเหตุผลที่ C ++ สามารถให้บริการประเภททั่วไปที่แท้จริงได้ ในขณะที่ Java มีการตรวจสอบที่เข้มงวดและด้วยเหตุนี้พวกเขาไม่อนุญาตให้ใช้ generics วิธีที่ C ++ อนุญาต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.