C++ 小白 学习记录6

c++博大精深, 越看越觉得不会的太多. 回炉一下吧~ 大神们 请勿浪费时间~

第六章

.函数基础

形参和实参: 实参是形参的初始值.

如果没有形参, 也可以用void代替.如 void f(void){...}

函数返回类型:

函数的返回类型不能是数组类型或函数类型, 但可以是指向数组或函数的指针.

局部对象, 自动对象,局部静态对象: 在局部定义成static类型, 则调用以后其生命周期贯穿后续执行.

局部静态变量, 只初始化一次, 初始化后一直存在,直至整个程序终止.

函数声明: 函数只能定义一次, 但可以声明多次.

分离式编译

参数传递,  引用传递和值传递

指针形参, 引用形参, 利用引用形参返回函数多个结果.

const 形参和实参

void fcn(const int i)  和void fcn(int i)的定义相同.

指针或引用形参与const

尽量使用常量引用, 因为常量引用既可以起到保护作用, 又可以使用字面值常量,普通常量引用,也就是说适用范围更广.

数组形参

需要注意数组的两个特点: 不允许拷贝数组, 则不能使用值传递. 数组会被转换成指针.

void print(const int*); void print(const int[]); void print (const int[10]) 三个声明一样.

管理指针形参的三种常用技术:(因为传递的是数组指针, 则函数体内不知道数组长度)

  • 使用标记指定数组长度 如c风格中字符串的结束标志'\0'
  • 使用标准库规范:同时向函数传递数组的首尾指针.
  • 显示传递一个表示数组大小的形参: size_t size

数组形参和const

数组引用形参: void print(int (&arr)[10]); 此种方法会限制传递的参数的数组的元素个数.

传递多维数组: void print(int (*matrix)[10], int rowSize) == void print(int matrix[][10], int rowSize)

void swapPtr(int* &a, int* &b)  

int & *p; 是不正确的,*靠近p, 所以p是指针, 因为引用没有地址, 所以不能创建指向引用的指针。

int *  &p, 是正确的, &与p靠得最近,所以p是一个引用,这个引用的类型是int*,也就是一个指针变量的引用,但是必须初始化,否则也是错误的, 即 指针变量的别名.

main: 处理命令行选项

int main(int argc, char **argv) 参数内容存在于argv中 argv[0]为程序名或空字符串

含有可变形参的函数:

类型相同的可变数量实参: initializer_list 形参.

省略符实参 只有作用于c中的varargs时采用, 慎用.其只能出现在形参的最后一个位置. void foo(parm, ...); 或者 void foo(...);

initializer_list 和vector 很像, 却别是 initializer_list 中的元素都是const, 二vector中的元素可以修改.

以{}包含参数后 向其传值.

返回类型和return语句

无返回值函数 -- void 函数中.

在含有return语句的循环后面应该也有一条return语句.

不能返回内部对象的引用和指针, 因为函数运行结束后 资源被回收.

引用返回左值: 调用一个返回非常量引用的函数可以得到左值, 其他返回类型得到的是右值.

main的返回值: 在cstdlib中包含两个状态值: EXIT_SUCCESS; // EXIT_FAILURE; 也可以不返回 编译器自动帮助返回. main不能调用自身.

递归

返回数组指针

typedef int arrT[10] 或者useing arrT = int[10];

arrT* func(int i);

也可以:  type(*func(param_list))[dimension]  type 类型, () 内函数, []维度,如int (*func(int i))[10]; 跟 数组声明差不都.

尾置返回类型: auto func(int i) -> int (*)[10];

使用decltype: int a[]; decltype(a) * arrPtr(int i) {}

函数重载

main不能重载

重载只关注形参类型和数量, 能否重载也取决于形参.

顶层const不能区分形参.

const_cast 和重载

函数匹配 重载确定

重载与作用域, 跟变量一样.

特殊用途语言特性

