首页 文章 精选 留言 我的

精选列表

搜索[标准直播],共10000篇文章
优秀的个人博客,低调大师

C++标准转换运算符dynamic_cast

dynamic_cast <new_type> (expression) dynamic_cast运算符,应该算是四个里面最特殊的一个,因为它涉及到编译器的属性设置,而且牵扯到的面向对象的多态性跟程序运行时的状态也有关系,所以不能完全的使用传统的转换方式来替代。但是也因此它是最常用,最不可缺少的一个运算符。 与static_cast一样,dynamic_cast的转换也需要目标类型和源对象有一定的关系:继承关系。 更准确的说,dynamic_cast是用来检查两者是否有继承关系。因此该运算符实际上只接受基于类对象的指针和引用的类转换。从这个方面来看,似乎dynamic_cast又和reinterpret_cast是一致的,但实际上,它们还是存在着很大的差别。 还是用代码来解释,让编译器来说明吧。 ///////////////////////////////////////////////////////////////////////////// // cast_operator_comparison.cpp // Language: C++ // Complier: Visual Studio 2010, Xcode3.2.6 // Platform: MacBook Pro 2010 // Application: none // Author: Ider, Syracuse University ider.cs@gmail.com /////////////////////////////////////////////////////////////////////////// #include <string> #include <iostream> using namespace std; class Parents { public: Parents(string n="Parent"){ name = n;} virtual ~Parents(){} virtual void Speak() { cout << "\tI am " << name << ", I love my children." << endl; } void Work() { cout << "\tI am " << name <<", I need to work for my family." << endl;; } protected: string name; }; class Children : public Parents { public: Children(string n="Child"):Parents(n){ } virtual ~Children(){} virtual void Speak() { cout << "\tI am " << name << ", I love my parents." << endl; } /* **Children inherit Work() method from parents, **it could be treated like part-time job. */ void Study() { cout << "\tI am " << name << ", I need to study for future." << endl;; } private: //string name; //Inherit "name" member from Parents }; class Stranger { public: Stranger(string n="stranger"){name = n;} virtual ~Stranger(){} void Self_Introduce() { cout << "\tI am a stranger" << endl; } void Speak() { //cout << "I am a stranger" << endl; cout << "\tDo not talk to "<< name << ", who is a stranger." << endl; } private: string name; }; int main() { /******* cast from child class to base class *******/ cout << "dynamic_cast from child class to base class:" << endl; Children * daughter_d = new Children("Daughter who pretend to be my mother"); Parents * mother_d = dynamic_cast<Parents*> (daughter_d); //right, cast with polymorphism mother_d->Speak(); mother_d->Work(); //mother_d->Study(); //Error, no such method cout << "static_cast from child class to base class:" << endl; Children * son_s = new Children("Son who pretend to be my father"); Parents * father_s = static_cast<Parents*> (son_s); //right, cast with polymorphism father_s->Speak(); father_s->Work(); //father_s->Study(); //Error, no such method cout << endl; /******* cast from base class to child class *******/ cout << "dynamic_cast from base class to child class:" << endl; Parents * father_d = new Parents("Father who pretend to be a my son"); Children * son_d = dynamic_cast<Children*> (father_d); //no error, but not safe if (son_d) { son_d->Speak(); son_d->Study(); } else cout << "\t[null]" << endl; cout << "static_cast from base class to child class:" << endl; Parents * mother_s = new Parents("Mother who pretend to be a my daugher"); Children * daughter_s = static_cast<Children*> (mother_s); //no error, but not safe if (daughter_s) { daughter_s->Speak(); daughter_s->Study(); } else cout << "\t[null]" << endl; cout << endl; /******* cast between non-related class *******/ cout << "dynamic_cast to non-related class:" << endl; Stranger* stranger_d = dynamic_cast<Stranger*> (daughter_d); if (stranger_d) { stranger_d->Self_Introduce(); stranger_d->Speak(); } else cout <<"\t[null]"<<endl; //Stranger* stranger_s = static_cast<Stranger*> (son_s); //Error, invalid cast cout << "reinterpret_cast to non-related class:" << endl; Stranger* stranger_r = reinterpret_cast<Stranger*> (son_s); if (stranger_r) { stranger_d->Self_Introduce(); //stranger_d->Speak(); //This line would cause program crush, //as "name" could not be found corretly. } else cout << "\t[null]" << endl; cout << endl; /******* cast back*******/ cout << "use dynamic_cast to cast back from static_cast:" << endl; Children* child_s = dynamic_cast<Children*> (father_s); if (child_s) { child_s->Speak(); child_s->Work(); } else cout << "\t[null]" << endl; //cout<<typeid(stranger_r).name()<<endl; cout << "use dynamic_cast to cast back from reinterpret_cast:" << endl; Children* child_r = dynamic_cast<Children*> (stranger_r); if (child_r) { child_r->Speak(); child_r->Work(); } else cout << "\t[null]" << endl; delete daughter_d; delete son_s; delete father_d; delete mother_s; return 0; } /********************* Result *********************/ //dynamic_cast from child class to base class: // I am Daughter who pretend to be my mother, I love my parents. // I am Daughter who pretend to be my mother, I need to work for my family. //static_cast from child class to base class: // I am Son who pretend to be my father, I love my parents. // I am Son who pretend to be my father, I need to work for my family. // //dynamic_cast from base class to child class: // [null] //static_cast from base class to child class: // I am Mother who pretend to be a my daugher, I love my children. // I am Mother who pretend to be a my daugher, I need to study for future. // //dynamic_cast to non-related class: // [null] //reinterpret_cast to non-related class: // I am a stranger // //use dynamic_cast to cast back from static_cast: // I am Son who pretend to be my father, I love my parents. // I am Son who pretend to be my father, I need to work for my family. //use dynamic_cast to cast back from reinterpret_cast: // [null] 从上边的代码和输出结果可以看出: 对于从子类到基类的指针转换,static_cast和dynamic_cast都是成功并且正确的(所谓成功是说转换没有编译错误或者运行异常;所谓正确是指方法的调用和数据的访问输出是期望的结果),这是面向对象多态性的完美体现。 而从基类到子类的转换,static_cast和dynamic_cast都是成功的,但是正确性方面,我对两者的结果都先进行了是否非空的判别:dynamic_cast的结果显示是空指针,而static_cast则是非空指针。但很显然,static_cast的结果应该算是错误的,子类指针实际所指的是基类的对象,而基类对象并不具有子类的Study()方法(除非妈妈又想去接受个"继续教育")。 对于没有关系的两个类之间的转换,输出结果表明,dynamic_cast依然是返回一个空指针以表示转换是不成立的;static_cast直接在编译期就拒绝了这种转换。 reinterpret_cast成功进行了转换,而且返回的值并不是空指针,但是结果显然是错误的,因为Children类显然不具有Stranger的Self_Introduce()。虽然两者都具有name数据成员和Speak()方法,,Speak()方法也只是调用了该相同名称的成员而已,但是对于Speak()的调用直接造成了程序的崩溃。 其实前面static_cast的转换的结果也会跟reinterpret_cast一样造成的程序的崩溃,只是类的方法都只有一份,只有数据成员属于对象,所以在调用那些不会访问对象的数据的方法时(如Stranger的Self_Introduce())并不会造成崩溃。而daughter_s->Speak();和daughter_s->Study();调用了数据成员却没有出现运行错误,则是因为该成员是从基类继承下来的,通过地址偏移可以正确的到达数据成员所在的地址以读取出数据。 最后,程序里还用dynamic_cast希望把用其他转换运算符转换过去的指针转换回来。对于使用static_cast转换后指向了子类对象的基类指针,dynamic_cast判定转换是合理有效的,因此转换成功获得一个非空的指针并且正确输出了结果;而对于reinterpret_cast转换的类型,的确如它的功能一样——重新解析,变成新的类型,所以才得到dynamic_cast判定该类型已经不是原来的类型结果,转换得到了一个空指针。 总得说来,static_cast和reinterpret_cast运算符要么直接被编译器拒绝进行转换,要么就一定会得到相应的目标类型的值。 而dynamic_cast却会进行判别,确定源指针所指的内容,是否真的合适被目标指针接受。如果是否定的,那么dynamic_cast则会返回null。这是通过检查"运行期类型信息"(Runtime type information,RTTI)来判定的,它还受到编译器的影响,有些编译器需要设置开启才能让程序正确运行(导师的PPT详细介绍了Visual Studio的情况),因此dynamic_cast也就不能用传统的转换方式来实现了。 虚函数(virtual function)对dynamic_cast的作用 已经在前面反复提到过面向对象的多态性,但是这个多态性到底要如何体现呢?dynamic_cast真的允许任意对象指针之间进行转换,只是最后返回个null值来告知转换无结果吗? 实际上,这一切都是虚函数(virtual function)在起作用。 在C++的面对对象思想中,虚函数起到了很关键的作用,当一个类中拥有至少一个虚函数,那么编译器就会构建出一个虚函数表(virtual method table)来指示这些函数的地址,假如继承该类的子类定义并实现了一个同名并具有同样函数签名(function siguature)的方法重写了基类中的方法,那么虚函数表会将该函数指向新的地址。此时多态性就体现出来了:当我们将基类的指针或引用指向子类的对象的时候,调用方法时,就会顺着虚函数表找到对应子类的方法而非基类的方法。 当然虚函数表的存在对于效率上会有一定的影响,首先构建虚函数表需要时间,根据虚函数表寻到到函数也需要时间。 因为这个原因如果没有继承的需要,一般不必在类中定义虚函数。但是对于继承来说,虚函数就变得很重要了,这不仅仅是实现多态性的一个重要标志,同时也是dynamic_cast转换能够进行的前提条件。 假如去掉上个例子中Stranger类析构函数前的virtual,那么语句Children* child_r =dynamic_cast<Children*> (stranger_r); 在编译期就会直接报出错误,具体原因不是很清楚,我猜测可能是因为当类没有虚函数表的时候,dynamic_cast就不能用RTTI来确定类的具体类型,于是就直接不通过编译。 这不仅仅是没有继承关系的类之间的情况,如果基类或者子类没有任何虚函数(如果基类有虚函数表,子类当然是自动继承了该表),当他们作为dynamic_cast的源类型进行转换时,编译也会失败。 这种情况是有可能存在的,因为在设计的时候,我们可能不需要让子类重写任何基类的方法。但实际上,这是不合理的。导师在讲解多态性的时候,时刻强调了一点:如果要用继承,那么一定要让析构函数是虚函数;如果一个函数是虚函数,那么在子类中也要是虚函数。 我会将导师关于"为何继承中析构函数必须是虚函数"的讲解总结一下,当然你也可以看这边文章来了解原因。 Director: Jim Fawcett C++ Language Tutorial - Type Casting Object Oriented Design IBM Complilers - XL C/C++ V9.0 for Linux - The dynamic_cast operator (C++ only) MSDN Visual C++ Develope Center - dynamic_cast Operator In C++, what’s a virtual destructor and when is it needed? Wikipedia The Free Encyclopedia - Run-Time Type Information Wikipedia The Free Encyclopedia - Virtual Function

