سؤال

جافا الأدوية و C++ يوفر قوية جدا مع نموذج البرمجة templates.إذن ما هو الفرق بين C++ و Java الأدوية?

هل كانت مفيدة؟

المحلول

هناك فرق كبير بينهما.في C++ لا يجب عليك تحديد الفئة أو واجهة نوع عام.هذا هو السبب في أنك يمكن أن تخلق حقا المهام العامة والطبقات ، مع التحذير من مرونة الكتابة.

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

الطريقة أعلاه يضيف اثنين من الكائنات من نفس النوع, و يمكن أن تستخدم في أي نوع T الذي يحتوي على "+" المشغل المتاحة.

في جافا يجب تحديد نوع إذا كنت ترغب في أساليب الدعوة على الكائنات مر شيء من هذا القبيل:

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

في C++ عامة وظائف/دروس لا يمكن تعريفها إلا في رؤوس منذ مترجم يولد وظائف مختلفة لأنواع مختلفة (أنه الاحتجاج مع).لذا تجميع أبطأ.في جافا تجميع لا عقوبة الرئيسية, ولكن جافا يستخدم تقنية تسمى "المحو" حيث النوع العام تمحى في وقت التشغيل ، حتى في وقت التشغيل جافا هو في الواقع الدعوة ...

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

حتى عام البرمجة في جافا ليست مفيدة حقا, انها فقط القليل من السكر النحوية للمساعدة الجديدة بناء foreach.

تحرير: الرأي أعلاه على فائدة كتب بواسطة الأصغر النفس.جافا الأدوية المساعدة مع نوع-سلامة الحال.

نصائح أخرى

الأدوية جافا هي على نطاق واسع مختلفة إلى C++ قوالب.

الأساس في C++ قوالب الأساس سبحانه المعالج/الماكرو تعيين (ملاحظة: لأن بعض الناس يبدو غير قادر على فهم القياس ، أنا لا أقول قالب تجهيز الكلي).في جاوة وهي في الأساس النحوية السكر لتقليل النمطي الصب من الكائنات.هنا هو لائق جدا مقدمة C++ قوالب مقابل الأدوية جافا.

أن يوضح هذه النقطة:عند استخدام C++ قالب أنت في الأساس إنشاء نسخة أخرى من القانون ، تماما كما لو كنت تستخدم #define الماكرو.هذا يسمح لك أن تفعل أشياء مثل int المعلمات في قالب التعاريف التي تحدد أحجام المصفوفات مثل هذه.

جافا لا تعمل هكذا.في جافا جميع الكائنات حد من java.لانغ.وجوه حتى قبل الأدوية, كنت أكتب رمز مثل هذا:

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

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

  ...
}

لأن كل جمع جافا أنواع تستخدم كائن قاعدة اكتب لذا أنت يمكن أن تضع أي شيء في نفوسهم.جافا 5 لفات حول ويضيف الأدوية حيث يمكنك أن تفعل أشياء مثل:

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

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

  ...
}

و أن جميع الأدوية جافا هي:مغلفة الصب الكائنات.ذلك لأن الأدوية جافا لا المكرر.أنها تستخدم نوع المحو.وقد اتخذ هذا القرار لأن الأدوية جافا جاء في وقت متأخر جدا في القطعة التي لم ترغب في كسر التوافق (أ Map<String, String> يمكن استخدامها كلما Map هو دعا).قارن هذا .Net/C# حيث نوع المحو لا يستخدم ، الأمر الذي يؤدي إلى كل أنواع الاختلافات (مثليمكنك استخدام أنواع بدائية ، IEnumerable و IEnumerable<T> لا تمت بصلة إلى بعضها البعض).

و فئة باستخدام الأدوية جمعت مع جافا 5+ مترجم قابلة للاستخدام على JDK 1.4 (على افتراض أنه لا يستخدم أي ميزات أخرى أو الفئات التي تتطلب جافا 5+).

هذا هو السبب في جافا الأدوية تسمى نحوي السكر.

ولكن هذا المقرر على كيفية القيام الأدوية له آثار عميقة لدرجة أن (رائعة) الأدوية جافا التعليمات وقد انتشرت في الإجابة على العديد والعديد من الناس لديهم أسئلة حول الأدوية جافا.

