《C++ primer》——第6章

《C++ primer》——第6章
6.1 函数基础

形参:就是定义or声明函数时需要的参数名。
例如:
声明函数void func(int a, int b){//}
在这里 a , b就是形参,只有名字和类型,没有其他具体的含义。

实参:调用函数时传递的变量参数
例如:
调用函数 func(2,3);
在这里2 , 3就有具体的含义。

形参:声明变量的作用,告诉其他人,调用我这个函数需要给我什么样的参数。
实参:赋值初始化的作用,调用函数时,把该值赋值给形参变量。

局部变量:形参和函数体内部定义的变量统称为局部变量(注意其作用域)

局部静态对象:知道程序的结束才被销毁的对象,不受块的约束

6.2 参数传递

主要分为两种:
1.引用传递
2.值传递

C++中什么是引用?
引用:就是相当于取别名,东西还是这么个东西,但是名字不一样了。我对这个名字进行对操作实质上是对同一个参数进行操作,是有影响的。

引用传递:在C++中 return只能返回一个参数,如果想要返回多个参数,就可以考虑使用引用传递的方式。

值传递:个人理解,赋值初始化的过程,就是将形参初始化为实参的值,注意这里是形成了两个对象,你在函数里对形参进行对操作,是无法影响实参的,因为这是两个不同的对象。虽然值一样,但是内存地址是不同的。

总结:在这里就可以得到在C++中参数传递的本质:赋值初始化(无论是引用传递还是值传递都可以这样理解。)

void func(int a, int b)
func(c, d);
a = c;
b = d;
a, b交换对c, d没有任何影响

void func(int &a, int &b)
func(c, d);
&a = c;
&b = d;
a, b交换影响c, d,cd也跟着交换

void func(int *a, int *b)
func(&c, &d);
*a = &c;
*b = &d;
a, b交换对c, d没有任何影响

void func(int * &a, int * &b)
int *c ,*d;
func(c, d);
&a = c;
&b = d;
a, b交换影响c, d,cd也跟着交换

数组形参:
数组的两个特殊点:
1、不允许拷贝数组,所以不可以使用传值的方式使用数组参数(传值即为拷贝)
2、通常数组的传递使用的是指针形式,传递的是指针的首地址。

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

上面三个函数是等价对,每个函数对唯一形参都是const int *类型。如果给函数传递数组,则实参自动地转换成指向数组首元素对指针,数组对大小对函数对调用没有影响。

1.当函数不需要对数组元素进行写操作时,使用const常量指针。

2.引用的数组和数组的引用是有区别的!数组的引用才可以作为函数的参数。

3.多维数组的传递,传递的同样是数组的首元素,不过多元数组的首元素本身就是数组

推荐使用标准库规范

void print(const int *beg ,const int *end){
	while(beg != end)
		cout << *beg++ <<endl;
}

int arr[2] = {1,2};
print(begin(arr) , end(arr);

main:处理命令行选项

使用argv中的实参时,一定要记得可选参数从argv[1]开始,argv[0]保存的是程序的名字。

为了使函数能够处理不同数量的实参
方法一:initializer_list标准库。
方法二:省略符形参(常用于C接口程序)——这个东西使用的情况不是很多

6.3返回类型和return语句
void func() //无返回值函数
int/char/bool func() //有返回值函数

函数名前面的类型名表示该函数返回的值类型:
int func(); //返回int
int &func(); //返回int引用
int *func(); //返回int指针

知识点1:返回的引用无效:局部临时变量或者局部对象的引用对于返回都是无效的,因为在函数终止之后,局部变量或者对象的引用不再指向有效的内存区域。若是常量在函数调用之前存在,引用即可用。

知识点2:可以对返回值是非常量引用的函数结果赋值。

引用返回左值

#include <iostream>
using namespace std;
char &get_val(string &str , string :: size_type ix){
    return str[ix];
}

int main(){
    string s("a value");
    cout << s <<endl;
    get_val(s,0) = 'A';
    cout << s <<endl;
    cout << get_val(s , 0) << endl;
    return 0;
}

main函数的返回值:
允许main函数没有return语句直接结束,但是编译器将隐式地插入一条返回0的return语句。

返回数组指针:

四种方式:

//第一种方式:类型别名的方式
typedef int arrT[10];
using arrT  = int[10];
arrT* func(int i);

//第二种方式:直接返回
int arr[10];	//普通数组
int *pl[10];	//指针数组
int (*p)[10];	//数组的指针

//第三种方式:尾置
auto func(int i) -> int (*)[10];

//第四种方式:decltype
decltype(odd) *arrPtr(int i){
	return (i % 2) ? &odd :& even;
}
int odd[] = {1,3,5,7,9};
int even[] = {2,4,6,8,10};

函数重载
如果同一个作用域内的几个函数名字相同但形参列表不同,我们称之为重载(overloaded)函数。

PS:main函数不能重载

对于重载函数,他们应该在形参数量或形参类型上有所不同。不允许两个函数除了返回类型外其他所有要素都相同。

如果我们在内层作用域中声明名字,它将隐藏外层作用域中声明但同名实体,在不同但作用域中无法重载函数名。

6.5 特殊用途语言特性

默认实参:

一旦函数的某个形参被赋予了默认值,他后面所有的参数都必须有默认值
(a) int ff(int a , int b = 0 , int c = 0); 对
(b) char *init(int ht = 24, int wd ); 错

知识点1:函数反复调用的过程中重复出现的形参,这样的值被称为默认实参。该参数在使用过程中可以被用户指定,也可以使用默认数值

知识点2:调用含有默认实参的函数时,可以包含该实参,也可以省略该实参。

知识点3:一旦某个形参被赋予了默认值,其后所有形参都必须有默认值。

知识点4:顺序很重要!在设计函数时,将默认值的形参放在后面。

知识点5:在给定的作用域中,一个形参只能被赋予一次默认实参,且局部变量不能作为默认实参。

内联函数和constexpr

知识点1:将函数指定为“内联函数(inline)”,将它在每个调用点上“内联的展开”,该说明只是向编译器发出一个请求,编译器可以选择忽略这个请求。内联的机制用于优化规模较小、流程直接、频繁调用的函数,建议不大于75行。

知识点2:constexpr函数是指能用于常量表达式的函数:函数的返回值类型和所有形参的类型必须是“字面值类型”:算术、引用、指针。并且函数体内有且只有一条return语句。

知识点3:将较小的操作如比较两个字符串的大小定义为函数,有很多的优点。

知识点4:inline函数和constexpr函数可以在函数中多次定义,但是通常将其定义在头文件中。

#include <iostream>
#include <string>
using namespace std;
constexpr int new_sz(){ return 42;}

int main(){

    constexpr int foo = new_sz();
    const int foo1 = new_sz();
    cout << foo << " " << foo1 <<endl;
    return 0;
}
#include <iostream>
#include <string>
constexpr int new_sz(){
    return 42;
}

constexpr int scale(int cnt){
    return new_sz()*cnt ;
}

int main(){
    
    int arr[new_sz()];
    int i = 2;
    int a[scale(i)];
    return 0;
}

上述arr数组和a数组都可以初始化成功,因为C++版本的问题已经解决了上述问题。

调试帮助:

程序的调试帮助:assert和NDEBUG

知识点1:预处理宏assert(expr):包含一个表达式,expr为真时,assert什么也不做,为假时输出信息并终止程序。包含在cassert头文件中。通常用于检查不能发生的条件

知识点2:assert依赖于一个NDEBUG的预处理变量的状态,如果定义了NDEBUG,assert什么也不做,默认状态下NDEBUG是未定义的。编译器也可以预先定义该变量。

知识点3:也可以使用NDEBUG编写自己的条件调试代码,如果NDEBUG未定义,将执行#ifndef到#endif之间的代码,如果定义了NDEBUG,这些代码将被忽略。

一些C++编译器定义的调试有用的名字:
_ func _ :一个静态数组,存放函数的名字

_ FILE _ :存放文件名的字符串字面值

_ LINE _ :存放当前行号的整形字面值

_ TIME _ :存放文件编译时间的字符串字面值

_ DATE _ :存放文件编译日期的字符串字面值

6.6函数匹配
知识点1:候选函数:函数匹配的第一步是选定本次调用的重载函数集,集合中的函数被称为候选函数

知识点2:根据实参情况,从候选函数中挑选出能被这实参调用的函数,此次选出的函数被称为可行函数。

函数匹配:重载函数调用时的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值