Visual C++ 2010 第6章 程序结构(2)

6.1 函数指针

6.1.1 声明函数指针

  • 声明函数指针的通用形式:
    *return_type (pointer_name) (list_of_parameter_types);
    函数指针声明由3部分组成:

    • 指向函数的返回类型
    • 指针名称(前面是指明其指针身份的型号)
    • 指向函数的形参类型
double (*pfun) (char* , int);
//声明1个指针pfun,指向接受2个类型为 char* 和 int 的实参,返回值类型为double的函数
  • 初始化函数指针:
//用函数名初始化函数指针
long sum (long num1,long num2);
long (*pfun) (long,long) = sum; //sum()函数的地址初始化pfun指针
//声明的指针pfun 指向任何接受2个long类型实参,返回值为long类型的函数。

long (*pfun) (long,long);
long product(long,long);
pfun = product ;
#include <iostream>
using std::cout;
using std::endl;

long sum (long a,long b);
long product(long a,long b);

int main()
{
	long (*pdo_it)(long,long);
	pdo_it = product;
	cout << endl
		 << "3*5 = "<< pdo_it(3,5);

	pdo_it = sum;
	cout << endl
		 << "3*(4+5)+6 = "
		 << pdo_it(product(3,pdo_it(4,5)),6);
	cout << endl;

	return 0;
}

long sum (long a,long b)
{
	return a + b;
}

long product(long a,long b)
{
	return a * b;
}

6.1.2 函数指针作为实参

  • 函数可以拥有类型为函数指针的形参,这样的函数可以调用实参指向的函数。
//处理数组的函数:某些情况下,该函数产生数组中所有数的平方和;
//其他情况下,计算所有数的立方和。

#include <iostream>
using std::cout;
using std::endl;

double squared(double);
double cubed(double);
double sumarray(double array[],int len,double(*pfun)(double));

int main(void)
{
	double array[] = {1.3,2.5,3.5,4.5,5.5,6.5,7.5};
	int len(sizeof array/sizeof array[0]);

	cout << endl << "Sum of squares = "<< sumarray(array,len,squared);
	cout << endl << "Sum of cubed = "<< sumarray(array,len,cubed);
	cout << endl;

	return 0;
}

double squared(double x)
{
	return x * x;
}
double cubed(double x)
{
	return x * x * x;
}
double sumarray(double array[],int len,double(*pfun)(double))
{
	double total(0.0);
	for(int i = 0;i < len;i++)
		total += pfun(array[i]);
	return total;
}

6.1.3 函数指针的数组

double sum(double,double);
double product(double,double);
double difference(double,double);

double (*pfun[3])(double,double) = {sum,product,difference};
// 各个数组元素分别初始化为大括号内初始化列表中对应的函数的地址。

//使用该指针数组的第2个元素调用product() 函数
pfun[1] (2.5,3.5);

6.2 初始化函数形参

//如果在调用函数时省略实参,则函数使用默认值执行;
//如果提供实参,则实参将代替默认值
#include <iostream>
using std::cout;
using std::endl;

void showit(const char message[] = "Something is wrong.");
int main()
{
	const char mymess[] = "The end of the world is nigh.";

	showit(); //显示默认值
	showit("Something is terribly wrong!");
	showit();
	showit(mymess);

	cout<<endl;
	return 0;
}
void showit(const char message[])
{
	cout<< endl
		<< message;
	return;
}

在这里插入图片描述

6.3 异常
异常真正适用于可能出现异常且接近致命状态的环境,而不是在正常事件序列中通常预料的将出现的环境。
异常机制使用了3个新的关键字:

  • try:标识可能出现异常的代码块
  • throw:使异常状态产生
  • catch:标识处理异常的代码块
/计算在某台机器上制造一个零件所需的时间(单位:分钟),每小时制造的
//零件数量已经被记录下来,但这台机器经常停机,停机期间不可能制造任
//何零件。
#include <iostream>
using std::cout;
using std::endl;

int main(void)
{
	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 << endl << "Hour" << i+1;
			if(0 == counts[i])
				throw "Zero count - calculation not possible."; 
				//执行throw语句时,控制权立即传递给catch代码块中的第一条语句
				//如果没有抛出异常,则不执行catch代码块
			cout << "minutes per item: "<< static_cast<double>(time)/counts[i];
		}
		catch(const char aMessage[]) 
		{
			cout<< endl << aMessage << endl;
		}

	return 0;
}

在这里插入图片描述

