Visual C++ 2008入门经典 第六章 程序结束
// 第六章 程序结束 //(二).cpp: 主项目文件。 //1 什么函数指针 //2 如何定义和使用函数指针 //3 如果定义和使用函数指针的数组 //4 异常的概念,如何编定处理异常和异常处理程序 //5 如何编写多个同名函数,以自动处理不同类型的数据 //6 函数模板的概念,如何定义和使用函数模板 //7 如何使用我个函数编写有实际价值的本地C++程序示例 //8 C++/CLI中类函数的概念 //9 如何使用多个函数编写有有实际价值的C++/CLI程序示例 #include "stdafx.h" #include <iostream> using namespace std; using namespace System; //6.1 函数指针 //指针还可以指向函数的地址,该功能使我们可以通过指针来调用函数,最近一次赋给指针的地址所包含的函数将被调用 //6.1.1 声明函数指针 //double (*pfun)(char*, int); //最初,我们可能发现第一对括弧使该语句看起来有点怪异,该语句声明一个名为pfun的指针,它可以指向接受两个类型的char*和int的实参,返回值类型为double的函数 //包围指针名称pfunc的括弧和星号,都是必不可少的,如果没有它们,该语句将是函数声明而非指针声明 //在这种情况下,访语句将成为下面的样子 //声明函数指针的通式如下 //return_type (*pointer_name)(list_of_parameter_types); //注意:这种指针只能指向具有声明中指定的return_type和list_of_parameter_types的函数 //指向函数的返回类型 //指针名称(前面是指明其指针身分的星号) //指向函数的形参类型 //long sum(long num1, long num1); //long (*psum)(long, long) = sum; //如同指向变量的指针一样,我们必须确保函数指针在调用函数之前被初始化,如果没有被初始化,则必定会出现致命的程序错误 /*long sum(long a, long b); long product(long a, long b); int main(array<System::String ^> ^args) { long (*pfun)(long, long); pfun = product; cout<<"3*5 = "<<pfun(3,5)<<endl; //15 pfun = sum; //把函数指针重新指向了sum函数 cout<<endl; // (3 * (4+5) + 6) cout<<" (3 * (4+5) + 6) = "<<pfun( product(3, pfun(4,5) ), 6)<<endl; system("pause"); return 0; } long sum(long a, long b) { return a+b; } long product(long a, long b) { return a*b; }*/ //6.1.2 函数指针作为实参 //因为"指向函数的旨针"是完全合理的类型,所以函数还可以拥有类型为函数指针的形参,然后,这样的函数可以调用实参指向的函数 //指针在不同的环境中可以指向不同的函数,这使得某个数内部调用的具体函数可以由调用程序决定,这种情况下,我们可以显式传递函数名作为实参 /*double squared(double); double cubed(double); double sumarray(double ar[], int len, double(*pfun)(double)); int main(array<System::String ^> ^args) { double arr[] = {1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5}; int len = sizeof(arr) / sizeof(arr[0]); cout<<"sum of squares = "<<sumarray(arr, len, squared)<<endl; cout<<"sum of cubes = "<<sumarray(arr, len, cubed)<<endl; system("pause"); return 0; } double squared(double x) { return x*x; } double cubed(double x) { return x*x*x; } double sumarray(double ar[], int len, double(*pfun)(double)) { double total = 0.0; for(int i=0; i<len; i++) { total += pfun(ar[i]); } return total; }*/ //6.1.3 函数指针的数组 //如同常规指针一样,我们可以用相同的方式来声明函数指针的数组,还可以在声明语句中将它们初始化 /*double squared(double); double cubed(double); double sumarray(double ar[], int len, double(*pfun)(double)); int main(array<System::String ^> ^args) { //定义函数指针数组 double (*pfun[2])(double)={ squared, cubed}; cout<<"2的平方是:"<<pfun[0](2)<<endl; cout<<"2的立方是:"<<pfun[1](2)<<endl; system("pause"); return 0; } double squared(double x) { return x*x; } double cubed(double x) { return x*x*x; } double sumarray(double ar[], int len, double(*pfun)(double)) { double total = 0.0; for(int i=0; i<len; i++) { total += pfun(ar[i]); } return total; }*/ //6.2 初始化函数形参 /*void showit(const char message[] = "Something is wrong") { cout<<message<<endl; } int main(array<System::String ^> ^args) { const char mymess[] = "The end of the world is nigh."; showit(); showit("something is terribly wrong!"); showit(); showit(mymess); system("pause"); return 0; }*/ //如果函数有多个实参,那么我们可以给任意个数的实参提供初值,如果我们想省略多个实参以利用默认值,则被省略的实参中最左边那个实参右边的所有实参同样者必须省略掉 //由此可以得出结论,我们应该将拥有默认值的参数依次全部放在函数原型中形参列表中最后,使最可能被省略的参数最后出现 //6.3 异常 //异常机制处理需要三个关键字 //try----标识可能出现异常的代码块 //throw--使异常状态产生 //catch--标识处理异常的代码块 /*int main(array<System::String ^> ^args) { int counts[] = {34,54,0,27,0,10,0}; int time = 60; for(int i=0; i<sizeof(counts)/sizeof(counts[0]); i++) { try{ cout<<"Hour "<<i+1<<endl; if(counts[i] == 0) { //throw "Zero count - calculation not possible."; throw i; } cout<<"生产数为:"<<static_cast<double>(time)/counts[i]<<endl; //}catch(const char message[]) }catch(const int index) { cout<<"第:"<<index<<" 次机器停机 "<<endl; } } system("pause"); return 0; }*/ //6.3.1 抛出异常 //异常也可以从try代码块调用的函数中抛出,并被try代码块后面的catch代码块捕获, /*void testThrow(void) { throw "Zero count - calculation not possible."; } int main(array<System::String ^> ^args) { int counts[] = {34,54,0,27,0,10,0}; int time = 60; for(int i=0; i<sizeof(counts)/sizeof(counts[0]); i++) { try{ cout<<"Hour "<<i+1<<endl; if(counts[i] == 0) { testThrow(); } cout<<"生产数为:"<<static_cast<double>(time)/counts[i]<<endl; }catch(const char message[]) { cout<<"message:"<<message<<endl; } } system("pause"); return 0; }*/ //6.3.2 捕获异常 //在前面的示例中,try代码块后面的catch代码块将捕获任何const char[]类型的异常,这取决于catch关键字后面的括中出现参说明 //如果希望使某个catch代码块处理try代码块中抛出的任何异常,则必须将省略号(...)放入包围异常的声明的括弧之间 //catch(...){} /*int main(array<System::String ^> ^args) { int height = 0; const double inchesToMeters = 0.0254; char ch='y'; try{ while(ch=='y' || ch=='Y') { cout<<"请输入高度:"<<endl; cin>>height; try{ if(height > 100){ throw "高度的最大值不能大于100"; } if(height < 10) { throw height; } cout<<static_cast<double>(height)*inchesToMeters<<" meters "<<endl; }catch(const char Message[]) { cout<<"Message:"<<Message<<endl; return 0; } cout<<"Do you want to continue(y or n)"; cin>>ch; } }catch(const int badHeight) { cout<<badHeight<<" inches is below minimum"<<endl; return 0; } system("pause"); return 0; } //该标例中外部try代码包围着while循环,内部try代码块可能抛出两种不同类型的异常 //const char[]类型的异常被对应内部的try代码块的catch代码块捕获,但int类型异常没有与内部try代码块相关的异常处理程序,因此 //外部try代码中的catch处理程序将被执行,这种情况下,程序将立即终止,因为catch代码块后面的语句为return */ //6.3.3 MFC中的异常处理 //MFC中的TRY THROW CATCH 它们是的MFC内定义的宏,产生于C++语言实现异常处理机制之前 //与try throw catch操作一样 //当使用抛出异常的MFC函数时,我们需要记住一点细微的不同,抛出异常的MFC函数通常抛出类类型的异常 //6.4 处理内存分配错误 /*#include<new> int main(array<System::String ^> ^args) { char* pdata = 0; size_t count = ~static_cast<size_t>(0)/2; cout<<"count:"<<count<<endl; try { pdata = new char[count]; cout<<"Memory allocated."<<endl; }catch(bad_alloc &ex) { cout<<"Memor allocation failed."<<endl; cout<<"The information from the exception object is:"; cout<<ex.what()<<endl; } delete pdata; system("pause"); return 0; }*/ //6.5 函数重载 //6.5.1 函数重载的概念 //数重载允许我们使用相同的函数名定义多个函数,条件是这些函数的形参表各不相同 /*int max(int ar[], int len); long max(long ar[], int len); double max(double ar[], int len); int main(array<System::String ^> ^args) { int small[] ={1,24,34, 22}; long medium[] = {23,245,123,1,234,2345}; double large[] = {12.0,1.4,2.456,345.6,12.0,21.0}; int Lsmall = sizeof(small) / sizeof(small[0]); int Lmedium = sizeof(medium)/sizeof(medium[0]); int Llarge = sizeof(large)/sizeof(large[0]); cout<<"small的最大值为:"<<max(small,Lsmall)<<endl; cout<<"medium的最大值为:"<<max(medium,Lmedium)<<endl; cout<<"large的最大值为:"<<max(large,Llarge)<<endl; system("pause"); return 0; } int max(int ar[], int len) { int max = ar[0]; for(int i=0; i<len; i++) { if(max < ar[i]){ max = ar[i]; } } return max; } long max(long ar[], int len) { long max = ar[0]; for(int i=0; i<len; i++) { if(max < ar[i]){ max = ar[i]; } } return max; } double max(double ar[], int len) { double max = ar[0]; for(int i=0; i<len; i++) { if(max < ar[i]){ max = ar[i]; } } return max; }*/ //6.5.2 何时重载函数 //函数重载的意图是清楚的,允许使用单个函数名,以不同的操作数执行相同的操作,因此,只要有多个函数执行本质上相同的操作,但使用不同类型的实参,我们就应该重载这些函数,并使用相同的函数名 //6.6 函数模板 //函数模板有一个或多个类型形参,我们通过给模板每个形参提供具体的类型实参来生成具体的函数,因此, //函数模板生成的函数都有相同的基本代码,但因为我们提供的类型实参而各不相同,通过前面示例中的max()函数定义一个函数模板 /*template<class T>T max(T ar[], int len) { T max = ar[0]; for(int i=0; i<len; i++) { if(max < ar[i]){ max = ar[i]; } } return max; }*/ //template关健字将上面的代码标识为模板定义,template关键字后面的尖括号包围着以逗号分开的,用来创建具体函数实例的类型形参, //本例中我们只有一个类型形参T,T前面的关键字class表示,T是该模板类型形 //class是表示类型的通用术语 //可以使用关键字typename代替class来标识函数模板中的形参 /*template<typename T>T max(T ar[], int len); int main(array<System::String ^> ^args) { int small[] ={1,24,34, 22}; long medium[] = {23,245,123,1,234,2345}; double large[] = {12.0,1.4,2.456,345.6,12.0,21.0}; int Lsmall = sizeof(small) / sizeof(small[0]); int Lmedium = sizeof(medium)/sizeof(medium[0]); int Llarge = sizeof(large)/sizeof(large[0]); cout<<"small的最大值为:"<<max(small,Lsmall)<<endl; cout<<"medium的最大值为:"<<max(medium,Lmedium)<<endl; cout<<"large的最大值为:"<<max(large,Llarge)<<endl; system("pause"); return 0; } template<typename T>T max(T ar[], int len) { T max = ar[0]; for(int i=0; i<len; i++) { if(max < ar[i]){ max = ar[i]; } } return max; } //注意,使用模板不能减小已编译程序的大小,因为即使现有的函数版本可以强制转换为相应的实参而满足使用要求,但编译器仍然可能自动创建 //新版本*/ //6.7 使用函数的示例 //6.7.1 实现计算器 //6.7.2 从字符串中删除空格 //将eatspaces()函数的原型写成下面这样 // void eatspaces(char* str); /*#include <cstdlib> #include <cctype> void eatspaces(char* str) { int i=0; int j=0; while( (*(str+i) = *(str+(j++))) != '\0') { if(*(str+i) != ' '){ i++; } }//如果为空那么i就不会自加,但是j还是会自加的,所以这就成了去掉空格的方式 } //6.7.3 计算表达式的值 double expr(char* str) { double value = 0.0; int index = 0; //用理字符串的当前位置 value = term(str, index); //term()函数的形参应该是一个char*指针和一个int变量,第二个形参是提供的字符串相应的项的第一个字符索引 //term()函数应该更新传递过来的索引值,使其指向找到的这一项中最后一个字符后面的字符 //term()函数应该返回doulble类型的值 for(;;) { switch( *(str+ (index++))) { case '\0'; return value; case '+': value += term(str, index); break; case '-': value -= term(str, index); break; default: cout<<endl; cout<<"Arrrgh~*#!! There's an error"; exit(1); } } } //6.7.4 获得项值 //double term(char* str, int& index); double term(char* str, int& index) { double value = 0.0; value = number(str, index); //取得首数字值 while( (*(str + index)=='*') || (*(str+index) == '/') ) { if(*(str+index) == '*'){ value *= number(str, ++index); } if(*(str+index) == '/'){ value /= number(str, ++index); } } } //6.7.5 分析数 //double number(char* str, int& index); //<cctype>头文件中测试符的函数 //int isalpha(int c); //如果实参是字母,则返回true,否则返回false //int isupper(int c); //如果实参是大写字母,则返回true,否则返回false //int islower(int c); //如果实参是小写字母,则返回true,否则返回false //int isdigit(int c); //如果实参是数字,则返回true,否则返回false double number(char* str, int& index) { double value = 0.0; //存储找到的数的值 while(isdigit(*(str + index))) value = 10 * value + (*(str+(index++)) - '0'); //数字字符的ASCII仁政是48(对应于数字0) 和57(对应于数字9) //因此,如果我们发现令某个数字的ASCII代码减去0的ASCII代码,,是该数字将被转换为等价的从0-9的数值, //包围子表达*(str + index++) -'0'的括弧不是必需的,但是可以使我们的意图更析明确 //在加入数值之前,我们将变量value的内容乘以10 //从而使value向左移动一位,因为我们是从左边向右寻找数字的-即首先寻找最高有效位,该过程如图6-6所示 //作为十进制值的ASCII码 // 5 1 3 // 53 49 51 //第一个数 value=10*value+(53-48); //10*0.0+5 //5.0 //第二个数 vlaue = 10 * value + (49-48); //10*5.0+1 //51 //第三个数 value = 10 * value + (51-48); //10*51.0+3 //513 if(*(str + index) != '.') //如果是小数点,那么进行下面的循环,如果不是直接退出循环 return val; double factor = 1.0; while(isdigit(*(str+(++index)))) { factor *= 0.1; value = value + (*(str+index) - '0'); } //如果是小数点,我们就在第二个循环中累计对应于小数部分的数字,在该循环中,我们使用初值为1.0的factor变量来设定当前数字的小数位 //因为每发现一个字符就令factor乘以0.1 //这样,小数点后面的第一个数字将乘以0.1,第二个数乘以0.01,第三个数乘以0.001,以此类推 //作为十进制值的ASCII码 513. 6 0 8 // 46 54 48 56 //小数点之前 //value = 513.0 //factor = 0.1 //第一个数字 value = value + factor * (54-48); //=513 + 0.1 * 6 //=513.60 //第二个数字 value = value + factor*(48-48); //=513.60 + 0.01*0 //=513.60 //第三个数 value = value + factor*(56-48); //513.60 + 0.001 * 8 //513.60 * 0.008 //513.608 return value; } */ //6.7.6整合程序 /*#include <cstdlib> #include <cctype> void eatspaces(char* str); double expr(char* str); double term(char* str, int& index); double number(char* str, int& index); const int MAX = 80; int main() { char buffer[MAX] ={0}; cout<<endl; cout<<"Welcome to your friendly calculator."; cout<<endl; cout<<"Enter an expression, or an empty line to quit."; cout<<endl; for(;;) { cin.getline(buffer, sizeof buffer); eatspaces(buffer); if(!buffer[0]){ return 0; } cout<<"buffer:"<<buffer<<endl; cout<<"\t = "<<expr(buffer); cout<<endl<<endl; } } void eatspaces(char* str) { int i=0; int j=0; while( (*(str+i) = *(str+(j++))) != '\0') { if(*(str+i) != ' '){ i++; } } } double expr(char* str) { double value = 0.0; int index = 0; //用理字符串的当前位置 value = term(str, index); for(;;) { switch( *(str+ (index++))) { case '\0': return value; case '+': value += term(str, index); break; case '-': value -= term(str, index); break; default: cout<<endl; cout<<"Arrrgh~*#!! There's an error"; exit(1); } } } double term(char* str, int& index) { double value = 0.0; value = number(str, index); cout<<"term.value = "<<value<<endl; while( (*(str + index)=='*') || (*(str+index) == '/') ) { if(*(str+index) == '*'){ value *= number(str, ++index); } if(*(str+index) == '/'){ value /= number(str, ++index); } } return value; } double number(char* str, int& index) { double value = 0.0; //存储找到的数的值 while(isdigit(*(str + index))) value = 10 * value + (*(str+index++) - '0'); if(*(str + index) != '.') //如果是小数点,那么进行下面的循环,如果不是直接退出循环 return value; double factor = 1.0; while(isdigit(*(str+(++index)))) { factor *= 0.1; value = value + (*(str+index) - '0') * factor; } return value; }*/ //对上面的例子进行扩展版 //如果加()进行计算 这里没有ppt只能从源码进和分析了 /*#include <cstdlib> #include <cctype> void eatspaces(char* str); double expr(char* str); double term(char* str, int& index); double number(char* str, int& index); char* extract(char* str, int& index); //定义extract返回的是一个char指针 const int MAX = 80; int main() { char buffer[MAX] ={0}; cout<<endl; cout<<"Welcome to your friendly calculator."; cout<<endl; cout<<"Enter an expression, or an empty line to quit."; cout<<endl; for(;;) { cin.getline(buffer, sizeof buffer); eatspaces(buffer); if(!buffer[0]){ return 0; } cout<<"buffer:"<<buffer<<endl; cout<<"\t = "<<expr(buffer); cout<<endl<<endl; } } void eatspaces(char* str) { int i=0; int j=0; while( (*(str+i) = *(str+(j++))) != '\0') { if(*(str+i) != ' '){ i++; } } } double expr(char* str) { double value = 0.0; int index = 0; //用理字符串的当前位置 value = term(str, index); for(;;) { switch( *(str+ (index++))) { case '\0': return value; case '+': value += term(str, index); break; case '-': value -= term(str, index); break; default: cout<<endl; cout<<"Arrrgh~*#!! There's an error"; exit(1); } } } double term(char* str, int& index) { double value = 0.0; value = number(str, index); cout<<"term.value = "<<value<<endl; while( (*(str + index)=='*') || (*(str+index) == '/') ) { if(*(str+index) == '*'){ value *= number(str, ++index); } if(*(str+index) == '/'){ value /= number(str, ++index); } } return value; } double number(char* str, int& index) { double value = 0.0; //存储找到的数的值 //这个是新添加的用来处理有'('的计算表达式 if(*(str+index) == '(') { char* psubstr = 0; //指向子串 psubstr = extract(str, ++index); //提取括号内的子串 value = expr(psubstr); //获取值的子串 delete[] psubstr; //清空在自由区存储区 return value; //返回子字符串的值 } while(isdigit(*(str + index))) value = 10 * value + (*(str+index++) - '0'); if(*(str + index) != '.') //如果是小数点,那么进行下面的循环,如果不是直接退出循环 return value; double factor = 1.0; while(isdigit(*(str+(++index)))) { factor *= 0.1; value = value + (*(str+index) - '0') * factor; } return value; } char* extract(char* str, int& index) { char buffer[MAX]; //新的buffer字符串 char* pstr = 0; //返回新的字符串的指针 int numL = 0; //计数的左括号发现 int bufindex = index;//保存初始值的索引 do { buffer[index - bufindex] = *(str + index); switch(buffer[index - bufindex]) { case ')': if(numL == 0){ size_t size = index - bufindex; buffer[index - bufindex] = '\0'; ++index; pstr = new char[index - bufindex]; if(!pstr){ cout<<"Memorty allocation failed."; exit(1); } strcpy_s(pstr, index-bufindex, buffer); return pstr; }else{ numL--; } break; case '(': numL++; break; } }while(*(str+ index++) != '\0'); cout<<"Ran off the end of the expression, must be bad input. "<<endl; exit(1); return pstr; }*/ //定义和使用泛型函数 //通用的功能,找到的最大的数组中的元素 /*generic<typename T> where T:IComparable T MaxElement(array<T>^ x) { T max = x[0]; for(int i=0; i<x->Length; i++) { //这个函数什么意意,应该是个比较函数 //如果max小于x[i]返回的只-1 相等0 大于1 if(max->CompareTo(x[i]) < 0){ max = x[i]; } } return max; } //通用函数从数组中删除一个元素 generic<typename T> where T:IComparable array<T>^ RemoveElement(T element, array<T>^ data) { array<T>^ newData = gcnew array<T>(data->Length - 1); //定义新数组 int index = 0; bool found = false; for each(T item in data) { //如果还没有找到,并且当前值相等 if((!found) && item->CompareTo(element) == 0) { found = true; continue; }else{ //已经找到新数组的最后了 if(index == newData->Length){ Console::WriteLine(L"Element ot remove not found"); return data; } newData[index++] = item; //放入到新数组中去 } } return newData; } //显示数组所有内容 generic<typename T> where T:IComparable void ListElements(array<T>^ data) { for each(T time in data) { Console::WriteLine(L"{0,10}",time); } Console::WriteLine(); } //列出一个数组的通用功能 int main(array<System::String ^> ^args) { array<double>^ data = {1.5, 3.5, 6.7, 4.2, 2.1}; Console::WriteLine(L"Array contains:"); ListElements(data); Console::WriteLine(L"最大值为:{0}",MaxElement(data)); array<double>^ result = RemoveElement(MaxElement(data),data); Console::WriteLine(L"删除过后的字符串:"); ListElements(result); array<int>^ numbers = {3, 12, 7, 0, 10, 11}; Console::WriteLine("整型数组:"); ListElements(numbers); Console::WriteLine("最大值为:{0}",MaxElement(numbers)); Console::WriteLine("删除最大值以后的数组:"); ListElements(RemoveElement(MaxElement(numbers),numbers)); array<String^>^ strings = {L"Many", L"hands", L"make", L"light", L"work"}; Console::WriteLine("定义字符串数组:"); ListElements(strings); Console::WriteLine("字符串中最大值为:{0}", MaxElement(strings)); Console::WriteLine("删除最大值后:"); ListElements(RemoveElement(MaxElement(strings), strings)); system("pause"); return 0; }*/