zoukankan      html  css  js  c++  java
  • C++对于C关于函数的扩展

    1 内联函数

    C++使用const常量来代替宏定义:如const int A = 3; === #define A 3

    那么C++是否有解决替代宏代码片段?

    C++中推荐使用内联函数替代宏代码片段

    内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。

    举个栗子

    //宏替换和函数调用区别:

    #include "iostream"
    using namespace std;
    #define MYFUNC(a, b) ((a) < (b) ? (a) : (b))  
    
    inline int myfunc(int a, int b) 
    {
    	return a < b ? a : b;
    }
    
    int main()
    {
    	int a = 1;
    	int b = 3;
    	//int c = myfunc(++a, b);  //头疼系统
    	int c = MYFUNC(++a, b);  
    
    	printf("a = %d
    ", a); 
    	printf("b = %d
    ", b);
    	printf("c = %d
    ", c);
    
    system("pause");
    	return 0;
    }
    
    
    • 必须inline int myfunc(int a, int b)和函数体的实现,写在一块

    • C++编译器可以将一个函数进行内联编译,被C++编译器内联编译的函数叫做内联函数

    • 内联函数在最终生成的代码中是没有定义的,C++编译器直接将函数体插入在函数调用的地方 ,内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)

    • C++编译器不一定准许函数的内联请求!

    • 现代C++编译器能够进行编译优化,因此一些函数即使没有inline声明,也可能被编译器内联编译一些现代C++编译器提供了扩展语法,能够对函数进行强制内联如:g++中的__attribute__((always_inline))属性

    • C++中内联编译的限制:

      • 不能存在任何形式的循环语句

      • 不能存在过多的条件判断语句

      • 函数体不能过于庞大

      • 不能对函数进行取址操作

      • 函数内联声明必须在调用语句之前

    • 编译器对于内联函数的限制并不是绝对的,内联函数相对于普通函数的优势只是省去了函数调用时压栈,跳转和返回的开销。

      因此,当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义

    结论

    1. 内联函数在编译时直接将函数体插入函数调用的地方
    2. inline只是一种请求,编译器不一定允许这种请求
    3. 内联函数省去了普通函数调用时压栈,跳转和返回的开销

    2 默认参数

    C++中可以在函数声明时为参数提供一个默认值, 当函数调用时没有指定这个参数的值,编译器会自动用默认值代替.

    void myPrint(int x = 3)
    {
    	printf("x:%d", x);
    }
    
    

    函数默认参数的规则, 只有参数列表后面部分的参数才可以提供默认参数值, 一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默认参数值

    //默认参数
    void printAB(int x = 3)
    {
    	printf("x:%d
    ", x);
    }
    
    //在默认参数规则 ,如果默认参数出现,那么右边的都必须有默认参数
    void printABC(int a, int b, int x = 3, int y=4, int z = 5)
    {
    	printf("x:%d
    ", x);
    }
    int main(int argc, char *argv[])
    {
    	printAB(2);
    	printAB();
    	system("pause");
    	return 0;
    }
    
    

    3 函数占位参数

    int func(int a, int b, int ) 
    {
    	return a + b;
    }
    
    int main()
    {
        //func(1, 2); //可以吗?
    	printf("func(1, 2, 3) = %d
    ", func(1, 2, 3));
    
    	getchar();	
    	return 0;
    }
    
    

    4 默认参数和占位参数

    可以将占位参数与默认参数结合起来使用,意义:为以后程序的扩展留下线索 , 兼容C语言程序中可能出现的不规范写法 C++可以声明占位符参数,占位符参数一般用于程序扩展和对C代码的兼容 。

    int func2(int a, int b, int = 0)
    {
    	return a + b;
    }
    void main()
    {
    	//如果默认参数和占位参数在一起,都能调用起来
    	func2(1, 2);
    	func2(1, 2, 3);
    	system("pause");
    }
    
    

    5 函数重载

    5.1 函数重载的概念

    函数重载(Function Overload),用同一个函数名定义不同的函数,当函数名和不同的参数搭配时函数的含义不同。

    5.2 函数重载判断标准

    函数重载必须满足以下的条件中的一个

    • 参数个数不同
    • 参数类型不同
    • 参数顺序不同

    5.3 函数重载调用准则

    1. 将所有同名函数作为候选者

    2. 尝试寻找可行的候选函数

    3. 精确匹配实参

    4. 通过默认参数能够匹配实参

    5. 通过默认类型转换匹配实参

    6. 匹配失败

    7. 最终寻找到的可行候选函数不唯一,则出现二义性,编译失败。

    8. 无法匹配所有候选者,函数未定义,编译失败。

    5.4 函数重载的注意事项

    • 重载函数在本质上式相互独立的不同函数(静态链编 )
    • 函数重载的函数类型是不同的
    • 函数的返回不能作为函数重载的依据
    • 函数重载是由函数名和参数列表决定的

    5.5函数重载遇上函数默认参数

    当函数默认参数遇上了函数重载会发生什么了

    int func(int a, int b, int c = 0)
    {
    	return a * b * c;
    }
    
    int func(int a, int b)
    {
    	return a + b;
    }
    
    //1个参数的允许吗
    int func(int a)
    {
    	return a + b;
    }
    
    int main()
    {
    	int c = 0;
    	c = func(1, 2); // 存在二义性,调用失败,编译不能通过 
    	
    	printf("c = %d
    ", c);
    	printf("Press enter to continue ...");
    	getchar();	
    	return 0;
    }
    
    

    5.6 函数重载和函数指针结合

    函数重载与函数指针

    ​ 当使用重载函数名对函数指针进行赋值时

    ​ 根据重载规则挑选与函数指针参数列表一致的候选者

    ​ 严格匹配候选者的函数类型与函数指针的函数类型

  • 相关阅读:
    使用字体图标完整步骤
    用position:absolute定位小窗口位于版面正中心
    MySql 技术内幕 (第7章 游标)
    MySql 技术内幕 (第5章 联接与集合操作)
    赋值语句作为判断的条件
    发布订阅模式和观察者模式
    关系代数
    数据库关系代数表达式学习
    软考通过分数
    哈希表——线性探测法、链地址法、查找成功、查找不成功的平均长度
  • 原文地址:https://www.cnblogs.com/Kroner/p/15456496.html
Copyright © 2011-2022 走看看