优秀的个人博客,低调大师

C++标准转换运算符static_cast

static_cast <new_type> (expression) 虽然const_cast是用来去除变量的const限定,但是static_cast却不是用来去除变量的static引用。其实这是很容易理解的,static决定的是一个变量的作用域和生命周期,比如:在一个文件中将变量定义为static,则说明这个变量只能在本Package中使用;在方法中定义一个static变量,该变量在程序开始存在直到程序结束;类中定义一个static成员,该成员随类的第一个对象出现时出现,并且可以被该类的所有对象所使用。 对static限定的改变必然会造成范围性的影响,而const限定的只是变量或对象自身。但无论是哪一个限定,它们都是在变量一出生(完成编译的时候)就决定了变量的特性,所以实际上都是不容许改变的。这点在const_cast那部分就已经有体现出来。 static_cast和reinterpret_cast一样,在面对const的时候都无能为力:两者都不能去除const限定。两者也存在的很多的不同,比如static_cast不仅可以用在指针和引用上,还可以用在基础数据和对象上;前面提到过reinterpret_cast可以用在"没有关系"的类型之间,而用static_cast来处理的转换就需要两者具有"一定的关系"了。 还是用例子来说明比较直观一些。 还是用例子来说明比较直观一些。 在reinterpret_cast一篇,已经提到过reinterpret_cast可以在任意指针之间进行互相转换,即使这些指针所指的内容是毫无关系的,也就是说一下语句,编译器是不会报错的,但是对于程序来说也是毫无意义可言的,只会造成程序崩溃: #include <iostream> using namespace std; unsigned short Hash( void *p ) { unsigned long val = reinterpret_cast<unsigned long>( p ); return ( unsigned short )( val ^ (val >> 16)); } class Something { /* Some codes here */ }; class Otherthing { /* Some codes here */ }; int main() { typedef unsigned short (*FuncPointer)( void *) ; FuncPointer fp = Hash; //right, this is what we want int a[10]; const int* ch = a; //right, array is just like pointer char chArray[4] = {'a','b','c','d'}; fp = reinterpret_cast<FuncPointer> (ch); //no error, but does not make sense ch = reinterpret_cast<int*> (chArray); //no error cout <<hex<< *ch; //output: 64636261 //it really reinterpret the pointer Something * st = new Something(); Otherthing * ot = reinterpret_cast<Otherthing*> (st); //cast between objects with on relationship } 而以上转换,都是static_cast所不能完成的任务,也就是说把上边程序里所有的reinterpret_cast换成static_cast的话,就会立即得到编译错误,因为目标指针和原始指针之间不存在"关系" 从上边的程序,也就一下子看出来了reinterpret_cast和static_cast之间最本质的区别。 而以上转换,都是static_cast所不能完成的任务,也就是说把上边程序里所有的reinterpret_cast换成static_cast的话,就会立即得到编译错误,因为目标指针和原始指针之间不存在"关系" 从上边的程序,也就一下子看出来了reinterpret_cast和static_cast之间最本质的区别。 对于static_cast所需要的关系,"继承"绝对是其中之一,所以static_cast支持指向基类的指针和指向子类的指针之间的互相转换: class Parents { public: virtual ~Parents(){} /*codes here*/ }; class Children : public Parents { /*codes here*/ }; int main() { Children * daughter = new Children(); Parents * mother = static_cast<Parents*> (daughter); //right, cast with polymorphism Parents * father = new Parents(); Children * son = static_cast<Children*> (father); //no error, but not safe } 但是从基类到子类的转换,用static_cast并不是安全的,具体的问题会在dynamic_cast一篇阐述。 在指针和引用方便,似乎也只有继承关系是可以被static_cast接受的,其他情况的指针和引用转换都会被static_cast直接扔出编译错误,而这层关系上的转换又几乎都可以被dynamic_cast所代替。这样看起来static_cast运算符的作用就太小了。 实际上static_cast真正用处并不在指针和引用上,而在基础类型和对象的转换上。 而基于基础类型和对象的转换都是其他三个转换运算符所办不到的。 这些转换跟C++用户自定义类型转换一文中所设计的内容比较接近,所以在那边文章中出现转换可以全部加上static_cast。 基础类型转换:floatfloatValue = 21.7;intintValue = 7;cout<< floatValue / 7 <<"\t\t"<<static_cast<int> (floatValue)/7 <<endl;cout<< intValue/3 <<"\t\t"<<static_cast<double> (intValue)/3 <<endl;//Output://3.13//22.33333 从输出结果可以看出转换是成功并且正确的。 对于对象的转换,也是需要又关系的,这层关系就是C++用户自定义类型转换中提到的方法: 构造函数(Constructor) 类型转换运算符(Type –Cast Operator static_cast会根据上述顺序寻找到合适的方法进行类型转换。 赋值运算符并不被算在内,因为它自身已经是一种运算符,不能再当做转换运算符来用。 int main(void) { Ape a; Human h = static_cast<Human> (a); // using promtion constructor Programmer p; p = static_cast<Programmer> (h); // using Programmer-cast operaotor //Ape a2; //a2 = static_cast<Ape> (p); //Error, assignment operator should be used directly return 0; } (类的代码见C++用户自定义类型转换,或者下载代码查看) 传统转换方式实现static_cast运算符 从上边对static_cast分析可以跟看,static_cast跟传统转换方式几乎是一致的,所以只要将static_cast和圆括号去掉,再将尖括号改成圆括号就变成了传统的显示转换方式。在C++用户自定义类型转换一文已有很多的介绍了。 Director: Jim Fawcett C++ Language Tutorial - Type Casting Object Oriented Design IBM Complilers - XL C/C++ V9.0 for Linux - The static_cast operator (C++ only) Bjarne Stroustrup's C++ Style and Technique FAQ - What good is static_cast?

