异常处理
需要人为throw才能catch,与Java的机制有所区别
throw抛出的异常可以是任意类型
#include <stdexcept>
/*
* ……
*/
int num[10] = {0};
try
{
num[0] = num [1];
throw num[0];
}
catch(int err)
{
cout << "error happend" << endl;
}
try
{
throw runtime_error("this is a run time error");
}
catch(runtime_error err)
{
cout << err.what() << endl;
}
函数基础
局部静态变量
在程序的执行路径第一次经过对象定义语句时初始化,直到程序终止时才销毁。
int call_count()
{
static int count = 0;
return ++count;
}
int main()
{
for(int i = 0; i < 5; i++)
{
call_count();
}
cout << call_count() << endl; //the output is 6
}
使用引用参数传递省去拷贝
const参数
void fun(const int num); //num只能读不能写
可变形参的函数
类型相同,数量不同
void init_list_test(initializer_list<string> str)
{
for(auto it = str.begin(); it != str.end; it++)
cout << *it << " ";
cout << endl;
}
init_list_test({"this", "is", "a", "test"});
省略符形参
#include <stdarg.h>
using namespace std;
void argFun(int parNum, ...)
{
va_list ap;
char* s;
va_start(ap, parNum);
for(int i = 0; i < parNum; i++)
{
s = va_arg(ap, char*);
cout << s << endl;
}
}
int main()
{
argFun(3, "hello", "world", "!");
}
也可以只有省略号,完全忽略形参
尾置返回类型
用于返回类型比较复杂的情况,特别是没有左值的类型
auto fun(int i) -> int (*)[10] //等价于int (*fun(int i))[10]
{
static int num[10];
for(int j = 0; j < 10; j++)
{
num[j] = i + j;
}
return #
}
int main()
{
void *result;
result = fun(-5);
int *temp;
for(int i = 0; i < 10; i++)
cout << *(temp = (((int*) result) + i)) << endl;
使用decltype,如下函数定义与上述方法等价
int type[10] = {0};
decltype(type) *fun(int i)
函数重载
同一作用域内的几个函数名字相同但形参列表不同,返回值也可以不同
int func(int *ptr);
int func(int* const prt); //重复声明了前者
int func(const int *prt); //新函数,作用域指向常量的指针
int func_new(int &num);
int func_new(const int &num); //新函数,作用域常量引用
有无顶层const无法被区分,有无底层const可以被区
非常量可以转化为常量,所以比如当仅有3时,传递一个非常量的prt没有错误,但若同时存在1,3,则编译器会优先选择1
const_cast强制转换与重载
如下函数,即省去了函数返回值拷贝的过程,又解决了实参不是const类型时的麻烦
const int &func(const int &i, const int &j);
int &func(int &i, int &j);
int main()
{
int m = 1, n = 3;
int &result = m;
result = func(m ,n);
cout << result << endl;
}
const int &func(const int &i, const int &j)
{
return (i > j) ? i : j;
}
int &func(int &i, int &j)
{
const int &temp = func(const_cast<const int&>(i), const_cast<const int&>(j));
return const_cast<int&>(temp);
}
const_cast还可用于多线程下volatile关键字
避免二义性调用
当有多个函数可以匹配时
默认实参
int caculateSquare(int width = 10, int length = 10);
调用时只能省去尾部的实参
内联函数
直接替换,省去开销,一般较小,不支持递归
inline int getMax(int i, int j);
内联函数必须是和函数体申明在一起,才有效。
内联函数和宏很类似,而区别在于,宏是由预处理器对宏进行替代,不检查函数参数,返回值,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。
constexpr
用于常量表达式的函数
返回值及所有形参类型比学位字面值类型,函数体中必须只有一条return语句
可以返回非常量,编译器检查上下文
通常放在头文件中
调试帮助:assert与NDEBUG
assert是一种预处理宏,包含在头文件assert.h中
assert(expr); expr为假时,打印错误,退出;expr为真时,doing nothing
assert的缺点是极大影响程序的性能,产生额外开销
调试结束后可以在#include<assert.h>前加入#define NDEBUG来使所有assert失效
可以利用NDEBUG编写自己的调试代码
#ifndef NDEBUG
cerr << "error:NDEBUG test success" ;
#endif
预处理器还提供了几个对于调试很有用的局部静态变量
__func__ 当前调试的函数名
__FILE__ 存放当前文件名
__LINE__ 当前行号
__TIME__ 文件编译时间
__DATE__ 文件编译日期
函数指针
声明一个函数指针
bool (*prtf)(double x, int n); //未初始化
可以直接给prtf赋值
int sum(int x, int y)
{
return x + y;
}
prtf1 = sum;
prtf2 = ∑//等价
prtf1(1,2);
(*prtf)(1,2); //等价
重载函数也可以有函数指针
函数指针可以作为形参传入
int prtfPara(int x, int y, int (*prtf) (int m, int n))
{
return prtf(x, y) + x;
}
cout << prtfPara(1, 2, sum) <<endl;
可以用typedef和decltype定义函数的类型,避免冗长和繁琐
typedef int functype1(int x, int y);
typedef decltype(sum) *functype2;
int prtfPara(int x, int y, functype2 prtf)
返回函数指针的函数
typedef int(*PF)(int x, int y) ;
PF pf1(int x)
{
return sum;
}
functype1 *func1 = pf1(1);
cout << func1(4, 5) << endl;
也可这样声明func1
int (*func2(int m))(int x, int y);
注意:当decltype作用于某个函数时,它返回函数类型而不是指针类型,需要显式的加上*表明是指针类型,例如functype2
最近开的书比较多,上周末又病了一场,节奏有点不太对,有待调整!
转载于:https://blog.51cto.com/jarvis365/1329326