Visual C++ 2008入门经典 第十章标准模板库(二)
//////////////////////////////////////////////////////////////////////// //10.4 关联容器 //关联容器(如map<K,T>)最重要的特性是无需搜索就可检索特定对像,关联容器内容T类型对像的位置由与对像一起提供的类型为K的键确定,因此只要提供适当的键就可以快速地检索任何对像,该键实际上是一个确定映射中的条目顺序的排序键 //对于set<T>和nultiset<T>容器,对像作为它们自己的键, //10.4.1 使用映射容器 //映射容器的模板在家<map>头文件中定义,当创建map<K,T>容器时,必须提供将使用的键的类型实参K,以及与键关联的对像类型T //map<Person,string> phonebook; //虽然这里对要存储的映射中的键和对像都使用了类对像,但是映射中的键和关联对像也可以是任何基本类型 //如int double, 或char //也可以创建一个映射容器,用另一个映射容器中的键/对像对序列来初始化: //map<Person, string> phonebook(iter1, iter2); //map<Person, string, greater<Person>> phonebook; //1 存储对像 //我们存储在映射中的对像总是模板类pait<K,T>的键/对像对,基中K是键的类型, T是与键关联的对像类型, //prit<K,T>类型是在<utility>并没有文件中定义的,它被包括在<map>头文件中,因此如果正在使用映射,类型就会自动可用, //pair<Person, string> entry = pait<Person, string> (Person("Mel", "Gibson"), "213 324 6789"); //pair<Person, string> //pair<Person, string> entry = make_pair(Person("Mel", "Gibson"), "213 345 56789"); //map<Person, string> phonebook; //typedef pair<Person, string> Entry; //Entry entry1 = Entry(Person("Jack", "Jones"), "213 456 789456"); //可以用insert()函数在映射中插入一个或多个对,例如,下面 //phonebook.insert(entry1); //pair<map<Person, string>::iterator, bool> checkpair; //checkpait = phonebook.insert(entry1); //if(checkpair.second){ // cout<<"插和成功"<<endl;; //}else{ // cout<<"插入失败"<<endl; //} //cout<<"The key for the netry is:"<<endl; //checkpair.first->first.showPerson(); //phonebook[Person("Jack", "Jones")] = "1111111"; // 2 访问对像 //string number = phonebook[Person("Jack", "Jones")]; /*string number; Person key = Person("Jack", "Jones"); map<Person, string>::iterator iter = phonebook.find(key); if(iter != phonebook.end()){ number = iter->second; cout<<"The number is "<<number<<endl; }else{ key.showPerson(); }*/ //3 其他映射操作 //erase()函数可以从映射中删除单个条目或者某个范围内的条目, //Person key = Person("Jack", "Jones"); //map<Person, string>::size_type coutn = phonebook.erase(key); //if(count == 0){ //cout<<"Entry was not found."<<endl; //} //当向erase()函数提供一个键时,它返回已经删除的条目个数,如果使用映射容器,返回值只能是0或者1,多重映射器可以有带相同键的几个条目 //在这种情况下erase()函数可能返回一个大于1的值 //Person key = Person("Jack", "Jones"); //map<Person, string>::iterator iter = phonebook.find(key); //iter = phonebook.erase(iter); //if(iter == phonebook.end()){ // cout<<"end of the map reached."<<endl; //} //在这种情况下,erase()函数返回一个迭代器,指向映射中被删除的条目的下一个条目前,或者,如果不存在的这样的元素,返回一个指向映射末尾的指针 //begin() 返回一个指向映射中第一条目前的双向迭代器 //end() 返回一个指向映射中最后一个条目的下一个位置的双向迭代器 //rbegin() 返回一个指向映射中最后一个条目的逆向迭代器 //rend() 返回一个指向直射中第一个条目的下一个位置的逆向迭代器 //lower_bound() 接受一个键作为实参,如果有一个键大于或等于(下边界)指定的键,则返回指向第一个条目的迭代器,如果该键不存在,将返回指向最后一个条目的下一个位置的迭代器 //upper_bound() 接受一个键作为实参,如果有一个键大于(上边界)指定键,则返回一个指向第一个条目前的迭代器,如果该键不存在,将返回指向最后一个条目的下一个位置的迭代器 //equal_range() 接受一个键作为实参,并返回含两个迭代器的一对对像,这个对中的第一个成员指向指定键的下边界 //第二个成员指向指定键的上边界,如果该键不存在,对中的两个迭代器都会指向映射中最后一个条目前的一下人位置 //swap() 将我们作为实参传递的映射中的条目与调用该函数的映射中的条目交换 //clear() 删除映射中的所有条目 //size() 返回映射中的元素数目 //empty() 如果映射为空则返回true,否则返回false /* #include "stdafx.h" #include <iostream> #include <string> #include <functional> #include <cstdio> #include <map> #include <iomanip> using namespace std; class Person { public: Person(string first="", string second = "") { firstname = first; secondname = second; } bool operator<(const Person& p) const { if(secondname < p.secondname || (secondname == p.secondname && (firstname < p.firstname))) return true; else return false; } string getName() const{ return firstname +" "+secondname; } private: string firstname; string secondname; }; Person getPerson() { string first; string second; cout<<"输入姓:"<<endl; getline(cin,first); cout<<"输入名:"<<endl; getline(cin,second); return Person(first, second); } //添加一个Person对phone book中去 //形参是一个引用,该函数修改作为实参传递的容器,因此函数必须具有对原始对像的访问权限 void AddEntry(map<Person, string>& book) { pair<Person, string> entry; string number; Person person = getPerson(); //要求输入Person信息 cout<<"请输入"<<person.getName()<<"的电话号:"<<endl; getline(cin,number); //保存电话 entry = make_pair(person, number); //将Person跟number定放了entry中去 //make_pair()函数返回一个存储在entry中的pair<Person, stirng>对像, //将entry插入到关联容器中去 //调用容器对像的insert()并存储pr中返回的对像 pair<map<Person, string>::iterator, bool> pr = book.insert(entry); if(pr.second){ cout<<"插入成功!"; }else{ cout<<"用户已经存在"<<person.getName()<<". the numbre is "<<pr.first->second<<endl; //pr.first->second; //pr返回的是一个迭代器,但这里返回的肯是包括所有相同值的元素的迭代器,所以用first取首个值的second } } //循环显示整个容器 void listEntryes(map<Person, string>& book) { if(book.empty()){ cout<<"book empty"<<endl; return; } map<Person, string>::iterator iter; cout<<setiosflags(ios::left); //设置对齐方式 for(iter = book.begin(); iter!=book.end(); iter++){ cout<<setw(30) <<iter->first.getName() <<setw(12) <<iter->second<<endl; } cout<<setiosflags(ios::right); //还原对齐输出方式 } //查找指定用户的电话 void getEntry(map<Person, string>& book) { Person person = getPerson(); //提示用户输入信息 map<Person, string>::const_iterator iter = book.find(person); //查找指定的键值对像 if(iter == book.end()){ cout<<"no entry found for"<<person.getName()<<endl; }else{ cout<<"The number for"<<person.getName() <<" is "<<iter->second<<endl; } } //删除phone book信息 void deleteEntry(map<Person, string>& book) { Person person = getPerson(); map<Person, string>::iterator iter = book.find(person); //先查找 if(iter == book.end()){ cout<<"没有找到指定元素"<<endl; }else{ book.erase(iter); cout<<person.getName()<<" 删除成功!"<<endl; } } int _tmain(int argc, _TCHAR* argv[]) { map<Person, string> phonebook; //声明一个容器phonebook //映射的一个条目中的对像是含有电话号码的string,键是Person对像 char answer = 0; //声明一个字符变量 while(true){ cout<<"请输入你的记录(Y or N):"<<endl; cin>>answer; cin.ignore(); //调用cin的ignore()可以忽略下一个字符,使得接下来的输入可以正常工作 if(toupper(answer) == 'N'){ break; } if(toupper(answer) != 'Y'){ cout<<"请输入Y 或 N 进行操作"<<endl; continue; } AddEntry(phonebook); //输入数据phonebook中 } //开始处理phonebook while(true){ cout<<endl; cout<<"A(添加记录) D(删除记录) G(查询记录) L(循环记录) Q(退出)"<<endl; cin>>answer; cin.ignore(); switch(answer){ case 'A': AddEntry(phonebook); break; case 'D': deleteEntry(phonebook); break; case 'G': getEntry(phonebook); break; case 'L': listEntryes(phonebook); break; case 'Q': return 0; break; default: cout<<"请输入合法值进行操作"<<endl; break; } } return 0; } */ //10.4.2 使用多重映射容器 //多重映射器的工作过程与支持相同范围的函数的映射容器非常相似,只是多重映射不能使用下标运算符,映射与多重映射的基本区别在于相同的键可以有多个条目 //而且这样会影响部分函数的行为方式,显然,由于存在几个键有相同值的可能行,所以重载operator[]()函数对于多重映射来说意义不大 //multimap<Person, string> multi /*Person person = Person("Jack", "Jones"); nulitmap<Person, string>::iterator iter = phonebook.lower_bound(person); if(iter == phonebook.end()){ cout<<"没有找到 "<<person.getName()<<endl; }else{ cout<<"以下是找到的 "<<person.getName()<<endl; for(; iter != phonebook.upper_bound(person); iter++) { cout<<iter->second<<endl; } }*/ //检查lower_bound()函数返回的迭代器很重要,如果不检查,最终可能会尝试引用最后一个条目的下一个位置的条目 /* #include "stdafx.h" #include <iostream> #include <string> #include <functional> #include <cstdio> #include <map> #include <iomanip> using namespace std; class Person { public: Person(string first="", string second = "") { firstname = first; secondname = second; } bool operator<(const Person& p) const { if(secondname < p.secondname || (secondname == p.secondname && (firstname < p.firstname))) return true; else return false; } string getName() const{ return firstname +" "+secondname; } private: string firstname; string secondname; }; Person getPerson() { string first; string second; cout<<"输入姓:"<<endl; getline(cin,first); cout<<"输入名:"<<endl; getline(cin,second); return Person(first, second); } //添加一个Person对phone book中去 //形参是一个引用,该函数修改作为实参传递的容器,因此函数必须具有对原始对像的访问权限 void AddEntry(multimap<Person, string>& book) { pair<Person, string> entry; string number; Person person = getPerson(); //要求输入Person信息 cout<<"请输入"<<person.getName()<<"的电话号:"<<endl; getline(cin,number); //保存电话 //entry = make_pair(person, number); //将Person跟number定放了entry中去 //make_pair()函数返回一个存储在entry中的pair<Person, stirng>对像, //entry = pair<Person, number>; entry = pair<Person, string> (person, number); //prit<K,T>类型是在<utility>并没有文件中定义的,它被包括在<map>头文件中,因此如果正在使用映射,类型就会自动可用, //pair<Person, string> entry = pait<Person, string> (Person("Mel", "Gibson"), "213 324 6789"); //pair<Person, string> //pair<Person, string> entry = make_pair(Person("Mel", "Gibson"), "213 345 56789"); //map<Person, string> phonebook; //typedef pair<Person, string> Entry; //Entry entry1 = Entry(Person("Jack", "Jones"), "213 456 789456"); //checkpait = phonebook.insert(entry1); //将entry插入到关联容器中去 //调用容器对像的insert()并存储pr中返回的对像 //pair<Person, string>::iterator pr = book.insert(entry); //插入不成功,失败在这里 //pair<map<Person, string>::iterator, bool> pr = book.insert(entry); if(pr.second){ cout<<"插入成功!"; }else{ cout<<"用户已经存在"<<person.getName()<<". the numbre is "<<pr.first->second<<endl; //pr.first->second; //pr返回的是一个迭代器,但这里返回的肯是包括所有相同值的元素的迭代器,所以用first取首个值的second } } //循环显示整个容器 void listEntryes(multimap<Person, string>& book) { if(book.empty()){ cout<<"book empty"<<endl; return; } multimap<Person, string>::iterator iter; cout<<setiosflags(ios::left); //设置对齐方式 for(iter = book.begin(); iter!=book.end(); iter++){ cout<<setw(30) <<iter->first.getName() <<setw(12) <<iter->second<<endl; } cout<<setiosflags(ios::right); //还原对齐输出方式 } //查找指定用户的电话 void getEntry(multimap<Person, string>& book) { Person person = getPerson(); //提示用户输入信息 multimap<Person, string>::const_iterator iter = book.find(person); //查找指定的键值对像 if(iter == book.end()){ cout<<"no entry found for"<<person.getName()<<endl; }else{ cout<<"The number for"<<person.getName(); for(; iter != book.upper_bound(person); iter++){ cout<<iter->second<<endl; } } } //删除phone book信息 void deleteEntry(multimap<Person, string>& book) { Person person = getPerson(); multimap<Person, string>::iterator iter = book.find(person); //先查找 if(iter == book.end()){ cout<<"没有找到指定元素"<<endl; }else{ for(; iter != book.upper_bound(person); iter++){ cout<<iter->second<<endl; book.erase(iter); cout<<person.getName()<<" 删除成功!"<<endl; } } } int _tmain(int argc, _TCHAR* argv[]) { multimap<Person, string> phonebook; //声明一个容器phonebook //映射的一个条目中的对像是含有电话号码的string,键是Person对像 char answer = 0; //声明一个字符变量 while(true){ cout<<"请输入你的记录(Y or N):"<<endl; cin>>answer; cin.ignore(); //调用cin的ignore()可以忽略下一个字符,使得接下来的输入可以正常工作 if(toupper(answer) == 'N'){ break; } if(toupper(answer) != 'Y'){ cout<<"请输入Y 或 N 进行操作"<<endl; continue; } AddEntry(phonebook); //输入数据phonebook中 } //开始处理phonebook while(true){ cout<<endl; cout<<"A(添加记录) D(删除记录) G(查询记录) L(循环记录) Q(退出)"<<endl; cin>>answer; cin.ignore(); switch(answer){ case 'A': AddEntry(phonebook); break; case 'D': deleteEntry(phonebook); break; case 'G': getEntry(phonebook); break; case 'L': listEntryes(phonebook); break; case 'Q': return 0; break; default: cout<<"请输入合法值进行操作"<<endl; break; } } return 0; }*/ /////////////////////////////////////////// //10.5 关于迭代器的更多内容 //<iterator>头文件定义迭代器的几个模板将数据从源传到目的地,流迭代器作为指向输入或输出流的指针,它们可以用来在流和任何使用迭代器的源或目的地之间传输数据,如算法 //插入迭代器可以将数据传输给一个其本序列容器 //<iterator>头文件定义两个流迭代器模板,基中istream_iterator<T>用于输入流 //ostream_iterator<T>用于输出流 //头文件还定义了三个插入模板: inserter<T>, back_inserter<T> front_inserter<T> //10.5.1 使用输入流迭代器 //创建输入流迭代器 //istream_iterator<int> numbersInput(cin); //istream_iterator<int< numbersEnd; //我们有一对迭代器,定义cin中一个int类型的值的序列,可以用这些迭代器将cin中的值加载到vector<int>容器中 /*vector<int> numbres; istream_iterator<int> numbresInput(cin), numbresEnd; cout<<"开始输入数值"<<endl; while(numbresInput != numbresEnd){ numbres.pushback(*numbresIn++); //numbresIn是从cin中读取int类型的值的输入流迭代器, } cout<<"你输入数值的总和为:"<<accumulate(intvecRead, endStream, 0)<<endl;*/ //accumulate()算法的实参是指向序列中第一个值的迭代器,指向最后一个值的下一个位置的迭代器及和的初值, /* string data("2.4 2.5 3.6 2.1"); istringstream input(data); istream_iterator<double> begin(input), end; cout<<accumulate(begin,end,0.0)<<endl;*/ /*#include "stdafx.h" #include <iostream> #include <string> #include <functional> #include <cstdio> #include <map> #include <iomanip> #include <iterator> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { typedef map<string, int>::const_iterator Iter; map<string, int> words; //这个容器用string类型的单词作为键来存储int类型的每个单词的个数,当我们用流迭代器从输入流中读取时,用它会使每个单词的个数累计更容易 cout<<"请输入数字值以空格分割开退出请按A+Z"<<endl; std::istream_iterator<string> begin(cin); std::istream_iterator<string> end; while(begin != end){ words[*begin++]++; //递增和存储一个计算值 //在循环内我们用映射容器的下标运算符将单词的个数存储为键,注意,映射的下标运算符的实参是键,表达式*begin访问一个单词,表达式*begin++在访问单词后递增迭代器 //在第一次读取一个单词时,它不会在映射中,因此表达式words[*begin++]将新条目的个数存储为默认值0 //并将begin迭代器递增到下一个单词,准备下一个循环迭代,整个表达式[*begin++]++会递增条目的个数,不管它是不是新条目,因此,现有条目只会使个数递增,而新条目会被创建,然后它的个数从0递增到1 //还是没看懂这段 } cout<<"现在开始输出:"<<endl; for(Iter iter = words.begin(); iter != words.end(); ++iter) { cout<<setw(5)<<iter->second<<" "<<iter->first<<endl; } return 0; }*/ //整个实例运行失败,已经发贴求助 //10.5.2 使用插入迭代器 //插入迭代器是一个可以向序列容器vector<T>, deque<T> 和list<T>中的任何一个添加新元素的迭代器 //back_inserter<T>在类型T的容器末尾插入元素 //front_inserter<T>在类型T的容器开头插入元素 //inserter<T>在类型T的容器内从指定位置开始插入元素 //vector<int> numbres; //front_inserter<vector<int>> iter(numbres); //*iter = 99; //inserter<vector<int>> iter_anywhere(numbres,numbres.begin()); /*for(int i=0; i<100; i++){ *iter_anywhere = i+1; } list<double> values; istream_iterator<double> input(cin), input_endl; copy(input, input_end, back_inserter<list<double>>(values)) */ //10.5.3 使用输出流迭代器 //ostream_iterator<int> out(cout); //该模板的类型实参int指定要处理的数据类型,构造函数实参cout指定将作为数据的目的地的流 //int data[]= {1, 2, 3, 4, 5, 6, 7, 8, 9}; //vector<int> numbres(data, data+9); //copy(numbres.begin(), numbres.end(), out); //在<algorithm>头文件中定义的copy()算法复制由第三个实参指定的输出迭代器的对像序列(由第二个实参指定) //ostream_iterator<int> out(cout,", "); //这个构造函数的第二个实参是一个字符串,作为输出值的分隔符,如果用这个迭代器作为前面代码版段中copy()函数的第三个实参 /*#include "stdafx.h" #include <iostream> #include <numeric> #include <vector> #include <iterator> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { vector<int> numbres; cout<<"请输入数值,退出请按(Ctrl+Z):"<<endl; istream_iterator<int> input(cin), input_end; //创建两个输入流迭代器,用来从标准输入流input和input_end中读取int类型的值 ostream_iterator<int> out(cout, " "); //创建一个输入流迭代器,将int类型的值传输给标准输出流,跟在每个输出值后面的分隔符是一个空格 copy(input, input_end, back_inserter<vector<int>>(numbres)); //我们通过两个输入流迭代器input和input_end指定复制操作的数据源,复制操作的目的地是numbres容器的后端插入迭代器 //因此,复制操作会通过后端插入迭代器将cin中的数据值传输到numbres容器中 cout<<"输入的数据如下:"<<endl; copy(numbres.begin(), numbres.end(), out); //另一个复制操作输入存储在容器中的值 //输出的源由begin()和end()迭代器指定,目的地由输出流迭代器out指定 //因此,这个操作会由空格分隔的值将numbres中的数据写到cout中 cout<<"输入的数据总和为:"<<endl; cout<<accumulate(numbres.begin(), numbres.end(), 0)<<endl; //用accumulate()算法计算numbres容器中的值之和 system("pause"); return 0; }*/ //10.6 关于函数对像的更多内容 //<functional>头文件定义了一个可扩展的模板集合,用来创建可用于算法和容器的函数对像, //less<T> 创建一个二元谓词,表示T类型之间的<运算,例如:less<string>()定义一个比较string类型对像的函数对像 //less_equal<T> 创建一个二元谓词,表示T类型对像之间的<=运算,例如:less_equal<double>()定义一个比较double类型对像的函数对像 //equal<T> 创建一个二元谓词,表示T类型对像之间的==运算 //not_equal<T> 创建一个二元谓词,表示T类型对像之间的!=运算 //geater_equal<T> 创建一个二元谓词,表示T类型对像之间的>=运算 //greater<T> 创建一个二元谓词,表示T类型对像之间的>运算 //not2<B> 创建一个二元谓词,它是B类型的二元谓词的负值,例如,not2(less<int>)创建一个二元谓词来比较int类型的对像 //如果左操作数不小于右操作数,则返回true //下面的代码是用not2<B>模板来定义用于sort()算法的二元谓词 //sort(v.begin(), v.end(), not2(greater<string>())); //<functional>头文件还定义对元素进行算术运算的函数对像 //plus<T> 计算两个T类型元素的和 //minus<T> 通过从第一个操作数中减去第二个操作数计算两个T类型元素之间的差 //multiplies<T> 计算两个T类型元素的积 //divides<T> 用第一个T类型操作数除以第二个T类型操作数 //modulus<T> 计算第一个T类型操作数除以第二个操作数后的余数 //negate<T> 返回它的T类型操作数的负值 //10.7 关于算法的更多内容 //<numeric>头文件中的这些算法主要用来处理数组中的数值, //<algorithm>头文件中的算法大多用搜索,排序和合并迭代器指定的对像序列 //10.7.1 fill() //fill(ForwardIterator begin, ForwardIterator end, const Type& value); //它会用值填充由迭代器begin()和end()指定的元素 //fill(v.begin(), v.begin()+9, "invalid"); //10.7.2 replace() //replace(ForwardIterator begin, ForwardIterator end, const Type& oldValue, const Type& newValue); //函分析begin()和end()指定的每个元素,并用newValue替换出现的每个oldValue //replace(v.begin(), v.end(), "yes", "no"); //replace()函数也会使用指针 //char str[] = "A nod is as good as a wink to a blind hors."; //replace(str, str+strlen(str), 'o', '*'); //10.7.3 find(); //find(InputIterator begin, InputIterator end, const Type& value); //搜索由首次出现在value的前两个实参指定的序列 //vector<int>::itertor iter = find(v.begin(), v.end(), 21) //find()算法反复查找出现的所有给定值 //vector<int::iterator iter = v.begin(); //int value = 21, count = 0; //while( (iter = find(iter, v.end(), value)) != v.end()){ // count++; // iter++; //} //或 //for((iter=find(v.begin(), v.end(), value)); iter != v.end(); // (iter = find(iter, v.end(), value))++, count++); //10.7.4 transform() //transform(InputIterator begin, InputIterator end, OutputIterator result, UnaryFunction f); //将二元函数f应用到迭代器begin()和end()指定范围中的所有元素 //并从迭代器result指定的位置开始存储结果,result迭代器可以与begin()相同,在这种情况下结果将替换原始元素 /*#include "stdafx.h" #include <iostream> #include <numeric> #include <vector> #include <iterator> #include <algorithm> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { ouble values[] = {2.5, -3.5, 4.5, -5.5, 6.5, -7.5}; vector<double> data(values, values+6); transform(data.begin(), data.end(), data.begin(), negate<double>()); vector<double>::iterator iter = data.begin(); int i = 0; while(iter != data.end()) { i++; //cout<<"i="<<i<<endl; cout<<*iter<<" "; iter++; } cout<<endl; system("pause"); return 0; }*/ //transform()的第二个版本通过来自迭代器指定的两个范围内的操作数应用一个二元函数该函数格式 //transform(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, OutputIterator result, BinaryFunction f); //由begin1()到end1()指定的范围表示最后一个实参指定的二元函数f的左操作数集合,表示右操作数的范围从begin2()迭代器指定的位置开始 //这个范围不需要提供end迭代器,因为begin1()和end1()指定的范围中的元素个数必须相同,结果将从result迭代器位置开始存储在这个范围内 /*#include "stdafx.h" #include <iostream> #include <numeric> #include <vector> #include <iterator> #include <algorithm> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { double values[] = {2.5, -3.5, 4.5, -5.5, 6.5, -7.5}; vector<double> data(values, values+6); vector<double> squares(data.size()); transform(data.begin(), data.end(), data.begin(), squares.begin(), multiplies<double>()); ostream_iterator<double> out(cout, " "); copy(squares.begin(), squares.end(), out); system("pause"); return 0; }*/ //10.8 C++/CLI程序中的STL //STL/CLR包含在cliext命名空内,因此所有STL名称都用cliext而不是std限定 //10.8.1 STL/CLR容器 /*T (const T% t) { } //构造函数 T% operator=(const T% t) { } //重载=运算符 ~T() { } //析构函数*/ //这些容器操作也要求定义无实参构造函数和operator==function,当容器存储对像而不是句柄时,如果需要为容器中的元素分配空格,就可以要用到无实参构造函数,如果在一个关联容器(如集合或映射)中存储引用类型的句柄或者值类型,它们至少必须重载一个运算符--默认要求重载operator<() //10.8.2 使用序列容器 //本地C++的STL提供的所有序列容器也可用于STL/CLR,STL/CLR实现本地STL容器支持的所有操作,只是使用C++/CLI类型时可能会出现一些区别,下面通过一些示例来介绍这些区别 /*ref class Person { public: Person():firstname(""), secondname(""){} Person(String^ first, String^ second):firstname(first), secondname(second){} virtual String^ ToString() override { return firstname+L" "+secondname; } private: String^ firstname; String^ secondname; };*/ //我们只在矢量中存储Person对像的句柄,因此不需要实现复制构造函数或赋值运算符, //ToString()函数重写了继承自类Object的版本,并且出于输出的目的 /*#include "stdafx.h" #include <cliext/vector> #include <string> //using namespace System; using namespace cliext; ref class Person { public: Person():firstname(""), secondname(""){} Person(string^ first, string^ second):firstname(first), secondname(second){} virtual String^ ToString() override { return firstname+L" "+secondname; } private: string^ firstname; string^ secondname; }; int _tmain(int argc, _TCHAR* argv[]) { system("pause"); return 0; }*/ //10.8.3 使用关联容器 //STL/CLR中的甩的关联容器的使用方式基本上与等价的本地STL容器相同,但是有一个重要的小区别,通常在处理对象的表示方式方面 //首先,我们存储在类型映射中的元素的类型 //map<K,T> //在本地STL中的类型pair<k,T>,但是在STL/CLR映射容器中它是类型map<K,T>::value_type, //它是一个数值类型,这暗示了我们不再能用make_pair()函在STL/CLR中创建映射条目,取而代之的是使用map<K,T>类中定义的静态make_value()函数 //第二,在map<K,T>中插入一个元素的insert()函数对于本地STL容器返回一个类型pair<map<K,T>::iterator, bool>类型的值,而对于STL/CLR map<K,T>容器,insert()函数返回下面的这个类型的值 //map<K,T>::pair_iter_bool //它是一个引用类型,类型map<K,T>::pair_iter_bool的对像有两个公有字段,first和second //first是下面类型的迭代器的一个句柄 //map<K,T>::iterator^ //second的类型为bool,如果second的值为true,那么first就指向新插入的元素,否则它指向映射中已经存在的具有相同键的元素 //10.9 小结 //STL和STL/CLR功能,包括容器,迭代器,算法和函数对像的模板 //容器是一个存储和组织其他对像的类,序列容器用一个序列(如数组)存储对像,关联容器存储是键/对像对的元素,其中键确定对存储在容器中的何处 //迭代器是行为与指针相似的对像,对中的迭代器用来通过一个半开放的间隔定义一个对像集合,其中第一个迭代器指向系列中的第一个对像,第二个迭代器指向系列中最后一个对像的下一个位置 //流迭代器是允许我们访问或修改流中的内容的迭代器 //迭代器有四大类,输入和输出迭代器,前向迭代器,双向迭代器和随机访问迭代器,迭代器这几类中每一类都提供了比上一类更多的功能,因此输入和输出迭代器提供的功能性最小,随机访问迭代器提供的功能性最大 //算法是在一对迭代器指定的一个对像序列上操作的模板函数 //函数对像是重载()运算符(通过在类中实现函数operator()())的类型的对像,STL和STL/CLR定义用于容器和算法的广泛类型的标准迭代器,我们也可以写自己的类来定义函数对像)