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 函数重载和函数指针结合

    函数重载与函数指针

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

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

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

  • 相关阅读:
    Pascal's Triangle II
    Pascal's Triangle
    Best Time to Buy and Sell Stock II
    Best Time to Buy and Sell Stock
    Populating Next Right Pointers in Each Node
    path sum II
    Path Sum
    [转载]小波时频图
    [转载]小波时频图
    [转载]Hilbert变换及谱分析
  • 原文地址:https://www.cnblogs.com/Kroner/p/15456496.html
Copyright © 2011-2022 走看看