首页 > 代码库 > 大话 函数指针 和 枚举这对鸳鸯
大话 函数指针 和 枚举这对鸳鸯
一:起因
(1)函数指针是指向函数的指针变量,即本质是一个指针变量,是一个指向函数(可能是代码区)的首地址的指针,正如我们都知道,数组名就是指向数组第一个元素的常量指针,对于一个函数而言,函数名也是指向函数第一条指令的常量指针。大话 回调函数 和 枚举
(2)而回调函数就是C语言里面对函数指针的高级应用,回调函数是一个通过函数指针调用的函数。如果你把函数指针(函数的入口地址)传递给另一个函数,当这个函数指针被用来调用它所指向的函数时,我们就说这个函数是回调函数。 大话 函数指针 和 指针函数
(2-2)为何要用枚举?一个星期只有七天,一年只有十二个月。如果把这些量说明为整型,字符型或其它类型显然是不妥当的。为此,程序设计语言提供了一种枚举类型(也称为枚举)。
(3) 枚举的声明,其形式为:(枚举名称相当于这个集合的名字,可有可无;类型定义以分号(;)结束),每一个成员的取值一定不要超过定义的范围。
访问修饰符 enum 枚举名:基础类型 { 枚举成员(标识符)}
(4)每个枚举成员均具有相关联的常数值,此值的类型就是枚举的基础类 型。枚举类型属于顺序类型,这样每一个枚举成员都代表一个值(int bool等),这样就可以用作函数数组的下标值。(枚举成员类型可以是除char 以外的任何整型)
二:详细解释
1) 枚举成员不能是数值常量、字符常量、字符串常量,使用时不能加单、双引号。例如,以下的定义是错误的:
enum Days { ‘Sun’, ‘Mon’, ‘Tues’, ‘Wed’, ‘Thu’, ‘Fri’,‘Sat’ }
enum Days { “Sun”, “Mon”, “Tues”, “Wed”, “Thu”, “Fri”,“Sat” }
2) 每个枚举成员均具有相关联的常数值。此值的类型就是枚举的基础类 型。枚举类型属于顺序类型。根据定义类型时各枚举成员的排列顺序确定它们的序列,如在默认基础类型即int的情况下序列号从0开始,后面每个枚举成员的值依次递增 1。当然可以显式赋值。例如:
enum Days { Sunday=2, Monday, Tuesday, Wednesday,Thursday, Friday, Saturday }
枚举成员是常量,不是变量。尽管是标识符也不能在程序中当做变量用赋值语句对它赋值。3) 枚举的声明,其形式为:(枚举名称相当于这个集合的名字,可有可无;类型定义以分号(;)结束),每一个成员的取值一定不要超过定义的范围。
访问修饰符 enum 枚举名:基础类型 { 枚举成员(标识符)}
说明:任意枚举类型都有基础类型,该基础类型可以是除char 以外的任何整型,如:byte、sbyte、short、ushort、int、uint、long 、 ulong。基础类型必须能够表示该枚举中定义的所有枚举成员。枚举声明时可以对基础类型进行显式地声明。而没有显式声明时基础类型默认是 int。基础类型指定为每个枚举数成员分配的内存大小。
4)设有变量a,b,c被说明为上述的Days,可采用下述任一种方式:相邻的每个枚举成员用逗号(,)隔开;最后一个没有逗号。 枚举类经常用在switch-case结构中,其常用的(Enum)方法主要有以下几个:
三:应用实例
(1)举个例子: 学生 类分大学生 高中 初中小学生 你就可以这么做
enum student{colleage,high,middle,junior}
//小明是个大学生
student xiaoming=colleage;
//判断小刚是不是高中生
if(xiaogang==high)
(2) 枚举元素本身由系统定义了一个表示序号的数值,(枚举元素是数值了)从0开始顺序定义为0,1,2…。如在weekday中,sun值为0,mon值为1,…,sat值为6。
int main()
{
enum weekday { sun,mon,tue,wed,thu,fri,sat } a,b,c;
a=sun; b=mon;
c=tue;
printf("%d,%d,%d",a,b,c);
}
说明:
只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。如:
a=sum; b=mon; 是正确的。
而: a=0; b=1; 是错误的。
如一定要把数值赋予枚举变量,则必须用强制类型转换。 如:
a=(enum weekday)2;
其意义是将顺序号为2的枚举元素赋予枚举变量a,相当于:
a=tue;
还应该说明的是枚举元素不是字符常量也不是字符串常量,使用时不要加单、双引号。枚举成员是常量,不是变量。尽管是标识符也不能在程序中当做变量用赋值语句对它赋值。
int main() { enum body { a,b,c,d } month[31],j; int i; j=a; for(i=1;i<=30;i++) { month[i]=j; j++; if (j>d) j=a; // 可以看出枚举元素相当于被定义为固定值的常量了 } for(i=1;i<=30;i++) { switch(month[i]) { case a:printf(" %2d %c\t",i,'a'); break; case b:printf(" %2d %c\t",i,'b'); break; case c:printf(" %2d %c\t",i,'c'); break; case d:printf(" %2d %c\t",i,'d'); break; default:break; } } printf("\n"); }
(3)完整的例子,可以和对比,发现下面的优点
#include <iostream> using namespace std; double add(double, double); double sub(double, double); double mul(double, double); double div(double, double); // 或者其它的指针 double (*oper_func[])(double, double)={ add,sub,mul,div }; double calculate(double, double, double (*func)(double,double)); enum operations{ add_ = 0, sub_ = 1, mul_ = 2, div_ = 3 }; int main(){ operations operation = sub_; cout << operation << endl; double op1,op2; cin >> op1 >> op2; int index = 0;// index 可以根据需要进行更改 //double result = oper_func[index](op1,op2);// double result = calculate(op1,op2,oper_func[sub_]);// 这样在真正的工程中,根据实际的字符串名称处理问题了, // 而且可以不用考虑字符串所对应的数值是否会越界等问题,因为枚举成员是固定在某一个取值范围内的。 cout << "result= " << result << endl; return (0); } double calculate(double op1, double op2, double (*func)(double,double)) { return func(op1,op2); } double add(double op1, double op2) { return op1 + op2; } double sub(double op1, double op2) { return op1 - op2; } double mul(double op1, double op2) { return op1 * op2; } double div(double op1, double op2) { if(op2 != 0) return op1 / op2; return -1;// 失败了 }解释:这样就可以通过枚举类型(enum operators)和函数指针数组( double (*oper_func[])(double, double) = { } ),以及回调函数( double calculate(double op1,double op2, double (*func)(double,double) ) ) 代替了复杂的swich-case句型
double calculate(double op1, double op2, double (*func)(double,double)) { return func(op1,op2); }当然,目前的代码仍然有需要改进的地方,例如:计算那一步,只能计算double类型的数据,所以需要优化来实现计算任何类型的数据。
(4)插入错误解释方法 undefined reference
最近在Linux下编程发现一个诡异的现象,就是在链接一个静态库的时候总是报错,类似下面这样的错误:
~~~~~~~ undefined reference to `func‘
这就是最典型的undefined reference错误,因为在链接时发现找不到某个函数的实现文件,(一句话就是缺少函数的实现部分,仅仅写出了声明部分是不行的)
大话 函数指针 和 枚举这对鸳鸯