6.3.1 抛出异常

  • 在try代码块中的任何位置都可以抛出异常,throw语句的操作数决定着异常的类型。throw关键字后面的操作数可以是任何表达式,而表达式结果的类型决定着被抛出异常的类型。
  • 可以从try代码块调用的函数中抛出异常:
//上例中做如下修改:
void testThrow(void)
{
	throw "Zero count - calculation not possible."; 
}
// if 语句后调用函数
if(0== counts[i])
testThrow();

6.3.2 捕获异常

  • catch代码块将捕获的异常,取决于catch关键字后面的()中出现的形参说明。
  • 必须为try代码块提供至少一个catch代码块,且catch代码块必须紧跟try代码块。
  • catch代码块将捕获前面紧邻的try 代码块中出现的任何异常,包括从try 代码块内直接或间接调用的函数中抛出的异常。
  • 如果希望使某个catch代码块处理try代码块中抛出的任何异常,则必须将省略号(…)放入包围异常声明的圆括号内:
    catch (…)
    {
    //code to handle any excption
    }
  • 嵌套的try代码块
    可以在try代码块内嵌套try代码块,如果内部try代码块抛出异常,而该代码块后面又没有对应于被抛出的异常类型的catch代码块,则会搜索外部try 代码块的异常处理程序。
#include <iostream>
using std::cin;
using std::cout;
using std::endl;

int main(void)
{
  int height(0);
  const double inchesToMeters(0.0254);
  char ch('y');

  try                                            // Outer try block
  {
    while('y' == ch || 'Y' == ch)
    {
      cout << "Enter a height in inches: ";
      cin >> height;                             // Read the height to be converted

      try                                        // Defines try block in which
      {                                          // exceptions may be thrown
        if(height > 100)
           throw "Height exceeds maximum";       // Exception thrown
        if(height < 9)
           throw height;                         // Exception thrown

         cout << static_cast<double>(height)*inchesToMeters
              << " meters" << endl;
      }
      catch(const char aMessage[])               // start of catch block which
      {                                          // catches exceptions of type
        cout << aMessage << endl;                // const char[]
      }
      cout << "Do you want to continue(y or n)?";
      cin >> ch;
    }
  }
  catch(int badHeight)
  {
    cout << badHeight << " inches is below minimum" << endl;
  }
  return 0;
}

在这里插入图片描述
在这里插入图片描述

6.3.3 MFC中的异常处理

  • 抛出异常的MFC函数通常抛出 类 类型的异常,需要将异常当作指针,而非具体的异常类型进行捕获。如果抛出的异常是CDBException
    类型,则作为catch 代码块形参出现的类型应该是CDBException* 。

6.4 处理内存分配错误

  • 捕获new操作符抛出的异常
    当不能分配内存时,new操作符抛出的异常是bad_alloc类型。bad_alloc 是new标准头文件中定义的类 类型。
#include <new>
#include <iostream>
using std::bad_alloc;
using std::cout;
using std::endl;

int main()
{
	char* pdata(nullptr);
	size_t count(~static_cast<size_t>(0)/2); 
	// 0是int类型,static_cast<size_t>(0) 转换成size_t类型的0
	// ~ 操作符,对所有位取反,得到一个所有位都是1的 size_t值,对应于size_t可表示的最大值。
	// size_t是无符号类型,该值超出了new操作符一次可以分配的最大容量,除2 使其落入允许范围
	// 但此值仍较大,除非计算机有特别大的内存,否则分配请求必将失败
	try
	{
		pdata = new char[count];
		cout<< "Memory allocated."<<endl;
	}
	catch(bad_alloc &ex) // bad_alloc类型的引用 ex
	{
		cout<< "Memory allocation failed."<<endl
			<< "The information from the exception object is: "
			<< ex.what() << endl; 
		// ex调用what()函数,返回一个字符串来描述导致异常的问题
	}
	delete[] pdata;
	return 0;
}

在这里插入图片描述

6.5 函数重载

6.5.1 函数重载的概念

  • 函数重载:允许使用相同的函数名定义多个函数,条件时这些函数的形参列表各不相同。当调用函数时,编译器基于提供的实参列表选择正确的版本。
  • 一组重载函数中各个函数的形参列表必须是唯一的。
#include <iostream>
using std::cout;
using std::endl;

int max(int array[],int len);
long max(long array[],int len);
double max(double array[],int len);