C++ قوالب لديها عدد من الميزات التي الأدوية جافا لا:

  • استخدام نوع بدائي الحجج.

    على سبيل المثال:

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

    جافا لا تسمح باستخدام نوع بدائي الحجج في الأدوية.

  • استخدام النوع الافتراضي الحجج, الذي هو ميزة واحدة افتقد في جافا ولكن هناك التوافق أسباب هذا ؛

  • جافا يسمح إحاطة من الحجج.

على سبيل المثال:

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

أنه حقا لا تحتاج إلى التأكيد على أن قالب الدعاء مع مختلف الحجج حقا هي أنواع مختلفة.حتى لا مشاركة أعضاء ثابتة.في جاوة هذا ليس هو الحال.

وبصرف النظر عن الخلافات مع الأدوية ، واكتمال هنا الأساسية مقارنة بين C++ و Javaآخر واحد).

وأنا يمكن أن تشير أيضا إلى التفكير في جافا.C++ مبرمج الكثير من المفاهيم مثل الكائنات سوف يكون طبيعة ثانية بالفعل ولكن هناك اختلافات لذلك يمكن أن يكون من المفيد أن يكون نص تمهيدي حتى لو كنت الخالي من أجزاء.

الكثير من ما سوف تتعلم عندما تعلم جافا جميع المكتبات (قياسية-ما يأتي في JDK--و غير قياسي ، والذي يتضمن استخداما أشياء مثل الربيع).تركيب جافا أكثر مطول من C++ الجملة و لا يملك الكثير من C++ الميزات (مثلعامل الحمولة الزائدة ، وراثة متعددة ، المدمر آلية, الخ) ولكن هذا لا فقط مجموعة فرعية من C++ سواء.

C++ وقد قوالب.جافا الأدوية التي تبدو نوعا ما مثل C++ قوالب, لكنها مختلفة جدا.

قوالب العمل ، كما يوحي الاسم ، من خلال توفير مترجم مع (انتظر...) قالب التي يمكن استخدامها لتوليد نوع آمن رمز طريق ملء القالب المعلمات.

الأدوية, كما أفهمها ، والعمل على العكس من ذلك:نوع المعلمات تستخدم من قبل المترجم للتحقق من أن التعليمات البرمجية باستخدام لهم هو نوع آمن ، ولكن الرمز الناتج يتم إنشاؤها دون الأنواع على الإطلاق.

التفكير في C++ قوالب كما حقا جيدة ماكرو نظام جافا الأدوية كأداة تلقائيا توليد typecasts.

 

ميزة أخرى أن C++ القوالب التي الأدوية جافا لا هو التخصص.هذا يسمح لك أن يكون تنفيذ مختلف لأنواع محددة.لذلك يمكنك ، على سبيل المثال ، قد للغاية نسخة محسنة من أجل الباحث, في حين لا يزال وجود نسخة عامة عن بقية الأنواع.أو يمكنك الحصول على إصدارات مختلفة عن مؤشر غير مؤشر أنواع.هذا يأتي في متناول اليدين إذا كنت تريد أن تعمل على dereferenced الكائن عندما سلم مؤشر.

هناك شرح هذا الموضوع في الأدوية جافا و المجموعات موريس Naftalin فيليب Wadler.أنا أوصي هذا الكتاب.اقتباس:

الأدوية في جافا تشبه القوالب في C++....بناء الجملة هو عمدا مماثلة و معاني الكلمات عمدا مختلفة....لغويا, جافا الأدوية الجنيسة هي تعريف المحو ، حيث C++ قوالب يحددها التوسع.

يرجى قراءة تفسير كامل هنا.

alt text
(المصدر: oreilly.com)

أساسا ، AFAIK, C++ قوالب إنشاء نسخة من رمز لكل نوع ، في حين أن الأدوية جافا استخدام نفس الرمز.

نعم ، يمكن القول أن C++ قالب يعادل جافا عامة مفهوم ( على الرغم من أن أكثر بشكل صحيح يمكن أن نقول الأدوية جافا تعادل C++ في مفهوم )

إذا كنت معتادا على C++'s قالب آلية, قد تعتقد أن الأدوية متشابهة ، ولكن التشابه هو سطحي.الأدوية لا تولد فئة جديدة لكل تخصص ، ولا تسمح "قالب metaprogramming."

