回答
泛型編程意味着您不是編寫按原樣編譯的源代碼,而是編寫編譯過程中編譯器轉換爲源代碼的源代碼「模板」。通用編程最簡單的例子是容器類像數組,列表或包含其他對象的集合的地圖。但是泛型編程還有很多。在C++環境中(並且稱爲元編程)它意味着編寫在編譯時間評估的程序。
泛型編程的一個基本示例是容器模板:在像C++這樣的靜態類型語言中,您將不得不聲明容納整數,浮點數和其他類型的單獨容器,或者處理指向void
的指針,並因此丟失所有類型信息。作爲泛型編程的C++方式的模板通過讓您定義在定義類時一個或多個參數未指定的類來利用此約束。當你稍後實例化模板時,告訴編譯器應該使用哪種類型來創建模板外的類。例如:
template<typename T>
class MyContainer
{
// Container that deals with an arbitrary type T
};
void main()
{
// Make MyContainer take just ints.
MyContainer<int> intContainer;
}
模板是通用因爲編譯器將模板到實際的代碼。請注意,如果您沒有實例化您的模板,則不會生成任何代碼,全部爲。另一方面,如果聲明MyContainer<int>
,MyContainer<float>
和MyContainer<String>
,編譯器將創建三個版本的代碼,每個代碼具有不同的類型。將會涉及到一些優化,但基本上你的模板代碼將立即變爲三種新類型。
迭代是Gamma等人的開創性著作「設計模式」進行了推廣,一個設計模式。這是迭代容器類的內容的模式。與使用for
不同的是,迭代器是一個類的實例,指向容器的成員併爲您提供統一的接口來遍歷容器以及訪問成員。採取看看下面這個例子:
// Instanciate template QList with type int
QList<int> myList;
// put some ints into myList
// Copyconstruct iterator that points to the
// first member of the list.
QList<int>::iterator i = myList.begin();
// Iterate through the list
while (i != myList.end()) {
std::cout << *i << std::endl;
i++;
}
在這個C++例子中,我instantating一個模板的QList與int
類型。 QList a container存儲對象列表的類。在這個例子中,我們將使用它來存儲整數。
然後我創建一個迭代器i
來遍歷列表。 myList.begin()
返回一個指向列表第一個元素的迭代器。我們可以將迭代器與另一個迭代器myList.end()
進行比較,該迭代器在列表的最後一個元素之後指向。如果兩個迭代器都是相同的,我們知道我們已經通過了最後一個元素。在循環中,我們通過*i
訪問它來打印元素,並使用i++
轉到下一個元素。
請注意,在此示例中,*
和++
是重載操作符,並且被迭代器類重新實現。在沒有操作員重載的編程語言中,可能有類似i.element()
或i.next()
的方法執行相同的任務。看到i
不是一個指針,而是模仿指針行爲的整個類很重要。
迭代器有什麼好處?它們提供了一種統一的方式來訪問容器類的成員,完全獨立於容器類如何在內部實現。無論你想遍歷列表,地圖還是樹,迭代器類(應該)總是以相同的方式工作。
不錯的答案;我想補充一點,迭代器讓你設計和使用泛型算法(參見STL
@Matteo ltalia謝謝..... – bunty 2010-10-05 12:29:11
我不完全同意。泛型編程是它自己的一個範例,Template是一種在C++中實現它們的方法。正如Go所證明的,泛型編程並不意味着元編程。 – 2010-10-05 12:46:08
泛型編程:幾乎只涉及模板。
container:結構體或類,它包含自己的數據以及作用於該數據的方法。
迭代器:它是一個指向某個內存地址的指針,可以迭代(如數組)。
如果上述任何一個錯誤,請糾正我。
我會糾正你的迭代器的定義,說它是指針對數組的泛化。 – 2010-10-05 09:33:04
@Oli:同意。他們的接口是一個可迭代的內存地址,但這不是他們在大多數情況下(列表,地圖等)的實際內容。 – Puppy 2010-10-05 10:24:52
我想定義迭代器是一種通過從容器類型中抽象調用者代碼來獲取STL容器的標準化方法。 – 2010-10-05 10:33:54
作爲歷史重點,模板之前的C++版本是該語言的一部分,它包含一個「generic.h」,其中包含可以擴展爲類聲明的預處理器宏。所以你可以爲一個類設置一個通用模式(「模板」),當你將它們擴展爲實際的類聲明時,可以通過將某些參數傳遞給宏來改變它。然而,預處理器宏不是類型安全的並且處理起來有點笨拙,並且由於這些原因,它們在C++代碼中的使用顯着下降; C++採用了更通用的模板作爲語言的元素,但是「通用」編程這個術語仍然存在。 「泛型」現在在其他編程語言中用作美化類型轉換。 除此之外,這個問題已經熟練地回答了。
容器
在C++中,容器是一個允許存儲對象的類。例如,標準庫std::vector<T>
是一個可調整大小的數組,它存儲某些類型爲T的對象。爲了正式考慮爲容器類,它必須公開某些功能以便於通用編程。我可以引用C++標準的確切要求,但對於大多數目的而言,重要的容器類別是來自標準庫的容器類別:vector
,deque
,list
,map
,set
和multimap
//multiset
。
其中一個重要的要求是它們必須允許迭代器的訪問。
迭代
「迭代」可以在這裏意味着兩件事情:它是一種設計模式的名字,但在C++中,它也是設計模式中的特異表達的名稱。 C++迭代器是一種允許使用類似指針的語法遍歷一系列元素的類型。
舉例來說,如果你有一個數組int a[10]
,你可以使用一個簡單的指針作爲迭代器:
int* first = a; // create an iterator that points to the beginning of the array
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
int* last = a+10; //create an "end" iterator, one which points one past the end of the array
如果我有一個鏈表,如std::list<int> l
,我可以做多一樣,雖然現在我的迭代器不再只是指針,而是實現一個類類型與std::list
具體工作:
std::list<int>::iterator first = l.begin(); // create an iterator that points to the beginning of the list
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
std::list<int>::iterator last = l.end(); //create an "end" iterator, one which points one past the end of the list
或用載體std::vector<int> v
:
std::vector<int>::iterator first = v.begin(); // create an iterator that points to the beginning of the vector
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
std::list<int>::iterator last = v.end(); //create an "end" iterator, one which points one past the end of the vector
關於迭代器最重要的是,他們給我們一個統一的語法遍歷元素序列,無論順序如何存儲在內存(甚至如果它存儲在內存中。可以編寫迭代器來遍歷磁盤上數據庫的內容。或者我們可以使用迭代器包裝,使流如std::cin
樣子對象序列太:
std::istream_iterator<int>(std::cin) first;
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
std::list<int>::iterator last; //create an "end" iterator, which marks the end of the stream
雖然因爲這個包裝了一個常規流,它是一個更有限類型的迭代器(你不能移動例如,這意味着並非所有以下算法都適用於流迭代器
現在,考慮到任何這些迭代器類型,我們可以使用所有設計用於迭代器的標準庫算法,例如,找到值爲4
的序列中的第一個元素:
std::find(first, last, 4); // return the first iterator which equals 4 and which is located in the interval [first, last)
或者,我們可以排序的序列(不流迭代器工作):
std::sort(first, last);
,或者如果我們寫一個函數,它的廣場一個整數,比如這個:
int square(int i) { return i * i; }
然後我們可以把它應用到整個序列:
// for every element in the range [first, last), apply the square function, and output the result into the sequence starting with first
std::transform(first, last, first, square);
這是迭代器的優勢:它們抽象出來的含有細節呃,這樣我們就可以對的任何序列應用通用操作。感謝迭代器,同樣的find
或sort
實現與鏈接列表以及數組一起工作,甚至與您自己的自制容器類一起工作。
泛型編程
泛型編程基本的想法,你的代碼應該儘可能通用。正如上面的迭代器示例所示,我們想出了一組類型必須支持的通用集合以稱爲迭代器,然後我們編寫可與迭代器類型配合使用的算法。
將其與傳統的面向對象編程相比較,其中迭代器將不得不通過繼承某種類型的接口來「證明」它們是迭代器。這會阻止我們使用原始指針作爲迭代器,所以我們會失去通用性。
在C++中,以泛型編程,我們並不需要官方的接口。我們只是使用模板寫算法,所以他們接受任何類型的只是恰巧樣子一個迭代器,不論他們定義在哪裏,何時以及如何,以及它們是否從一個共同的基類派生或界面。
的類型參數,這使得它可以設計類和推遲一個或多個類型的規格,直到類或方法的方法的概念被聲明和由客戶機代碼實例化。
喂那些誰downvote,不要讓他知道的原因..至少他不會重複下一次.. – liaK 2010-10-05 10:01:17
爲什麼downvote?這是一個值得問的問題.SO不僅僅是專家! – 2010-10-05 10:03:41
這個問題很簡短,但我認爲它仍然有效。 「泛型編程」,「容器」和「迭代器」是非常重要的概念,可能會讓初學者感到恐懼。 @bunty請嘗試讓問題看起來更像是一個「真正的」SO問題。 – WolfgangA 2010-10-05 10:21:13