int main(void)
{
	int small[]={1,24,34,22};
	long medium[]={23,245,123,1,234,2345};
	double large[]={23.0,1.4,2.456,345.5,12.0,21.0};

	int lensmall(sizeof small/sizeof small[0]);
	int lenmedium(sizeof medium/sizeof medium[0]);
	int lenlarge(sizeof large/sizeof large[0]);

	cout << endl << max(small,lensmall);
	cout << endl << max(medium,lenmedium);
	cout << endl << max(large,lenlarge);
	//编译器基于实参列表的类型,选择合适的max()函数版本

	cout << endl;
	return 0;
}

int max(int x[],int len)
{
	int maximum(x[0]);
	for(int i = 1;i < len;i++)
		if(maximum < x[i])
			maximum = x[i];
	return maximum;
}

long max(long x[],int len)
{
	long maximum(x[0]);
	for(int i = 1;i < len;i++)
		if(maximum < x[i])
			maximum = x[i];
	return maximum;
}

double max(double x[],int len)
{
	double maximum(x[0]);
	for(int i = 1;i < len;i++)
		if(maximum < x[i])
			maximum = x[i];
	return maximum;
}

在这里插入图片描述

6.5.2 引用类型和重载选择

void f(int& arg);
void f(int&& arg);
//当实参是lvalue时,编译器将始终选择 f(int& )函数;
//当实参是rvalue时,编译器将选择 f(int&& )版本;
int num(5);
f(num); 			// Calls f(int& )
f(2*num);			// Calls f(int&& )
f(25);				// Calls f(int&& )
f(num++);			// Calls f(int&& )
f(++num);			// Calls f(int& )

6.6 函数模板

  • 函数模板:定义用于生成一组函数的方法的代码。
  • 函数模板有一个或多个类型形参,通过为模板的每个形参提供具体的类型实参来生成具体的函数。

使用函数模板

//为max()函数定义一个模板
template<class T> T max(T x[],int len) 
{
	T maximum(x[0]);
	for(int i = 1;i < len; i++)
		if(maximum < x[i])
			maximum = x[i];
	return maximum ;
}
// template 关键字将代码标识为模板定义;
// template后的< > 包围着以 , 分开的、用来创建具体函数实例的类型形参
// T 前面的关键字class表明,T是该模板的类型形参。class是表示类型的通用术语。 可以使用typename 代替 class

#include <iostream>
using std::cout;
using std::endl;

template<typename T> T max(T x[],int len)
{
	T maximum(x[0]);
	for(int i = 1;i < len; i++)
		if(maximum < x[i])
			maximum = x[i];
	return maximum ;
}

int main(void)
{
	int small[]={1,24,34,22};
	long medium[]={23,245,123,1,234,2345};
	double large[]={23.0,1.4,2.456,345.5,12.0,21.0};

	int lensmall(sizeof small/sizeof small[0]);
	int lenmedium(sizeof medium/sizeof medium[0]);
	int lenlarge(sizeof large/sizeof large[0]);

	cout << endl << max(small,lensmall);
	cout << endl << max(medium,lenmedium);
	cout << endl << max(large,lenlarge);
	//编译器使用模板,为每条输出数组中最大值的语句实例化一个max()的新版本

	cout << endl;
	return 0;
}
// 输出与前面的例子相同

6.7 使用decltype 操作符

  • decltype操作符,可以得到一个表达式的类型
