c++回炉-函数

函数

void func(){return;}  //return后面不能接内容,或者没有return.  在void函数中,return用于提前结束函数,否则在右大括号处结束
type func(){return value;}  //value到type有一步强制类型转换; 返回值不可以数组,可以是指针,基本类型,类对象。
string func(){return "nihao!"} //返回常量
int func(int arr[], int n);       int myarray[10];    func(myarray, 10);  int arr[]和int *只有在函数头里面才等价。
int func(const int arr[], int n);    //保证数组中的数据不能通过指针变量arr被改变
int func(int* start, int* end);  //数组可以通过起始地址加元素个数或者区间来传递

int n=5;  int* p=&n;  int** q=&p;   //q就是一个二级指针
const char* arrmonth[]={'Jan', 'Feb'};
const char** p = arrmonth; 
cout<<*(p+1)<<endl;    //输出Feb

const int** pp2;	int* p1;   const int n=123;  
pp2 = &p1; //pp2->p1->data   =>   **pp2->data  ,  这句就是pp2指向的data跟p1指向的是同一个
*pp2 =&n;   //*pp2变成一级指针,指针指向n, 所以p1也指向了n
*p1=10;  //通过p1解引用改变了n的值,但是n是const, 所以普通指针可以复制给const指针这个命题不适合多级指针

void fun(int (*ar)[4], int row);  //二维数组做函数参数,4在函数体内是有效的
void fun(int ar[][4], int row);   //第二个参数为二维数组的行数, 4在函数中可以使用
void fun(int arr[3][4]);   //只能接受3行4列的二维数组作为形参
void fun(int **arr, int row, int column);  //指出行列
int array[100][5];		fun(array, 50);   //对前50行进行处理, 调用都是只传数组名

void alloc_mem(int**& arr, int row, int column){   //arr是二维指针的引用,相当于三维指针
	arr = (int**)malloc(row*sizeof(int*));   //二维数组是二维指针,第一维里面存的是指针
	a[0] = (int*)malloc(row*column*sizeof(int));    //一次分配完整,内存连续
	for(int i=1; i<row; i++){  //处理各行指针的指向
		a[i] = a[i-1] + column;
	}
}
int** alloc_mem(int row, int column){
	
	return 
}

const double* (*pf)(const double*, int) = f1;   //声明函数指针的同时进行初始化
const double* (*pf[3])(const double*, int) = {f1, f2, f3};  //包含三个函数指针的数组pf
typedef const double* (*pf)(const double*, int);    pf  obj1;  //pf是一种类型

//实参与引用形参不匹配时候的临时变量
double fun(const double& ra){}
fun(arr[2]);   //double arr[10];   ra就是arr[2]				正常引用绑定
fun(rd);  //double& rd = side;  ra就是side				正常引用绑定
fun(*pd);   // double* pd = &side;  ra就是side			正常引用绑定
fun(edge);   //long edge = 5L;    ra指向的是一个匿名临时变量,临时变量只在函数调用期间存在。
fun(7.0);     //    ra指向的是一个匿名临时变量,临时变量只在函数调用期间存在。

//右值引用, 相比于右值引用,以前的就叫左值引用
double&&  re = std::sqrt(36.0);	cout<<re;   //得到6.0
double&& rf = 2.5;	std::cout<<rf;  //得到2.5

fre&  accumulate(fre& target, const fre& source){
	return target;    //因为函数原型是fre&,所以这里返回的是target的引用
}
void display(const fre& t);     display(accumulate(tem, tom));    //相当于display(tem), tem-target-t   都是引用传递。
accumulate(tup, temo) = tom;   //返回引用加不加const的区别
fre temp = accumulate(tup, temo);    //前一种,因为是引用,指向可修改的内存块,所以可以作为左值,后面加了const,只能作为右值了。

//函数重载
float fun(int a);		double fun(int a);    //不算是重载,因为cout<<fun(5);  编译器不知道调用哪一个
float fun(int a);     float fun(int& a);   //不是重载,同理,fun(5)无法确定调用哪一个
float fun(int& a);   float fun(int&& a);    //是重载,一个是左值引用,一个是右值引用

