2014-01-16 44 views
2

我正在閱讀一些關於某些不同編程語言中模板之間差異的問題。我明白,主要感謝這個問題:What are the differences between Generics in C# and Java... and Templates in C++?。然而,當他開始談論接口和添加內容時,我對接受的答案的結尾有點困惑。我主要從這個問題了解接口的概要:Explaining Interfaces to Students。問題中所陳述的內容我仍然感到困惑。因此,有人可以更好地解釋這最後一部分:Java接口和模板混淆

正因爲如此,C++編譯器的地方您可以用模板做任何限制 - 基本上任何代碼,你可以手工編寫, 你可以得到的模板爲你寫。最明顯的例子是 添加的東西:

在C#和Java泛型系統需要知道有哪些方法可以 一類,它需要通過這個下到虛擬機 。要告訴它的唯一方法是通過硬編碼 實際類或使用接口。例如:

string addNames(T first,T second){return first.Name()+ second.Name(); }

該代碼不會在C#或Java中編譯,因爲它不知道 類型T實際上提供了名爲Name()的方法。你必須告訴 它 - 在C#中是這樣的:

interface IHasName {string Name(); }; string addNames(T first,T second)其中T:IHasName {....}

然後你必須確保你傳遞的東西addNames 實現IHasName接口等等。 java的語法是 different(),但它遭受相同的 問題。

「經典」的情況下對這個問題是試圖寫一個函數 ,其執行此

串addNames(T第一,T秒){第二返回第一+; }

你實際上不能編寫這段代碼,因爲沒有辦法用 聲明一個帶有+方法的接口。你失敗了。

C++患有這些問題。編譯器不關心 關於將類型傳遞給任何虛擬機 - 如果兩個對象都有 .Name()函數,它將進行編譯。如果他們不這樣做,它不會。簡單。

我真的很想理解這個答案中的代碼,因爲我很困惑如何.Name()方法在IHasName接口中工作。是否有人有一個更好的例子,可以進一步解釋如何使用接口可以添加類名稱到Person類或其他東西...

編輯:我更感興趣的Java代碼。

回答

1

C++模板有很大的不同。但我不明白爲什麼Java的泛型不能做你在那裏引用的東西。

interface IHasName { 
    String getName(); 
} 

class Person implements IHasName { 
    private final String name; 
    public Person(String name) { 
     this.name = name; 
    } 

    @Override 
    public String getName() { 
     return name; 
    } 
} 

class GenericUtility { 
    public static <T extends IHasName> String addNames(T first, T second) { 
     return first.getName() + ", " + second.getName(); 
    } 
} 

class Main { 
    public static void main(String[] args) { 
     Person first = new Person("Peter"); 
     IHasName second = new IHasName() { 
      @Override 
      public String getName() { 
       return "John"; 
      } 
     }; 
     String result = GenericUtility.addNames(first, second); 
     System.out.println(result); 
    } 

} 

打印

Peter, John 

而且我認爲,由於按預期工作。

你實際上不能寫這段代碼,因爲沒有辦法用+方法聲明一個接口。你失敗了。

Java根據參數類型不允許覆蓋+運算符。這裏沒有任何失敗,因爲你必須採取不同的方法(可以寫成接口)。

C++患有這些問題。編譯器不關心將類型傳遞給任何虛擬機 - 如果兩個對象都有.Name()函數,它將編譯。如果他們不這樣做,它不會。簡單。

Java也不會。如果聲明泛型參數必須擴展/實現某個接口,那麼在參數不存在的情況下,您將看到編譯時錯誤。

+0

謝謝你的答案。我的問題不是代碼是否工作,而是更多地尋找代碼的解釋,因爲我相信這很好,但我不確定「如何」。看到像這樣的完整程序更好地解釋了這個例子,並且實際上回答了我的問題。謝謝! – LiverpoolFTW

2

在C++中編譯'+'的原因是C++模板(和C++專家請請原諒我的笨拙)像巨大的宏。它會一直等到實例化模板以檢查每個操作是否可能(仍然在編譯時,因爲foo在他們的評論中提醒我)。

例如下面的代碼:

#include "stdafx.h" 

#include <stdio.h> 

#include <vector> 
#include <iostream> 

template <class T> class adder { 
public: 
    adder(); 
    T add(T t1, T t2); 
}; 


template <class T> adder<T>::adder() {} 

template <class T> T adder<T>::add (T t1, T t2) { 
     return t1 + t2; 
} 

using namespace std; 

typedef vector<int> int_vector; 


int _tmain(int argc, _TCHAR* argv[]) 
{ 

    adder<int_vector> vector_adder; 
    int_vector v1; 
    int_vector v2; 

    v1.push_back(1); 
    v1.push_back(2); 

    v2.push_back(3); 
    v2.push_back(4); 
    v2.push_back(5); 

    // will fail here, in compile time! 
    int_vector v3 = vector_adder.add(v1, v2); 

    for (int_vector::iterator it = v3.begin(); it != v3.end(); it++) { 
     cout << *it; 
    } 

    return 0; 
} 

會很好地工作,直到我嘗試添加兩個向量;在那一刻,C++編譯器會意識到我在模板中使用的實際類型沒有超載。但是,我可以在模板中定義一些其他操作,如果我沒有嘗試添加實際類型(那麼它將嘗試解決宏),編譯器就不會意識到這一點。然而,像adder<int>這樣的東西完全可以工作。因爲它不允許真正的操作泛型類型(很難定義泛型包含如java.util。*下的類,但很少有其他東西),Java不允許你達到這一點。你最好的拍攝是去一個有界類型通用就像Java文檔:

public class NaturalNumber<T extends Integer> { 

    private T n; 

    public NaturalNumber(T n) { this.n = n; } 

    public boolean isEven() { 
     return n.intValue() % 2 == 0; 
    } 

    // ... 
} 

在這裏,您可以限制通用的類型有一定超一流的,有做一些操作它。

+0

對不起,您好像在這裏混淆了兩種語言。 C++模板在編譯時解析,而不是運行時。你的「巨大的宏觀」是正確的,而你是自相矛盾的。你在想Java的泛型嗎? – foo

+0

你是完全正確的,我忘記了更多關於C++的信息比我想象的更多)剛剛測試過它並將更新回答 –