优秀的个人博客,低调大师

标准模板库(STL)学习指南之set集合

set是关联容器。其键值就是实值,实值就是键值,不可以有重复,所以我们不能通过set的迭代器来改变set的元素的值,set拥有和list相同的特性:当对他进行插入和删除操作的时候,操作之前的迭代器依然有效。当然删除了的那个就没效了。set的底层结构是RB-tree,所以是有序的。 stl中特别提供了一种针对set的操作的算法:交集set_intersection,并集set_union,差集set_difference。对称差集set_symeetric_difference,这些算法稍后会讲到。 一:set模板类的声明。 template < class key class =Traitsless<key> class Allocator=allocator<key> > class set。 其中个参数的意义如下: key:要放入set里的数据类型,可以是任何类型的数据。 Traits:这是一个仿函数(关于仿函数是什么,我后面的文章会讲到)。提供了具有比较功能的仿函数,来觉得元素在set里的排列的顺序,这是一个可选的参数,默认的是std::less<key>,如果要自己提供这个参数,那么必须要遵循此规则:具有两个参数,返回类型为bool。 Allocator:空间配置器,这个参数是可选的,默认的是std::allocator<key>. 二:set里的基本操作 我们可以通过下面的方法来实例化一个set对象 std::set<int> s;那个s这个对象里面存贮的元素是从小到大排序的,(因为用std::less作为比较工具。) 如果要想在s里面插入数据,可以用inset函数(set没用重载[]操作,因为set本生的值和索引是相同的) s.insert(3);s.insert(5)..... 因为set是集合,那么集合本身就要求是唯一性,所以如果要像set里面插入数据和以前的数据有重合,那么插入不成功。 可以通过下面的方法来遍历set里面的元素 1 2 3 4 5 std::set< int >::iterator it = s.begin(); while (it!=s.end()) { cout<<*it++<<endl; //迭代器依次后移,直到末尾。 } 如果要查找一个元素用find函数,it = s.find(3);这样it是指向3的那个元素的。可以通过rbegin,rend来逆向遍历 1 2 3 4 5 std::set< int >::reverse_iterator it = s.rbegin(); while (it!=s.rend()) { cout<<*it++<<endl; } 还有其他的一些操作在这就不一一列出了。 三:set向量的使用实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <iostream> #include <string> #include <set> #include <algorithm> #include <iterator> using namespace std; /* 联合容器将值与关键字联合在一起,使用关键字来查找值, * 提供元素的快速访问,插入元素不能指定位置,容器自动处理插入位置 * STL 提供四种联合容器:set、multiset、map、multimap * set、multiset 存储一种元素,前者关键字不可重复,后者关键字可以重复。 * map、multimap 存储一对元素键与值,前者关键字不可重复,后者关键字可以重复。 */ int main() { const int N = 3; string s1[N] = { "xp" , "python" , "linux" }; string s2[N] = { "python" , "php" , "perl" }; set<string> sa(s1, s1 + N); // 声明一个集合sa,元素为数组s1 set<string> sb(s2, s2 + N); // 声明一个集合sb,元素为数组s2 set<string> sc; // 声明一个空集合sc ostream_iterator<string, char > out (cout, " " ); copy(sa.begin(), sa.end(), out); cout << "->set sa" << endl; copy(sb.begin(), sb.end(), out); cout << "->set sb" << endl; set_union(sa.begin(), sa.end(), sb.begin(), sb.end(), out); cout << "->set_union() 并集" << endl; set_intersection(sa.begin(), sa.end(), sb.begin(), sb.end(), out); cout << "->set_intersection() 交集" << endl; set_difference(sa.begin(), sa.end(), sb.begin(), sb.end(), out); cout << "->set_difference() 集合的差" << endl; set_difference(sb.begin(), sb.end(), sa.begin(), sa.end(), out); cout << "->set_difference() 集合的差" << endl; set_union(sa.begin(), sa.end(), sb.begin(), sb.end(), insert_iterator<set<string> >(sc, sc.begin() )); sc.insert( "delphi" ); copy(sc.begin(), sc.end(), out); cout << "->set sc" << endl; copy(sc.lower_bound( "perl" ), sc.upper_bound( "python" ), out); cout << "->显示集合区间" << endl; return 0; } 作者:ACShiryu出处:http://www.cnblogs.com/ACShiryu/若非注明,本博客文章均为原创,版权归作者和博客园共有,欢迎转载,但必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。该文章也同步发布在我的新浪微博中-ACShiryu's weibo,欢迎收听。

优秀的个人博客,低调大师

《C++标准程序库》读书笔记(四)

, 复制代码 #include <iostream> #include <list> #include <algorithm> using namespace std; int main() { list<int> coll; list<int>::iterator pos25,pos35,pos; for(int i=20;i<=40;++i) coll.push_back(i); pos25 = find(coll.begin(),coll.end(),25); pos35 = find(coll.begin(),pos25,35); if(pos35!=pos25) {//pos35在pos25前 pos = find(coll.begin(),pos25,30); } else {//pos25在pos35前 pos = find(pos25,coll.end(),30); } cout<<"num: "<<*pos<<endl; system("pause"); return 0; } 复制代码 使用仿函数 复制代码 #include <functional> /* class for the compose_f_gx_hx adapter*/ template <class OP1, class OP2, class OP3> class compose_f_gx_hx_t : public std::unary_function<typename OP2::argument_type, typename OP1::result_type> { private: OP1 op1; // process: op1(op2(x),op3(x)) OP2 op2; OP3 op3; public: // constructor compose_f_gx_hx_t (const OP1& o1, const OP2& o2, const OP3& o3) : op1(o1), op2(o2), op3(o3) { } // function call typename OP1::result_type operator()(const typename OP2::argument_type& x) const { return op1(op2(x),op3(x)); } }; /* convenience function for the compose_f_gx_hx adapter*/ template <class OP1, class OP2, class OP3> inline compose_f_gx_hx_t<OP1,OP2,OP3> compose_f_gx_hx (const OP1& o1, const OP2& o2, const OP3& o3) { return compose_f_gx_hx_t<OP1,OP2,OP3>(o1,o2,o3); } 复制代码 复制代码 #include <iostream> #include <list> #include <algorithm> #include <functional> #include "compose21.hpp" using namespace std; int main() { list<int> coll; list<int>::iterator pos; for(int i=20;i<=40;++i) coll.push_back(i); pos = find_if(coll.begin(),coll.end(), compose_f_gx_hx(logical_or<bool>(), bind2nd(equal_to<int>(),25), bind2nd(equal_to<int>(),35))); cout<<"num: "<<*pos<<endl; system("pause"); return 0; } 复制代码 2,三种迭代器适配器: 1) Insert iterator 插入位置可以是容器的最前或最后,或是在某一特定位置上. 复制代码 #include <iostream> #include <vector> #include <list> #include <deque> #include <set> #include <algorithm> using namespace std; int main() { list<int> coll1; // insert elements from 1 to 9 into the first collection for (int i=1; i<=9; ++i) { coll1.push_back(i); } // copy the elements of coll1 into coll2 by appending them vector<int> coll2; copy (coll1.begin(), coll1.end(), // source back_inserter(coll2)); // destination // copy the elements of coll1 into coll3 by inserting them at the front // - reverses the order of the elements deque<int> coll3; copy (coll1.begin(), coll1.end(), // source front_inserter(coll3)); // destination // copy elements of coll1 into coll4 // - only inserter that works for associative collections set<int> coll4; copy (coll1.begin(), coll1.end(), // source inserter(coll4,coll4.begin())); // destination return 0; } 复制代码 back_inserter的内部调用push_back(),在容器尾端插入元素,只有在提供有push_back()成员函数的容器中才能使用,这样的容器有:vector,deque,list. front_inserter的内部调用push_front(),在容器最前端插入元素,只有在提供有push_ front()成员函数的容器中才能使用,这样的容器有deque和list;一般性的inserter,作用是将元素插入”初始化时接受之第二参数”所指的位置的前方.它内部调用insert(). 2)Stream iterator.这是用来读写流的迭代器. 复制代码 #include <iostream> #include <vector> #include <string> #include <algorithm> #include <iterator> using namespace std; int main() { vector<string> coll; copy (istream_iterator<string>(cin), // start of source istream_iterator<string>(), // end of source back_inserter(coll)); // destination sort (coll.begin(), coll.end()); unique_copy (coll.begin(), coll.end(), // source ostream_iterator<string>(cout,"\n")); // destination } 复制代码 3)Reverse iterator 复制代码 #include <iostream> #include <vector> #include <algorithm> #include <iterator> using namespace std; int main() { vector<int> coll; // insert elements from 1 to 9 for (int i=1; i<=9; ++i) { coll.push_back(i); } // print all element in reverse order copy (coll.rbegin(), coll.rend(), // source ostream_iterator<int>(cout," ")); // destination cout << endl; } 复制代码 3,移除元素 复制代码 #include <iostream> #include <list> #include <algorithm> #include <iterator> using namespace std; int main() { list<int> coll; // insert elements from 6 to 1 and 1 to 6 for (int i=1; i<=6; ++i) { coll.push_front(i); coll.push_back(i); } // print all elements of the collection copy (coll.begin(), coll.end(),ostream_iterator<int>(cout," ")); cout << endl; list<int>::iterator end = remove (coll.begin(), coll.end(),3);//新的尾节点 // print resulting elements of the collection copy (coll.begin(), end,ostream_iterator<int>(cout," ")); cout << endl; // print number of resulting elements cout << "number of removed elements: "<< distance(end,coll.end()) << endl; // remove ``removed'' elements coll.erase (end, coll.end()); // print all elements of the modified collection copy (coll.begin(), coll.end(),ostream_iterator<int>(cout," ")); cout << endl; } 复制代码 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2008/08/27/1278096.html,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册