默认实参: 定义函数时, 直接给出默认值. 需要注意的是一旦某个形参有了默认值, 则其后的所有形参都必须有默认值.   如果要修改某个默认实参, 则其前面的形参均需赋值. 

string screen(int ht=24, int wid=80, char b='');

screen(,,'?') 这种调用是错误的

二次声明时可以为没有默认值的参数添加默认值且将要添加默认值的参数右边必须都具有默认值, 但是已有的不能修改默认值.

默认实参初始值: 除了局部变量外, 只要表达式能转化成形参的类型,即可做为默认值. 默认初始值不会使用函数内部重定义的变量. 如

int wd = 80;
char def='*';
string screen(int sz = wd, char = def);

int main(int argc, char** argv) {
    def = 'a';  
	int wd = 20;
	screen(); // 此时 sz 仍然默认为80, 而非内部的20, 但是def变成了'a'

	return EXIT_SUCCESS; // EXIT_FAILURE;
}

内联函数(inline)和constexpr函数

内联函数可以避免函数调用的开销, 感觉 有点像在执行函数的地方 替换为函数的代码. 很多编译器不支持内联递归函数.

constexpr函数: 函数的返回类型及所有形参的类型都是字面值类型, 函数中有且只有一条语句.

constexpr 不一定返回常量表达式.

调试帮助  assert  NDEBUG

assert(expr) 如果expr ==0 false, 则输出信息并终止程序, 否则什么都不做

NDEBUG 在编译时使用的一个参数, /D NDEBUG (-D NDEBUG) 用于关闭所有assert, 或者再main文件开头 #define NDEBUG

类似assert的验证代码也可以写在 #ifdef NDEBUG 和 #endif 中

  • __func__ 为当前调试的函数的名字
  • __FILE__存放当前文件名的字符串字面值
  • __LINE__存放当前行号的整型字面值
  • __TIME__存放文件编译时间的字符串字面值
  • __DATE__存放文件编译日期的字符串字面值

函数匹配

第一步 找到对应的重载函数集(函数和调用的同名, 调用点可见)

第二步 找出可行函数(形参数量和实参相同, 实参类型与对应的形参类型相同或能转换)

第三步 寻找最佳匹配(实参类型与形参类型越接近越好), 如果一个形参能精确匹配a, 另一个形参能精确匹配b, 则该调用具有二义性, 报错

实参类型转换

1. 精确匹配:

  • 实参类型和形参类型相同
  • 实参从数组类型或者函数类型转换成对应的指针类型
  • 向实参添加顶层const或者从实参中删除顶层const

2. 通过const转换实现的匹配

3. 动过类型提升实现的匹配

4. 通过算术类型转换

5. 通过类类型转换实现的

函数指针

函数的类型由其返回类型和形参类型共同决定.

bool lengthCompare(const string &, const string &), 声明函数指针: bool (*pf)(const string &, const string&)

调用时无需解引用, 如 bool b1 = pf("hello", "world"); 也可以解引用 bool b2 = (*pf)("hello", "world");

typedef bool Func(const string&, const string&);   Func 是别名

typedef decltype(lengthComare) *FuncP2;   FuncP2 执行函数的指针.

返回函数的指针

可以使用别名: using  F=int(int *,int*);  using PF = int(*)(int *, int*); 使用时: PF f1(int); F *f1(int);

返回类型必须显示的指定为指针. 

函数指针 可以 批量调用  一批返回值类型相同, 形参相同的函数.

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mutiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b == 0 ? 0 : a / b; }

int main(int argc, char** argv) {

	typedef int (*Farithmetic)(int, int);
	vector<Farithmetic> sizeyunsuan = { &add, &sub,&mutiply,&divide };
	for (auto f : Farithmetic) {
		cout << "reulst:" << f(8, 2) << endl;
	}
	

	return EXIT_SUCCESS; // EXIT_FAILURE;
}

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yutao1131

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值