من: الأدوية جافا

جافا (C#) الوراثة يبدو أن تكون بسيطة وقت تشغيل نوع إحلال آلية.
C++ قوالب الترجمة الوقت بناء والتي تعطيك طريقة لتعديل اللغة التي تناسب احتياجاتك.هم في الواقع محض وظيفية اللغة التي مترجم ينفذ خلال تجميع.

ميزة أخرى من 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 الكائنات الثالث سوف يطلق.أنا لا أعتقد أن هذا ممكن مع جافا.

سوف ألخص الأمر في جملة واحدة:قوالب إنشاء أنواع جديدة ، الأدوية يقيد الأنواع الحالية.

@كيث:

هذا الرمز هو في الواقع خطأ ، وبصرف النظر عن أصغر مواطن الخلل (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); }

الجواب أدناه هو من كتاب تكسير مقابلة الترميز حلول الفصل 13, التي أعتقد أنها جيدة جدا.

تنفيذ جافا الأدوية متجذر في فكرة"نوع المحو:'هذا الأسلوب يلغي معلمات أنواع عندما المصدر مدونة تترجم إلى آلة جافا الافتراضية (JVM) بايت كود.على سبيل المثال ، افترض أن لديك جافا البرمجية أدناه:

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);

استخدام الأدوية جافا لم تتغير كثيرا عن القدرات ؛ لقد جعل الأمور أجمل قليلا.لهذا السبب, جافا الأدوية تسمى أحيانا"نحوي السكر:'.

هذا يختلف تماما عن C++.في C++, قوالب هي أساسا سبحانه الكلي مع المحول البرمجي بإنشاء نسخة جديدة من القالب رمز لكل نوع.والدليل على ذلك هو في حقيقة مثيل MyClass لن نشارك متغير ثابت withMyClass.سحب حالات 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

في جاوة ، متغيرات ثابتة مشتركة عبر حالات من MyClass, بغض النظر عن نوع مختلف المعلمات.

الأدوية جافا و C ++ القوالب عدد من الاختلافات الأخرى.وتشمل هذه:

  • C++ قوالب يمكن استخدام أنواع بدائية مثل int.جافا لا يمكن ولا يجب أن بدلا من استخدام عدد صحيح.
  • في جافا, يمكنك تقييد القالب نوع المعلمات أن تكون من نوع معين.فعلى سبيل المثال ، قد تستخدم الأدوية لتنفيذ CardDeck و تحديد نوع المعلمة يجب أن تمتد من CardGame.
  • في C++, المعلمة نوع يمكن إنشاء مثيل ، بينما جافا لا الدعم هذا.
  • في جافا, المعلمة نوع (أي فو في MyClass) لا يمكن تستخدم أساليب ثابتة ومتغيرات ، لأن هذه قد تكون مشتركة بين MyClass و MyClass.في C++, هذه الفئات هي مختلفة ، لذلك المعلمة نوع يمكن أن تستخدم أساليب ثابتة و المتغيرات.
  • في جافا جميع حالات MyClass, بغض النظر عن نوع المعلمات ، هي نفس النوع.نوع المعلمات تمحى في وقت التشغيل.في C++ الحالات مع نوع مختلف المعلمات أنواع مختلفة.

قوالب ليست سوى ماكرو النظام.جملة السكر.أنها توسعت بشكل كامل قبل الفعلية تجميع (أو على الأقل المجمعين تتصرف كما لو كانت القضية).

على سبيل المثال:

دعونا نقول أننا نريد الوظيفتين.وظيفة واحدة يأخذ اثنين متواليات (قائمة, صفائف, ناقلات, كل ما ينطبق) من الأرقام ، وإرجاع الداخلية المنتج.آخر وظيفة يأخذ طول يولد اثنين من سلاسل من أن طول يمر بها أول وظيفة ، ويعود ذلك نتيجة.الصيد هو أننا قد نخطئ في وظيفة ثانية ، بحيث أن هذه المهام ليست من نفس الطول.نحن في حاجة إلى مترجم لتحذير لنا في هذه الحالة.لا عند تشغيل البرنامج, ولكن عندما يكون تجميع.

في جافا يمكنك أن تفعل شيئا مثل هذا:

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++ و لن تجميع تشكو التوسع اللانهائي من القوالب.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top