//函数模板重载
template <typename T>
void fun(T& a, T& b);
template<typename T>
void fun(T* a, T* b, int n);  	//是一个新的模板

//模板的具体化
template<typename T>
void fun(T& a, T& b);			//函数模板,调用时候两个参数必须类型一致,否则编译不过##1##
template<>
void fun<job>(job& a, job& b);   //特例化成T--job , 又叫具体化
template<>
void fun(job& a, job& b);   //第二种形式, 调用时候,优先匹配特例化的形式

template	void fun<int>(int& a, int& b);   //实例化的提前声明
cout<<fun<double>(a, b);   //显示实例化

//##1##直接调用函数属于隐式实例化, 显示实例化
fun<int>(a, b);   int a=4, float b=4.5;   //错的还是不行????

//decltype用法:   decltype(expression)  var;
template<typename T1, typename T2>
void add(T1 x, T2 y) {   ?  xy = x + y; }    //因为x,y是两种类型,所以xy不知道该用什么类型
void add(T1 x, T2 y) { decltype(x+y) xy = x+y; }   //用decltype来推测出x+y的类型。
//expression可以分为:带括号的左值,不带括号的左值,函数,
decltype(len(3))   w;   //不回去执行len(3), 而是查看函数原型的返回值。
decltype(x) v;   // double &  x=y;    v就表示double &
decltype((p)) v;  //int p =4;    v就表示 int&  ,  decltype(p)  v;   v表示int

//如果不能推断x+y的类型怎么办?
template<typename T1, typename T2>
?  add(T1 x, T2 y) {return x+y; }    ###1
template<typename T1, typename T2>         //
auto add(T1 x, T2 y)-> decltype(x+y) {return x+y; }    ###2
//###1中不能用decltype(x+y)替换?, 原因是:x, y是函数参数,返回值不可见,脱离了函数作用域
//###2中,用auto作为了占位符,把decltype(x+y)用->移到参数列表后面,这样函数内部可见, 编译器就可以把auto推测成decltype(x+y)

//例子
Time sum(Time& t1, Time& t2){
  Time sum;		sum.m=t1.m+t2.m   sum.h=t1.h+t2.h+sum.m/60;   sum.m %=60;   return sum;
} //没有运算符重载,导致效率上很多浪费
Time Time::operator+(const Time& t) const{   //const函数的原因是修改的是局部Time的data
  Time sum;		sum.m=t1.m+t2.m   sum.h=t1.h+t2.h+sum.m/60;   sum.m %=60;   return sum;
}   //不能级联  比如t4=t1+t2+t3,    t4=t1.operator+(t2.operator+(t3));    返回引用的话就可以级联。

void display(const Stone& st, int n){		//Stone::Stone(double);  单个参数的构造函数 
  for(int i=0; i<n; i++) cout<<st.show();
}
display(575,2);  //编译器先找Stone(int)构造函数,没找到,找int可以隐式转换的类型的构造函数Stone(double), int-->double然后转化成Stone对象