template<class T1,class T2>
auto f(T1 v1[ ], T2 v2[ ],size_t count) ->decltype(v1[0]*v2[0]) 
// ->decltype(v1[0]*v2[0]) 确定任何模板实例的返回类型
{
	decltype(v1[0]*v2[0] sum(0);
	for(size_t i = 0; i < count ; i++)
		sum += v1[i]*v2[i];
	return sum;
}
#include <iostream>
#include <typeinfo> //typeid 操作符在此头文件中
using std::cout;
using std::endl;

template<class T1,class T2>
auto product(T1 v1[],T2 v2[],size_t count) ->decltype(v1[0]*v2[0]) 
{
	decltype(v1[0]*v2[0]) sum(0);
	for(size_t i = 0; i < count ; i++)
		sum += v1[i]*v2[i];
	return sum;
}

int main()
{
	double x[] = {100.5,99.5,88.7,77.8};
	short y[] = {3,4,5,6};
	long z[] = {11L,12L,13L,14L};
	size_t n = 4;
	cout << "Result type is " << typeid(product(x,y,n)).name() << endl;
	cout << "Result is "<< product(x,y,n)<< endl;
	cout << "Result type is " << typeid(product(z,y,n)).name() << endl;
	cout << "Result is "<< product(z,y,n)<< endl;

	return 0;
}
// typeid(变量).name() ,获取变量类型名称

在这里插入图片描述

6.8 使用函数的示例

// 计算器程序
#include <iostream>
#include <cstdlib>  //包含exit()函数定义
#include <cctype>   // 包含isdigit()函数定义
using std::cout;
using std::cin;
using std::endl;

void eatspace(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
		 << "Welcome to your friendly calculator."
		 << endl
		 << "Enter an expression,or an empty line to quit."
		 << endl;

	for(;;)
	{
		cin.getline(buffer,sizeof buffer);
		eatspace(buffer);

		if(!buffer[0])
			return 0;
		cout << "\t= "<< expr(buffer)
			 << endl << endl;
	}

}
//从字符串中删除空格
void eatspace(char* str)
{
	int i(0);
	int j(0);

	while ((*(str+i) = *(str+j++))!= '\0')
		if(*(str+i)!= ' ')
			i++;
	return;
}
//计算表达式的值
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
			<< "Arrrgh!*#!! There's an error"
			<< endl;
		exit(1); //异常终止
		}	
	}
}
// 获取项值
// str:被分析的字符串;index:字符串中当前位置的索引
// 第2个参数指定为引用,因为希望该函数能够修改主调程序中index变量的值,
// 以使其指向输入字符串中被处理的这一项最后一个字符后面的字符
double term(char* str,int& index)
{
	double value(0.0);

	value = number(str,index);

	while(true)
	{
		if(*(str + index)== '*')
			value *= number(str,++index);
		else if(*(str + index)== '/')
			value /= number(str,++index);
		else
			break;
	}
	return value;
}
// 分析数
double number(char* str,int& index)
{
	double value(0.0);
	if(!isdigit(*(str+index)))
	{
		cout << endl
			<< "Arrrgh!*#!! There's an error"
			<< endl;
		exit(1);
	}
	while(isdigit(*(str + index)))
	{
		value = 10*value + (*(str + index++)-'0'); //数字字符的ASCII值在48~57之间(对应0~9)
													//某个数字的ASCII代码减去'0'的ASCII值,则该数字将被转换为等价的0~9的数字值
	}
	if(*(str + index)!= '.')
		return value;
	
	double factor(1.0);
	while(isdigit(*(str + (++index))))
	{
		factor *= 0.1;
		value = value + (*(str + index)-'0')*factor;
	}
	return value;
}

在这里插入图片描述

扩展:计算带()的表达式

#include <iostream>
#include <cstdlib>  // 包含exit()函数定义
#include <cctype>   // 包含isdigit()函数定义
#include <cstring>  // 包含strcpy_s()函数定义
using std::cout; 
using std::cin;
using std::endl;

void eatspace(char* str); //清空字符串中的空格
double expr(char* str); //计算表达式的值
double term(char* str,int& index);//获取项值
double number(char* str,int& index);//分析数
char* extract(char* str,int& index); // 获取括号内的子字符串

const int MAX(80);

