C++函数学习笔记

1 篇文章 0 订阅

函数声明

如果一个函数永远不会被我们用到,那么他可以只有声明没有定义.

在头文件中进行函数声明

1.函数应该在头文件中声明而在源文件中定义.

2.如果吧函数声明放在头文件中,就能确保同一函数的所有声明保持一致,而且一旦我们想
改变函数的接口,之需要改变一条声明即可.

3.定义函数的源文件应该把函数声明的头文件包含进来,编译器负责检验函数的定义和声明是否匹配.

引用传递和值传递

引用传递

当形参是引用类型的时候,我们就说他对应的实参是引用传递或者函数被引用调用.

值传递

当实参的值被拷贝给形参时,我们就说实参被值传递

使用引用避免拷贝

使用大的类类型或者容器对象比较低效,有的类类型根本不支持拷贝,当某种类型不支持拷贝操作的时候,函数只能通过引用形参访问该
类型的对象.当函数无需修改引用形参的值时,最好将其声明为引用常量

const 形参和实参

和其他初始化过程一样,当用实参初始化形参时会忽略掉顶层const,换句话说,形参的顶层const被忽略掉了,当形参有顶层const,传给他常量对象或者非常量
对象都是可以的.
其实也就是跟初始化一个变量和指针差不多
例子

void fcn(const int i){};
void fcn(int i){};   //这里直接报错重复定义

允许我们定义若干具有相同名字的函数,不过前提是不同函数的新参列表应该有明显的区别

初始化和对常量引用

一般的引用

引用的类型必须要与其引用的对象的类型一致

常量引用

1.在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可
2.允许为一个常量引用绑定非常量的对象,字面值,甚至是一个表达式.

const int &i = 520;   //这个是ok的

标题##数组形参

void print(const int*);
void print(const int[]);
void print(const int[10]);

实际上上面的三个函数声明是等价的,每个函数的唯一参数都是const int*类型的.

数组引用实参数

void print(int (&arr)[10])
{
    for(auto elem : arr)
        cout<< elem << endl;

}

int k[10] = {1,2,3,4,5,6,7,8,9,10};
print(k);

返回类类型的函数和调用运算符

调用运算符的优先级与点运算符和箭头运算符相同,并且也符合左结合律.

列表初始化返回值

c++11新标准,函数可以返回花括号包围的值的列表.

cstdlib中两个预处理变量

int main()
{
    if(some_failure)
    return EXIT_FAILURE;
    else
    return EXIT_SUCCESS;
}

因为他们是预处理变量,所以既不能在前面加上std::,也不能在using声明中出现.

返回数组指针

函数可以返回数组的指针或引用
使用类型别名简化处理

typedef int arrT[10];   // arrT是一个类型别名,他表示的类型是含有10个整数的数组
using arrT = int[10];      //  arrT的等价声明
arrT* func(int i);    // func返回一个指向含有10个整数的数组的指针

声明一个返回数组指针的函数

方法1

返回数组指针的函数形式如下

Type (*function (parameter_list)) [dimension];

int (*func(int i)) [10];

方法2

使用尾置返回类型
任何函数的定义都可以使用尾置返回,这种形式对于返回类型比较伏在的函数最有效.尾置返回类型跟在形参列表后面并以一个->符号
开头,我们在本应该出现返回类型的地方防止一个auto.

auto func(int i) -> int(*)[10];

方法3

使用decltype

int odd[] = {1,3,5,7,9};
int even[] =  {0,2,,4,6,8};
decltype(odd) *arrPtr(int i)
{
    return (i%2) ? &odd : &even;
}

decltype 并不负责吧数组类型转换成指针,所以decltype的结果是个数组.

函数重载

编译器根据传递的实参类型推断想要的是哪个函数,对于重载函数来说,他们应该在形参数量和形参类型上有所不同.
不允许两个函数除了返回类型外其他的所有的要素都相同

Record lookup(const Account &);
bool lookup(const Account &);     //错误的

重载与作用域

string read();
void print(const string &);
void print(double );
void  foobar(int ival);
{
    bool read = false;
    string s = read();   //错误,read是一个布尔值
    void print(int);  //新的作用域,隐藏掉之前的print函数
    print("Value: ");    //void print(const string &) 被隐藏起来,错误
    print(ival);      //调用的是void print(int);
    print(3.14);       //  调用的是void print(int);
}

在外层作用域中的print(const string &) 函数虽然于本次调用匹配,但是他已经被隐藏掉了,
根本不用考虑.

默认实参

调用含有默认实参的函数的时候,可以包含该实参,也可以省略该实参

注意
1:一旦某个形参被赋予了默认值,他后面的所有的形参都必须有默认值.
2.函数调用时实参按其位置解析,默认实参负责填补函数调用缺少的尾部实参.也就是说函数调用不能
填前面我们没有写的参数.
3.尽量让不怎么使用默认值的形参出现在前面,让经常使用的默认实参出现在后面

默认实参声明

string screen(sz,sz,char = ' ');
string screen(sz,sz,char = '*');   //这个是错误的
string screen(sz = 24,sz = 80,char );    //这个是正确的

对于函数的声明来说,多次声明同一个函数是合法的,但是在给定的作用域中一个形参
只能被赋予一次默认实参,后续声明只能为之前的没有默认值的形参添加默认
实参.而且右侧所有的形参都必须有默认值

内敛函数

内敛函数可以避免函数调用的开销,通常就是将他在调用点上"内敛的"展开.

cout << shorterstring(s1, s2) << endl;
coun << (s1.size() < s2.size() ? s1 : s2) << endl;

在函数的开头加上inline就变成了内敛函数

下面是书写的格式

inline const string  &
shorterstring(const string &s1, const string &s2)
{
    return s1.size() <= s2.size() ? s1 : s2;
}

实参类型匹配

需要类型提升和 算数类型转换的匹配

void ff(int);
void ff(short);
ff('a');     // char 提升成int,调用f(int);

假设有两个函数,一个接受int,另外一个接受short,当只有调用提供的是short类型的
值的时候才会选择short版本的函数
即使实参是一个很小的整数值,也会直接提升为int
类型.所有算数类型的转换的级别都是一样的

函数匹配和const实参

Record lookup(Account&); 
Record lookup(const Account&);

const Account a;
Account b;
lookup(a);       //调用const版本
lookup(b);      //非const,因为如果调用const版本需要类型转换

对于指针也是一样的.

函数指针

要想声明一个函数指针,只需要用指针替换函数名即可

重载函数的的指针

void ff(int *);
void ff(unsigned int);
void (*pf1)(unsigned int) = ff;
void (*pf2)(int) = ff; // 错误,没有任何一个ff与该形参列表匹配
double (*p3)(int*) = ff;   //错误

指针类型必须与重载函数中的某一个精确匹配

函数指针形参

void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));

void useBigger(const string &s1, const string &s2, bool (*pf(const string &, const tring &)));
//上面两个声明是等价的

返回指向函数的指针

方法1

using F = int (int*, int);   //F是类型
using PF = int(*) (int*, int);   //PF是函数指针 

PF f1(int);
F *f1(int);

方法2

int (*f1(int))(int*, int);
auto f1(int) ->int (*)(int*, int);

方法3:将auto 和 decltype 用于函数指针类型

string::size_type sumLgength(const string&, const string&);
string::size_type largerLength(const string&, const string&);

decltype(sumLength) *getFch(const string&);

注意:当我们将decltype作用与函数的时候,他返回函数的类型而非指针类型,因此我们要加上*.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值