using属于编译指令。
函数原型是函数与编译器的接口,原型告诉编译器函数的返回值,参数类型,数量。
函数返回值类型的作用,告诉调用函数到制定位置读取多少字节的数据,这个数据就是被调用函数的返回值。
函数在接受不同类型实参的时候会有一步强制类型转换。比如double形参接受了一个int实参。
函数形参接受实参值得过程是值传递。c++函数参数都是按值传递进行的,除了引用形参。
对数组名使用sizeof得到整个数组的大小;对数组名使用&得到的是整个数组的内存块的起始地址;数组名表示数组第一个元素的地址;
函数参数传递指针时候,值传递的是指针的值,引用传递的是指针的值所指向的数据。
stl中“超尾”的概念:标识数组结尾的参数指向数组最后一个元素后面的指针
二级指针:指向指针的指针。
void func(const double ar[], int n); 一个实参double* arr[]={…}; 形参对应位置不能加const. 为什么呢?因为二级指针下命题不成立。编译invalid conversion from ‘int**’ to ‘const int**’
虚拟地址指的是程序员看到的地址,实际物理地址是指硬盘上的地址空间。
二维数组在栈上分配时候,内存是连续的。在堆上分配注意连续性。
函数名就是函数的地址,函数指针知名返回类型和形参列表。函数地址传递给函数指针时候,必须返回类型和参数列表都要匹配上了才可以。
带参数的宏也是将代码替换,类似于inline,但是参数传递时候,宏不是按值传递的,inline是按值传递传参。
引用变量主要用于函数形参,声明的引用变量和原变量具有相同的值和内存地址。
引用是先有原始变量,在把引用添上去,也就是声明引用时候必须同时赋值。指针可以先有,然后再确定指向哪一个变量,可以先声明后赋值。引用类似于打了死结的绳子,只能绑一个东西;而指针是打了活结的绳子,可以解开绑另一个东西。
函数参数传递: 值传递:跟实参完全无关
指针:解引用后就是实参
引用:本身就是实参
实参与const引用参数不匹配时候,c++将生成临时变量:(只有const引用可以这么搞)
1:实参类型正确,但不是左值
2:实参类型不正确,但可以转换成正确的类型
为什么规定const引用才能这么玩,如果非const,则可以通过引用修改实参,但是实参不匹配,这时就会创建个临时变量,则引用实际改变的是临时变量的值,并没有改变实参。所以通过const禁止这种可能性,也就是实参跟引用变量不匹配时候只能访问而不能改写。
函数返回引用的原因:如果不是引用,函数会先把结果复制到一个临时变量,然后在调用的时候,把临时变量的值再复制给左值。如果是返回引用,则少了两次拷贝。
函数返回引用:不能返回函数调用结束后不存在的内存单元(临时变量)。避免的两种方法:
1:返回引用参数
2:返回函数中新new的内存
函数参数的形式怎么选择:
内置类型,值传递
数组,只能使用指针
结构体,const 引用或者const 指针
类对象,const引用
函数带不带默认参数只体现在函数原型上,函数定义都是相同的。
函数重载的基础是特征标:
参数个数
是否为const
类型
保证编译器在函数调用时候可以匹配到原型。
编译器内部怎么识别重载函数呢?会根据形参类型和个数进行名称修饰,通过特殊的规则添加冗余信息,使其内部唯一。
函数模板:
模板并不创建任何函数,只是告诉编译器如何定义函数。
将模板放到头文件中,并在需要使用模板的文件中包含头文件。
函数模板也可以重载。
函数模板为什么有特例化,主要是模板中的表达式用到的运算符在模板实例化时候的对象不支持那个运算符,比如T a+b, 有的对象不支持+。
如何匹配最佳函数?(重载,模板)
1.创建候选函数列表,以此创建可行函数列表,然后在列表中查找最佳的
decltype获取不确定类型参数的类型,专用于模板函数。
针对decltype(expression) var; expression的情况分为:
1.expression是没有括号的标识符,则var和标识符类型相同
2.expression是函数调用,则var和函数返回值类型相同
3.expression是左值且带有括号,则var是该类型的引用
4.除了上面,var的类型和expression类型相同
编译命令:
g++ -std=c++11 -g syntex.cpp -o syntex
cc1plus: error: unrecognized command line option “-std=c++11”
g++ -std=c++0x -g syntex.cpp -o syntex
g++ --version 4.4.7 只能用-std=c++0x

函数返回const引用时候只能作为右值, 而返回引用时候可以作为左值
cout打印字符数组的地址
print, cout如果发现一个数组是字符数组,则会全部输出,如果要输出收地址,char buff[10]; cout<<(void*)buff<<endl;

数组作为函数参数:
void fun(uint32_t num, capInfo workList[]) const;
void fun(uint32_t num, capInfo(&workList)[work_list_size]) cosnt; //推荐方式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值