int main()
{
	char buffer[MAX] = {0};

	cout << endl
		 << "Welcome to your friendly calculator."
		 << endl
		 << "Enter an expression,or an empty line to quit."
		 << endl;

	for(;;)
	{
		cin.getline(buffer,sizeof buffer);
		eatspace(buffer);

		if(!buffer[0])
			return 0;
		cout << "\t= "<< expr(buffer)
			 << endl << endl;
	}

}
//从字符串中删除空格
void eatspace(char* str)
{
	int i(0);
	int j(0);

	while ((*(str+i) = *(str+j++))!= '\0')
		if(*(str+i)!= ' ')
			i++;
	return;
}
//计算表达式的值
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
			<< "Arrrgh!*#!! There's an error"
			<< endl;
		exit(1); //异常终止
		}	
	}
}
// 获取项值
// str:被分析的字符串;index:字符串中当前位置的索引
// 第2个参数指定为引用,因为希望该函数能够修改主调程序中index变量的值,
// 以使其指向输入字符串中被处理的这一项最后一个字符后面的字符
double term(char* str,int& index)
{
	double value(0.0);

	value = number(str,index);

	while(true)
	{
		if(*(str + index)== '*')
			value *= number(str,++index);
		else if(*(str + index)== '/')
			value /= number(str,++index);
		else
			break;
	}
	return value;
}
// 分析数
double number(char* str,int& index)
{
	double value(0.0);
	if(*(str + index)== '(')
	{
		char* psubstr(nullptr);
		psubstr = extract(str,++index); 
		value = expr(psubstr); //递归调用
		delete[]psubstr;
		return value;
	}

	if(!isdigit(*(str+index)))
	{
		cout << endl
			<< "Arrrgh!*#!! There's an error"
			<< endl;
		exit(1);
	}
	while(isdigit(*(str + index)))
	{
		value = 10*value + (*(str + index++)-'0'); //数字字符的ASCII值在48~57之间(对应0~9)
													//某个数字的ASCII代码减去'0'的ASCII值,
													//则该数字将被转换为等价的0~9的数字值
	}
	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]; //声明数组临时容纳子字符串
	char* pstr(nullptr); 
	int numL(0); //记录字符串中左括号的数量
	int bufindex(index); //使用该变量和递增过的index值来索引数组buffer

	do
	{
		buffer[index - bufindex] = *(str + index);
		switch(buffer[index - bufindex])
		{
		case ')':
			if(0 == numL)
			{
				buffer[index - bufindex] = '\0';
				++index;
				pstr = new char[index - bufindex];
				if(!pstr)
				{
					cout << "Memory allocation failed,"
						 << " program terminated.";
					exit(1);
				}
				strcpy_s(pstr,index - bufindex,buffer); 
				//buffer指定的字符串复制到pstr指定的地址中,第2个参数是目标字符串的长度
				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);
}

在这里插入图片描述

6.9 C++/CLI 编程

  • CLR程序中,异常的throw 和 catch 机制:
    在C++/CLI 程序中,必须使用跟踪句柄来抛出异常。因此总是应该抛出异常对象,并尽可能避免抛出字面值,特别是字符串字面值。
try
{
	throw L"Catch me if you can."; //抛出的是 const wchar_t* 类型的异常
}
catch(String^ ex) // catch 代码块不能捕获这里抛出的对象
{
	Console::WriteLine(L"String^: {0}",ex);
}

//正确的代码1:
try
{
	throw L"Catch me if you can."; //抛出的是 const wchar_t* 类型的异常
}
catch(const wchar_t* ex)  //正确的类型
{
	String^ exc = gcnew String(ex);
	Console::WriteLine(L"wchar_t: {0}",exc);
}
//正确的代码2:
try
{
	throw gcnew String(L"Catch me if you can.");//抛出的是引用该字符串的句柄String^
}
catch(String^ ex) 
{
	Console::WriteLine(L"String^: {0}",ex);
}

6.9.1 理解泛型函数

  • 泛型函数,说明本身将被编译,当调用某个与泛型函数说明匹配的函数时,实际类型将在运行时代替类型形参。在编译时没有生成其他代码,也不会发生可能随函数模板出现的代码膨胀问题。
    1.定义泛型函数
//使用类型形参定义泛型函数,当调用函数时实际类型将代替这行形参。
generic<typename T> where T:IComparable
T MaxElement(array<T>^ x)
{
	T max(x[0]);
	for (int i = 1; i < x->Length; i++)
		if(max->CompareTo(x[i])<0)
			max = x[i];
	return max;
}
// 关键字generic将后面跟着的内容指定为泛型函数说明;
// 第一行将函数的类型形参定义成T;
// <>之间的typename 表明后面的T是这个泛型函数中类型形参的名称;
// 使用泛型函数时实际类型将代替这里的类型形参;
// 注意:对于多个类型形参的泛型函数,所有形参名称都要放在<>括号之间,每个名称前面都要有关键字typename,相互之间以逗号分开。
// where 关键字,引入对可能在使用泛型函数时代替T的实际类型的约束;
// 任何将在泛型函数中代替T的类型都必须实现IComparable接口,该约束意味着满足条件的实际类型必须实现CompareTo()函数,以允许该类型的2个队形进行比较;
// 有了这项约束,就可以使用CompareTo()函数来比较max 和某个数组元素。
// 当调用CompareTo函数的对象 (max)< 实参时,该函数返回一个 小于0的整数;
// 如果 max = 实参,则该函数返回0;
// 如果 max > 实参,则该函数返回大于0的整数。
// 第2行给出泛型函数的名称 MaxElement、返回类型T 和 形参列表。

2. 使用泛型函数
调用泛型函数:

  1. 像普通函数一样调用
array<double>^ data = {1.5,3.5,6.7,4.2,2.1};
double maxData = MaxElement(data);
//编译器能够推断出该泛型函数的类型实参时double,并相应的生成调用函数的代码
  1. 编译器无法根据对泛型函数的调用推断出类型实参时,调用时可以在函数名后面的<>内显式的指定类型实参。
double maxData = MaxElement<double> (data);
  • 可以作为类型实参提供给泛型函数的类型限制:
    类型实参不能是本地C++类 类型;
    不能是本地指针或引用;
    不能是值类类型的句柄;
    只能是 int 、double 这样的值类类型,像String^ 这样的跟踪句柄。
// 计算器程序.cpp: 主项目文件。

#include "stdafx.h"
#include <cstdlib> //包含exit()函数

using namespace System;
String^ eatspaces(String^str);
double expr(String^ str);
double term(String^ str,int^ index);
double number(String^ str,int^ index);
String^ extract(String^ str,int^ index);

int main(array<System::String ^> ^args)
{
	String^ buffer;
	Console::WriteLine(L"Welcome to your friendly calcaulator.");
	Console::WriteLine(L"Enter an expression,or an empty line to quit.");

	for(;;)
	{
		buffer = eatspaces(Console::ReadLine());
		if(String::IsNullOrEmpty(buffer)) //IsNullOrEmpty()函数,如果传递的实参字符串为空或长度为0,该函数返回true
		return 0;
		
		Console::WriteLine(L" = {0}\n\n",expr(buffer));
	}
    return 0;
}

// 删除输入字符串中的空格
// 使用System::String类定义的replace()函数将str中的空格全部替换为空字符串
// Replace()函数返回删除空格之后的新字符串
String^ eatspaces(String^str)
{
	return str->Replace(L" ",L"");
}

// 计算算术表达式的值

double expr(String^ str)
{
	//int^ index(0); //声明句柄 ,用*解除引用后可以进行算术运算
				   //这条语句依靠数值0的自动转换来产生该句柄引用的Int32数值类对象
				   // 消除警告 改写为:int^ index(gcnew int(0)); 显式的使用构造函数创建对象,并将其初始化为0
	int^ index(gcnew int(0));
	double value(term(str,index));

	while(*index < str->Length)
	{
		switch(str[*index])
		{
		case '+':
			++(*index);
			value += term(str,index);
			break;
		case '-':
			++(*index);
			value -= term(str,index);
			break;
		default:
			Console::WriteLine(L"Arrrgh!*#!! There's an error.\n");
			exit(1);
		}
	}
	return value;
}

// 获得项值
double term(String^ str,int^ index)
{
	double value(number(str,index));
	while(*index < str->Length)
	{
		if(L'*' == str[*index])
		{
			++(*index);
			value *= number(str,index);
		}
		else if(L'/' == str[*index])
		{
			++(*index);
			value /= number(str,index);
		}
		else 
			break;
	}
	return value;
}

//计算数的值
double number(String^ str,int^ index)
{
	double value(0.0);
	if(L'('== str[*index])
	{
		++(*index);
		String^ substr = extract(str,index);
		return expr(substr);
	}

	if(!Char::IsDigit(str,*index)) // Char类中的IsDigit函数当某个字符是数字时返回true,否则返回false
	{
		Console::WriteLine(L"Arrrgh!*#!! There's an error.\n");
		exit(1);
	}

	while((*index < str->Length)&& Char::IsDigit(str,*index))
	{
		value = 10.0*value + Char::GetNumericValue(str[(*index)]);
		// Char类中的 GetNumericValue()函数返回作为实参传递给它的Unicode数字字符的double值
		++(*index);
	}
	if((*index)== str->Length|| str[*index] != '.')
		return value;
	double factor(1.0);
	++(*index);

	while((*index < str->Length)&& Char::IsDigit(str,*index))
	{
		factor *= 0.1;
		value = value + Char::GetNumericValue(str[*index])*factor;
		++(*index);
	}
	return value;
}

//提取括号内的子字符串
String^ extract(String^ str,int^ index)
{
	int numL(0);
	int bufindex(*index);

	while(*index < str->Length)
	{
		switch(str[*index])
		{
		case ')':
			if (0 == numL)
				return str-> Substring(bufindex,(*index)++ - bufindex); 
				// Substring()提取括号中的子字符串,然后返回此子字符串
			else 
				numL--;
			break;

		case '(':
			numL++;
			break;
		}
		++(*index);
	}
	Console::WriteLine(L"Ran off the end of the expression,must be bad input");
	exit(1);
}

6.12 本章主要内容
在这里插入图片描述

To be continue…

猜你喜欢

转载自blog.csdn.net/madao1234/article/details/85156239