Visual C++ 2008入门经典 第八章深入理解类
// 第八章深入理解类 //.cpp: 主项目文件。 /* #include "stdafx.h" #include <iostream> using namespace std; using namespace System; */ /*class CBox { public: ~CBox(){ cout<<"析构对像CBox"<<endl; } CBox(double lv=1.0, double wv=1.0, double hv=1.0): m_Length(lv), m_Width(wv), m_Height(hv) { cout<<"构造函数"<<endl; } double Volume() const { return m_Length * m_Width * m_Height; } int compare(CBox* pBox)const { return this->Volume() > pBox->Volume(); } private: double m_Length; double m_Width; double m_Height; }; int main(array<System::String ^> ^args) { CBox boxes[5]; CBox cigar(8.0, 5.0, 1.0); CBox match(2.2, 1.1, 0.5); CBox* pB1 = &cigar; CBox* pB2 = 0; cout<<"Volume of cigar is "<<pB1->Volume()<<endl; pB2 = boxes; boxes[2] = match; cout<<"Volume of boxes[2] is "<<(pB2 + 2)->Volume()<<endl; //弄不懂 system("pause"); return 0; }*/ //2 使用析构函数来释放记忆体 /*#include <cstring> class CMessage { private: char* pmessage; public: void ShowIt()const { cout<<endl<<pmessage<<endl; } CMessage(const char* text="Default message") { pmessage = new char[strlen(text) + 1]; strcpy(pmessage, text); } ~CMessage() { cout<<"Destructor called."<<endl; delete[] pmessage; } }; int main(array<System::String ^> ^args) { CMessage motto("A miss is as good as a mile."); CMessage* pM = new CMessage("A cat can look at a queen."); motto.ShowIt(); pM->ShowIt(); cout<<endl; system("pause"); return 0; }*/ //3 锻炼大于“运算符重载” /*class CBox { public: ~CBox(){ cout<<"析构对像CBox"<<endl; } CBox(double lv=1.0, double wv=1.0, double hv=1.0): m_Length(lv), m_Width(wv), m_Height(hv) { cout<<"构造函数"<<endl; } double Volume() const { return m_Length * m_Width * m_Height; } int compare(CBox* pBox)const { return this->Volume() > pBox->Volume(); } bool operator>(const CBox& aBox) const; private: double m_Length; double m_Width; double m_Height; }; bool CBox::operator>(const CBox& aBox) const { return this->Volume() > aBox.Volume(); } int main(array<System::String ^> ^args) { CBox smallBox(4.0, 2.0, 1.0); CBox mediumBox(10.0, 4.0, 2.0); CBox bigBox(30.0, 20.0, 40.0); if(mediumBox > smallBox) { cout<<"mediumBox 大于 smallBox"<<endl; }else{ cout<<"mediumBox 小于 smallBox"<<endl; } if(mediumBox > bigBox) { cout<<"mediumBox 大于 bigBox"<<endl; }else{ cout<<"mediumBox 小于 bigBox"<<endl; } system("pause"); return 0; }*/ // 4 实施一个完整的重载“大于”运算符 /*class CBox { public: ~CBox(){ cout<<"析构对像CBox"<<endl; } CBox(double lv=1.0, double wv=1.0, double hv=1.0): m_Length(lv), m_Width(wv), m_Height(hv) { cout<<"构造函数"<<endl; } double Volume() const { return m_Length * m_Width * m_Height; } int compare(CBox* pBox)const { return this->Volume() > pBox->Volume(); } bool operator>(const CBox& aBox) const; //重载运算符> bool operator>(const double& value)const { return this->Volume() > value; } private: double m_Length; double m_Width; double m_Height; }; bool CBox::operator>(const CBox& aBox) const { return this->Volume() > aBox.Volume(); } //重载一个全局的大于对比 int operator>(const double& value, const CBox& aBox) { return value > aBox.Volume(); } //8.4.3 重载赋值运算符 //如果我们不新自给类提供重载的赋值运算符函数,则编译器将提供一个默认的函数,默认的版本仅仅提供遯个成员的复制过程,与默认复制构造函数功能类似,但是不能混淆默认复制构造函数与默认赋值运算符 //默认复制构造函数是通过声明以现有同类对像进行初始化的类对像,或者通过以传值方式给函数传递对像而被调用 //返之,默认赋值运算符是在赋值语句的左边和右边是同类对像时调用的 //我们需要赋值运算符做的事情是将文本复制到目标对像所拥有的内存区域 //修正问题 CMessage& operator=(const CMessage& aMess) { delete[] pmessage; pmessage = new char[strlen(aMess.pmessage) + 1]; strcpy(this->pmessage, aMess.pmessage); return *this; //从赋值运算符函数中返回的是引用, //赋值运算符右边的对像将被复制到左边, } //注意,本地C++语言对赋值算符的形参和返回类型没有任何限制,但如果希望自己的赋值运算符函数支持C++赋值用庋 //那么以刚才描述的方式声明赋值运算符就具有现实意义 //我们需要记住的第二点微妙之外是,两个对像都已经有拥有对字符串分配的内存,因此赋值运算符函数首先要删除分配给第一个对像的内存 //然后重新分配足够的内存,以容纳属于第二个对个的字符串,做完这件事后, //就可以将来自第二个对像的字符串复制到第一个对像现在拥有的内存中 //这句是不是错了,是将第一个对像的字符串复制到第二个对像现在拥有的内存中去呢 //如果写成 mottol = mottol; CMessage& operator=(const CMessage& aMess) { if(&aMess == this){ return *this; } delete[] pmessage; pmessage = new char[strlen(aMess.pmessage) + 1]; strcpy(this->pmessage, aMess.pmessage); return *this; //从赋值运算符函数中返回的是引用, //赋值运算符右边的对像将被复制到左边, }*/ /*int main(array<System::String ^> ^args) { CBox smallBox(4.0, 2.0, 1.0); CBox mediumBox(10.0, 4.0, 2.0); CBox bigBox(30.0, 20.0, 40.0); if(mediumBox > smallBox) { cout<<"mediumBox 大于 smallBox"<<endl; }else{ cout<<"mediumBox 小于 smallBox"<<endl; } if(mediumBox > bigBox) { cout<<"mediumBox 大于 bigBox"<<endl; }else{ cout<<"mediumBox 小于 bigBox"<<endl; } if(bigBox > 100){ cout<<"bigbox:"<<bigBox.Volume()<<" 大于 100"<<endl; }else{ cout<<"bigbox:"<<bigBox.Volume()<<" 小于 100"<<endl; } if(100000 > bigBox){ cout<<" 100000 大于 bigbox:"<<bigBox.Volume()<<endl; }else{ cout<<" 100000 小于 bigbox:"<<bigBox.Volume()<<endl; } system("pause"); return 0; }*/ /* class A { public: A(){ cout<<"构造函数"<<endl; } ~A(){ cout<<"析构函数"<<endl; } }; int main(array<System::String ^> ^args) { A* pa = new A; delete pa; A* pp[2] ={new A, new A}; for(int i=0; i<2; i++){ delete pp[i]; //对像指针数组要这样删除才对 } system("pause"); return 0; }*/ //重载赋值运算符 /*#include <cstring> class CMessage { private: char* pmessage; public: void ShowIt() const { cout<<" pmessage :"<<pmessage<<endl; } //设置为*号 void Reset() { char* temp = pmessage; while(*temp){ *(temp++) = '*'; } //这里是不是也可以直接用pmessage进行操作呢 } CMessage& operator=(const CMessage& aMess) { if(&aMess == this){ return *this; } delete[] pmessage; pmessage = new char[strlen(aMess.pmessage) +1]; strcpy(this->pmessage, aMess.pmessage); return *this; } CMessage& operator+=(const CMessage& aMess) { if(&aMess == this){ return *this; } //保存自己的字符串 char* temp = new char[strlen(pmessage) + strlen(aMess.pmessage) + 1]; //cout<<"temp.lenght: "<<strlen(temp)<<endl; for(int i=0; i < static_cast<int>(strlen(pmessage)); i++){ *(temp+i) = *(pmessage+i); } for(int i=strlen(pmessage), j=0; i<static_cast<int>(strlen(temp)); i++, j++){ *(temp+i) = *(aMess.pmessage + j); } temp[strlen(temp)] = '\0'; //将所有字符串都复制到temp中去了 delete[] pmessage; pmessage = new char[strlen(temp) +1]; strcpy(this->pmessage, temp); delete[] temp; return *this; } //构造函数 CMessage(const char* text="Default message") { pmessage = new char[strlen(text) + 1]; strcpy(pmessage, text); } //析构函数 ~CMessage() { cout<<"析构函数执行"<<endl; delete[] pmessage; } }; int main(array<System::String ^> ^args) { CMessage motto1("The devil takes care of his own"); CMessage motto2; cout<<"motto2.ShowIt:"; motto2.ShowIt(); motto2 = motto1; //这里进行赋值操作,调用赋值运算符 cout<<"motto2.ShowIt:"; motto2.ShowIt(); motto1.Reset(); cout<<"motto1.ShowIt:"; motto1.ShowIt(); cout<<"motto2.ShowIt:"; motto2.ShowIt(); motto2 += motto1; cout<<"motto2 += motto1:"<<endl; motto2.ShowIt(); system("pause"); return 0; } //由此我们得到另一条黄金规则: //如果需要给类的数据成员动态分配空间,则必须实现赋值运算符 //实现赋值运算符之后,在+=这样的操作中将发生什么事情呢?除非我们实现这样的运算符,否则他们不能工作,对于希望用来处理地类对像的第种op=形式,我们都需要编写一个运算符函数*/ //8.4.4 重载加法运算符 //因为我们需要直接访问对像的成员,所以应该将operator+()实现为成员函数,该函数成员在类定义的内部声明如下 //CBox operator+(const CBox& aBox)const; /*CBox CBox::operator+(const CBox& aBox) const { return CBox(m_Length > aBox.m_Lenght ? m_Length : aBox.m_Length, m_Width > aBox.m_Width ? m_Width : aBox.m_Width, m_Height + aBox.m_Height); }*/ //练习使用我们重载的加法运算符 /*class CBox { public: CBox(double lv = 1.0, double wv = 1.0, double hv=1.0) : m_Height(hv) { m_Length = lv > wv ? lv : wv;//当长度大于宽度时, m_Width = wv < lv ? wv : lv; //当宽度大于长度时 } double Volume() const { return m_Length * m_Width * m_Height; } int CBox::operator>(const CBox& aBox) const { return this->Volume() > aBox.Volume(); } int CBox::operator>(const double& value) const { return this->Volume() > value; } CBox operator+ (const CBox& aBox) const { return CBox(m_Length > aBox.m_Length ? m_Length : aBox.m_Length, m_Width > aBox.m_Width ? m_Width : aBox.m_Width, m_Height + aBox.m_Height); } void ShowBox()const { cout<<"m_Length:"<<m_Length<<", m_Width:"<<m_Width<<", m_Height:"<<m_Height<<endl; } private: double m_Length; double m_Width; double m_Height; }; int operator>(const int& value, const CBox& aBox) { return value > aBox.Volume(); } int main(array<System::String ^> ^args) { CBox smallBox(4.0, 2.0, 1.0); CBox mediumBox(10.0, 4.0, 2.0); CBox aBox; CBox bBox; aBox = smallBox + mediumBox; cout<<"aBox dimensions are:"; aBox.ShowBox(); bBox = aBox + smallBox + mediumBox; cout<<"bBox dimensions are:"; bBox.ShowBox(); system("pause"); return 0; }*/ //我们也能够了以友元函数形式实现CBox类的加法操作,其原型如下 //friend CBox operator+(const CBox& aBox, const CBox& bBox); //8.4.5 重载递增和递减运算符 /*class Length { private: double len; public: Length& operator++(); //前自加 const Length operator++(int); //后自加 Length& operator--(); //前自减 const Length operator--(int); //后自减 } //区分重载运算符前缀和后缀形式首要方法是利用形参列表,前缀形式没有形参,后缀形式有一个int类型的形 //前自加实现 Length& Length::operator++() { ++(this->len); return *this; } //后自加实现 const Length& Length::operator++(int) { Length length = *this; ++*this; return length; } */ //8.5 类模板 /*template <class T> class CSamples { public: CSamples(const T value[], int count) { m_Free = count < 100 ? count : 100; for(int i=0; i<m_Free; i++){ m_Values[i] = value[i]; } } CSamples(const T& value) { m_Values[0] = value; m_Free = 1; } CSamples(){ m_Free = 0;} bool Add(const T& value) { bool OK = m_Free < 100; if(OK){ m_Values[m_Free++] = value; } return OK; } T Max() const { T theMax = m_Free ? m_Values[0] : 0; for(int i=0; i<m_Free; i++) { if(theMax < m_Values[i]){ theMax = m_Values[i]; } } return theMax; } private: T m_Values[100]; int m_Free; } //模板成员函数 //如果类反有两个或更多形参,则每个定义成员函数的模板也应该有同样的形参 //在模板类的外面定义构造函数或其它成员函数的方法 template<class t> CSamples<T>::CSamples(T values[], int count) { m_Free = count < 100 ? count : 100; for(int i=0; i<m_Free; i++){ m_Values[i] = values[i]; } } */ //8.5.2 根据类模板创建对像 //类模板 /*class CBox { public: CBox(double lv = 1.0, double wv = 1.0, double hv=1.0) : m_Height(hv) { m_Length = lv > wv ? lv : wv;//当长度大于宽度时, m_Width = wv < lv ? wv : lv; //当宽度大于长度时 cout<<"构造了类CBox"<<endl; //CBox的构造函数被调用了103次, //我们首先创建了一个包含三个CBox对像的数组,因此发生了三次调用, //然后创建了一个容红领巾这些对像的CSamples对像 //但CSamples对像包含的数组有100个CBox类型的变量,因此需要再调用默认构造函数100次 //每个数组元素需要一次,当然,maxBox对像将由编译器提供的默认复制构造函数创建 } double Volume() const { return m_Length * m_Width * m_Height; } int CBox::operator>(const CBox& aBox) const { return this->Volume() > aBox.Volume(); } int CBox::operator>(const double& value) const { return this->Volume() > value; } CBox operator+ (const CBox& aBox) const { return CBox(m_Length > aBox.m_Length ? m_Length : aBox.m_Length, m_Width > aBox.m_Width ? m_Width : aBox.m_Width, m_Height + aBox.m_Height); } void ShowBox()const { cout<<"m_Length:"<<m_Length<<", m_Width:"<<m_Width<<", m_Height:"<<m_Height<<endl; } private: double m_Length; double m_Width; double m_Height; }; template <class T> class CSamples { public: CSamples(const T values[], int count); CSamples(const T& value); CSamples(){ m_Free = 0;} bool Add(const T& value); T Max() const; private: T m_Values[100]; int m_Free; }; template<class T> CSamples<T>::CSamples(const T values[], int count) { m_Free = count < 100 ? count : 100; for(int i=0; i<m_Free; i++){ m_Values[i] = values[i]; } } template<class T> CSamples<T>::CSamples(const T& value) { m_Values[0] = value; m_Free = 0; } template<class T> bool CSamples<T>::Add(const T& value) { bool OK = m_Free < 100; if(OK){ m_Values[m_Free++] = value; } return OK; } template<class T> T CSamples<T>::Max() const { T theMax = m_Free ? m_Values[0] : 0; for(int i=1; i<m_Free; i++) { if(m_Values[i] > theMax){ theMax = m_Values[i]; } } return theMax; }; int main(array<System::String ^> ^args) { CBox boxes[] = {CBox(8.0, 5.0, 2.0), CBox(5.0, 4.0, 6.0), CBox(4.0, 3.0, 3.0) }; CSamples<CBox> myBoxes(boxes, sizeof boxes / sizeof CBox); CBox maxBox = myBoxes.Max(); cout<<endl; cout<<"The biggest box has a volume of: "; cout<<maxBox.Volume(); cout<<endl; system("pause"); return 0; } //CSamples对像的声明基本上与普通对像的声明相同,但是模板类名称后面增加以尖括号包围的类型形参 */ //8.5.3 使用多个形参的类模板 template<class T1, class T2> class CExampleClass { private: T1 m_Value1; T2 m_Value2; }; template<class T, int Size> class CSamples { private: T m_Values[Size]; int m_Free; public: CSamples(const T values[], int count) { m_Free = cout < Size ? count : Size; for(int i=0; i<m_Free; i++){ m_Values[i] = values[i]; } } CSamples(const T& value) { m_Values[0] = value; m_Free = 1; } CSamples() { m_Free = 0; } int Add(const T& value) { int ok = m_Free < Size; if(ok){ m_Values[m_Free++] = value; } return ok; } T Max() const { T theMax = m_Free ? m_Values[0] : 0; for(int i=0; i<m_Free; i++){ if(m_Values[i] > theMax) theMax = m_Values[i]; } return theMax; } } //当实例化模板时,我们需要小心处理那些包含比较运算符的表达式, //CSamples<aType, x> y ? 10 : 20 > MyType(); //Wrong //该语句不能正确编译,因为表达式中y前面的>被解释为右尖括号,我们应该将这条语句写成 //CSamples<aType, (x ? y ? 10 : 20)> MyTypp(); //括弧确保第二个模板实参的表达式不会与尖括号混淆 //8.6 使用类 //8.6.1 类接口 //在设关类方面,我们首先需要考虑问题的本质,并由此确定应该在类接口中提供哪里些功能 //8.6.2 定义问题 //1 计算CBox的体积,体积是CBox对像的基本特性,我们已经有实现该功能的函数 //2 比较两个CBox对像的体积,以确定那个更大,我们应该为CBox实现一套完整的比较运算符,目前已经有>运算符版本 //3 比较CBox的体积与指定的数值,反之迹然,我们已经有>运算符实现了该功能,但还需要实现支持其它比较运算符函数 //4 将两相CBox对像相加,将产生包含原来两个对像的CBox对象,因此,结果到少将是原来两个体积的和,也可能更大 // 我们已经有重载+运算符的该功能的函数版本 //5 在CBox对像乘以一个整数(反之),以提供一个CBox对像来包含指定数量的原对像,这实现上是在设计一个纸板箱 //6 确定有多少个给定尺寸的CBox对像可以放入另一个给定尺寸的CBox对像,该功能实际上是除法问题,因此可以通过重载/运算符来实现 //7 确定放入最大数量给定尺寸的CBox对像之后,CBox对像中余下空间 //8.6.3实现CBox类 /*class CBox { public: CBox(double lv=1.0, double wv=1.0, double hv=1.0) { lv = lv <= 0 ? 1.0 : lv; wv = wv <= 0 ? 1.0 : wv; hv = hv <= 0 ? 1.0 : hv; m_Length = lv > wv ? lv : wv; m_Width = wv < lv ? wv : lv; m_Height = hv; } double Volume() const { m_Length * m_Width * m_Height; } double GetLength() const { return m_Length; } double GetWidth() const { return m_Width; } double GetHeight() const { return m_Height; } CBox operator*(int n) const; private: double m_Length; double m_Width; double m_Height; }; //1 比较CBox对像 //我们重做以前定义过的operator>()函数 int operator>(const double& value, const CBox& aBox) { return value > aBox.Volume(); } //小于重载 int operator<(const double& value, const CBox& aBox) { return value < aBox.Volume(); } int operator>(const CBox& aBox, const double& value) { return aBox.Volume() > value; } //小于重载 int operator<(const CBox& aBox, const double& value) { return aBox.Volume() < value; } //重载运算符== int operator==(const double& vlaue, const CBox& aBox) { return value == aBox.Volume(); } int operator==(const CBox& aBox, const double& value) { return aBox.Volume == value; } //合并CBox对像 //现在需要解决的问题是重载+ * / %运算符 CBox CBox::operator*(int n) const { if(n % 2){ //有余数时, return CBox(m_Length, m_Width, m_Height * n); }else{ return CBox(m_Length, m_Width*2.0, m_Height * (n/2)); } } CBox operator* (int n, const CBox& aBox) { return aBox * n; } //分解CBox对像 //胶面曾经说过,除法操作确定左操作数指定的CBox对像可以包含多少个右操作数指定的CBox对像// //为了使问题相对简单,我们假设所有CBox对像都是以正常层新序包装诉即高度是垂直的 //另外假设它们都是以相同的朝向包装的,即长度方向相同,如果没有这些假设,问题可能变得相当复杂 //这样,该问题实际上就变成求出一层可以放多少个右操作数对像,再求出左操作数对像中可以放几层 int operator/(const CBox& aBox) { int tc1 = 0; int tc2 = 0; tc1 = static_cast<int>((m_Lenght / aBox.m_Lenght)) * static_cast<int>((m_Width / aBox.m_Leight));//2 * 3 = 6 tc2 = static_cast<int>((m_Length / aBox.m_Width)) * static_cast<int>((m_Width / aBox.m_Leight));//4 * 2 = 8 //理解了 return static_cast<int>((m_Height / aBox.m_Height) * tc1 > tc2 ? tc1 : tc2); } //该函数首先求出左,右操作数CBox对像的长度方赂相同时,一层可以容纳多少个右操作数CBox对像 //并将结果存入ct1中 //然后再求出右操作数CBox的长度与左操作CBox的宽度同向时,一层可以容纳多少个右操作数对像, //最后 使ct1 和ct2 中较大的数乘以可以包装的层数,并返回得到的数值, double operator%(const CBox& aBox, const CBox& bBox) { return aBox.Volume() - ((aBox/bBox)*bBox.Volume()); }*/ //8.7 组织程序代码 //还有其他向种用于说明像菜单和工具按钮这样一些对像的定义,这些定义被存储在扩展名为.rc和.ico的文件中 //命名程序文件 //8.8 字符串本地C++库类 //这些字符串类型比以空字符结尾的字符串容易使用得多,它们还配备了一整套有用的函数 //string类型上下文件中的功能与用法跟wstring一样,除了字符串包含有Unicode字符代码,并且必须在代码中字符串字面值前加上前缀L外, //wstring的运行与string类型的全完一样的 //8.8.1 创建字符串对象 /*#include "stdafx.h" #include <iostream> #include <string> using namespace std; using namespace System; int main(array<System::String ^> ^args) { //string sentence = "This sentence is false."; //由于字符串对像末尾没有空字符,因此字符串长度是字符中的字符个数 //cout<<"sentence.length:"<<sentence.length()<<endl; //我们也可以像下面这样将字符串读到字符串对像中国 //cin>>sentence; //getline(cin,sentence, '*'); //第一个实参是该流(作为输入源)它不一定是cin //第二个实参是接收输入的对像, //第三个实参是终止读取的字符 //另一种可能性是通过重复一个字符指定的次数来初始化字符对像 //string bess(7,'b'); //cout<<"bess:"<<bess<<endl; //string sentence("This sentence is false."); //string part(sentence, 5, 11); //cout<<"part:"<<part<<endl; //8.8.2 连接字符串 //string sentence1("This sentence is false."); //string sentence2("Therefore the sentence above must be true!"); //string combined; //sentence1 = sentence1 + "\n"; //sentence1 +="\n"; //combined = sentence1 + sentence2; //cout<<combined<<endl; //使用+=运算符与使用+运算符有一个区别,正如本书所指出的,+运算符创建一个包含合并后的字符串的新字符串对像, //+=运算符将作为右操作数的字符串字符附加到作为左操作数的string对像后面,因此直接修改string对像,而不创建新的对像 system("pause"); return 0; }*/ /*#include "stdafx.h" #include <iostream> #include <string> using namespace std; using namespace System; void listnames(string name[], string age[], size_t count) { size_t i =0; cout<<"开始循环用户名信息"<<endl; while(i < count && !name[i].empty()){ cout<<name[i]<<" aged " + age[i]<<endl; i++; } } int main(array<System::String ^> ^args) { const size_t count = 2; string names[count]; string ages[count]; string firstname; string secondname; for(size_t i=0; i<count; i++) { cout<<endl<<"请输入姓,退出请输入回车:"<<endl; getline(cin,firstname,'\n'); if(firstname.empty()) { listnames(names, ages, count); cout<<"Done!!"<<endl; return 0; } cout<<"请输入名:"<<endl; getline(cin,secondname,'\n'); names[i] = firstname+' '+secondname; cout<<"Enter "+names[i]<<" 的年龄是:"<<endl; getline(cin,ages[i],'\n'); } cout<<"No space for more names."<<endl; listnames(names, ages, count); cout<<"输入一样,只有这样了"<<endl; cin>>firstname; system("pause"); return 0; }*/ //8.8.3 访问与修改字符串 /*#include "stdafx.h" #include <iostream> #include <string> using namespace std; using namespace System; int main(array<System::String ^> ^args) {*/ //string sentence("Too many cooks spoil the broth."); //cout<<"sentence:"<<sentence<<endl; //for(size_t i = 0; i<sentence.length(); i++) //{ //if(sentence[i] == ' '){ //sentence[i] = '*'; //sentence.at(i) = '*'; //} //} //用at()成员数与用[]运算符得到的结果相同 //使用[]与使用at()的区别在是利用下标比使用at()函数快,不过缺点是没有检查索引的有效性,如果索引超出了范围, //那么使用下标运算符的结果将不确定了 //string sentence("Too many cooks spoil the broth."); //string substring = sentence.substr(4, 10);//从索引4开始取十个字符 //cout<<"substring:"<<substring<<endl; //substr()函数的第一个实参是要提取的字串的第一个字符位置,第二个实参是子串中的字符个数 //通过使用字符串对像的append()函数,我们可以在字符串末尾添加一个或多个字符,该函数有同个版本 /*string phrase("The higher"); string word("fewer"); phrase.append(1, ' '); //一个字符 phrase.append("the "); //一个字符串 phrase.append(word); //一个字符串变量 phrase.append(2,'!'); //两个! cout<<"phrase:"<<phrase<<endl;*/ //如果我们想向一个字符串后面除加一个字符,可以用push_back()函数作为append()的替换函数 //string phrase("The higher"); //phrase.push_back('*'); //cout<<"phrase:"<<phrase<<endl; //字符串中间的某个位置插入一个或多个字符,insert()函数的各种版本 /*string saying("A horse"); string word("blind"); string sentence("He is as good as gold."); string phrase("a wink too far"); saying.insert(1, " "); //在索引1后面加上空格 saying.insert(2, word); //在索引2后面加上word saying.insert(2,"nodding", 3); //在索引2后面加上nodding的前三个字符 saying.insert(5, sentence, 2, 15); //在索引5开始插入sentence从2到15的字符 saying.insert(20, phrase, 0, 9); saying.insert(29," ").insert(30, "a poor do", 0, 2); cout<<"saying:"<<saying<<endl;*/ //通过swap()成员函数来交换封装在两个string对像之间的字符串 /*string phrase("The more the merrier."); string query("Any"); query.swap(phrase); cout<<"phrase:"<<phrase<<endl; cout<<"query:"<<query<<endl;*/ //如果我们需要将一个字符串对像转换为以空字符结尾的字符串,可以用c_str()函数来完成 //string phrase("The higher the fewer"); //const char *pstring = phrase.c_str(); //cout<<"pstring:"<<pstring<<endl; //c_str()函数返回一个指向以空字符结尾的字符串的指针,该字符串的内容与string对像相同, //会不会多个字符串结束符呢?没说 //通过调用字符串对像的replace()成员函数来替换字符对像的一部分 /*string proverb("A nod is as good as a wink to a blind horse"); string sentence("It's bath time!"); proverb.replace(38, 5, sentence, 5, 3); cout<<"proverb:"<<proverb<<endl;*/ //8.8.4 比较字符串 /*string dog1("St Bernard"); string dog2("Tibetan Mastiff"); if(dog1 < dog2){ cout<<"dog2 大于 dog1"<<endl; }else{ cout<<"dog2 小于 dog1"<<endl; }*/ //实际上是比罗对应的字符,直到发现一个不同的字符 /* system("pause"); return 0; }*/ /*#include "stdafx.h" #include <iostream> #include <string> #include <iomanip> using namespace std; using namespace System; string* sort(string* strings, size_t count) { bool swapped = false; while(true) { //循环 for(size_t i=0; i<count-1; i++){ if(strings[i] > strings[i+1]){ //如果当前字符大于他的下一个字会 swapped = true; strings[i].swap(strings[i+1]); } } //如果已经没有for循环了,直接退出while if(!swapped){ break; } //重载设置为false swapped = false; } return strings; } //用>运算符比较strings数组中的遯个元素,如果一对元素中第一个元素大于第二个元素,就交换这两个元素,在这种情况下,通过调用一个string对像的swap()函数,并将另一个string对像作为实参来交换元素,当有必须要继承时对整个数组的元素靛个比较并进行交换 int main(array<System::String ^> ^args) { const size_t maxstrings = 100; string strings[maxstrings]; size_t nstrings = 0; size_t maxwidth = 0; while(nstrings < maxstrings) { cout<<"请输入字符串:"<<endl; getline(cin,strings[nstrings],'\n'); //保存 //最大的宽度,小于指定的字符串长度 //取得输入最大长度的字符串 if(maxwidth < strings[nstrings].length()) maxwidth = strings[nstrings].length(); //保存字符串的长度 if(strings[nstrings].empty()){ break; //如果为空退出while } nstrings++; } sort(strings, nstrings); setiosflags(ios::left); for(size_t i=0; i<nstrings; i++) { if(i % 5 == 0){ cout<<endl; } cout<<setw(maxwidth+2)<<strings[i]; } cout<<endl; system("pause"); return 0; }*/ //8.8.5 搜索字符串 //搜索给定字符或子串的string对像的find()函数 //find()函数的各个版本都返回发现字符或子串的第一个字符的索引位置,如果没有找到要找的条目,该函数会返回值string::npos; //后一个值是在string类中定义的一个常量,表示string对像中的一个非法位置 /*#include "stdafx.h" #include <iostream> #include <string> using namespace std; using namespace System; int main(array<System::String ^> ^args) { string phrase("So near and yet so far"); string str("So near"); cout<<phrase.find(str)<<endl; cout<<phrase.find("so far")<<endl; cout<<phrase.find("so near")<<endl; //string::nops的值可能根据不同的C++编译器实现不同,因此为了测试它,我们应该总是使用string::npos,而不是使用显式的值 //cout<<"nops:"<<string::npos<<endl; system("pause"); return 0; }*/ //反复扫描同一个字符串以搜索出现的特定子串 /*#include "stdafx.h" #include <iostream> #include <string> using namespace std; using namespace System; int main(array<System::String ^> ^args) { string str("Smith, where jones had had \"had had\", \"had had\" had." "\"Had had\" had had the examiners' approval."); string substr("had"); cout<<"查询字符串:"<<substr<<endl; size_t offset = 0; //开始位置 size_t count = 0; //总数 size_t increment = substr.length(); //被查询字符长度 while(true) { offset = str.find(substr, offset); //开始查询字符substr if(offset == string::npos) //已经没有字符串了,offset为string::npos { break; } offset += increment; //重新设置offset为当前位置加上substr字符的长度 count++; //找到的字符总数自加 } cout<<" 一共找到了字符'"<<substr<<"'字符"<<count<<"次"<<endl; system("pause"); return 0; }*/ //find_first_of()和find_last_of()成同函数在string对像中搜索出现的给定集合中的任何字符 //例如,我们可能在字符串中搜索空格或标点符号(它们可以用来将一个字符串分解为单个单词) /*#include "stdafx.h" #include <iostream> #include <string> using namespace std; using namespace System; int main(array<System::String ^> ^args) { string str("Smith, where jones had had \"had had\", \"had had\" had." "\"Had had\" had had the examiners' approval."); string substr("had"); cout<<"查询字符串:"<<substr<<endl; //size_t offset = 0; //开始位置 size_t offset = string::npos; //设置为string值的最大值,反正很大 //cout<<"string::npos:"<<string::npos<<endl; size_t count = 0; //总数 while(true) { offset = str.find_last_of(substr, offset); //从offset索引后一次出现的以空字符结尾的字符串pstr中的任何字符 cout<<"offset:"<<offset<<endl; if(offset == string::npos){ break; } --offset; //当前位置--,也就是向左移动一位, ++count; } cout<<" 一共找到了字符'"<<substr<<"'字符"<<count<<"次"<<endl; system("pause"); return 0; }*/ //唉,刚才没看后面,我们在搜索字符str中出现的"had"中的任何字符 //"had"和"Had"单词中有32个 //find_first_not_of()和find_last_not_of() //排序文本中的单词 /*#include "stdafx.h" #include <iostream> #include <iomanip> #include <string> using namespace std; using namespace System; string* sort(string* strings, size_t count) { bool swapped = false; while(true) { for(size_t i = 0; i<count-1; i++) { if(strings[i] > strings[i+1]){ swapped = true; //设置为true,表示有数据交换,要进行下一次for循环 strings[i].swap(strings[i+1]); } } if(swapped == false){ break; } swapped = false; } return strings; }; int main(array<System::String ^> ^args) { const size_t maxwords(100); //定义常量maxwords string words[maxwords]; //定义words数组 string text; string separators(" \".,:;!?()\n"); //一些特殊字符的string串 size_t nwords = 0; size_t maxwidth = 0; cout<<"请输入一串数据以星(*)号结束输入:"<<endl; getline(cin,text,'*'); //保存输入的文本 size_t start(0), end(0), offset(0); //定义开始结束当前的索引值 while(true) //开始while { start = text.find_first_not_of(separators, offset); //从开始查询不是separators内出现的字符位置 if(start == string::npos) //如果已经到了最后,或者已经没有不是separators字会的时候 { break; } offset = start + 1; //将当前索引值加1,也就是向左移动一个字符位 end = text.find_first_of(separators, offset); //现在开始从offset人位置向下搜索第一次出现separators字符串的任意一个字符的位置 if(end==string::npos){ offset = end; //设置offset为end end = text.length(); //设置为text的长度 }else{ offset = end+1; //向左移动一位 } words[nwords] = text.substr(start, end-start); //切取一个从start到end-start位置中间的字符 //放入数组中去 //计算保存最长的字符串 if(maxwidth < words[nwords].length()) { maxwidth = words[nwords].length(); } //如果已经到了最后,直接退出 if(offset == string::npos){ break; } //如果words数组所保存的值已经达到了最大的值,就不用在处理了 if(++nwords == maxwords) { cout<<"数组已经达到最大值,不用在处理了"<<endl; break; } } //开始进行排序 sort(words, nwords); cout<<endl<<"现在开始循环我们所进行排序之后的字符数组"<<endl; size_t count(0); for(size_t i=0; i<nwords; i++) { if(count == 0){ count = 1; }//如果count为0的时候,表示该字符刚出现一次 //如果当前的字符串与他的下一对字符相同 //并且i大于最大长度减去2 //循环条件也检查索引i是否小于nwords-2,若当前单词是数组中的最后一个单词,我们就不用检查了下一个单词了, //因此,当下一个单词与当前单词不同,或者当前单词是数组的最后一个单词时,我们仅输出一个单词和它的计数 if(i<nwords-2 && words[i] == words[i+1]){ ++count; //把该字符出现的次数加一 continue; } cout<<setiosflags(ios::left) <<setw(maxwidth+2)<<words[i]; cout<<resetiosflags(ios::right) <<setw(5)<<count<<endl; count = 0; } system("pause"); return 0; }*/