c++-函数
- 函数
- 默认参数
- 函数重载
- 传递方式
- 值传递
- 指针(地址)传递
- 引用传递
- 引用传递与const
- 指针引用
- 引用与函数返回值
- 引用与指针
- 引用与临时数据 - 还要看
- 引用与const 其他注意事项- 还没看
- const 与函数
- const与形参
- const修饰函数(返回值)
- const 成员函数
- 内联函数 -- 还没看
函数
可以为函数多次声明,但是尽量不要这么做(后续的声明只能为之前哪些没有默认参数的值添加默认值)
默认参数
int b=2;
void func(int a=1,int c=b+2)
{}
注意:C++中在给定的作用域中只能指定一次默认参数
且编译器使用的是当前作用域中的默认参数
// 下面是在一个文件下同时进行声明和定义
// 下面通常来讲是错误的
void func(int a=1);int main()
{func();return 0;
}void func(int a=1) // 不能同时指定默认参数
{cout<<a<<endl;
}
第二个例子
这个例子就没有错误
/*test.c*/
void func(int a=1) // 定义的作用域在test.c文件中
{/*code*/cout<<a<<endl;
}
/*main.c*/
extern void func(int a=2); // 声明的作用域在main.c文件中
int main()
{func(); // a结果是2 不是1,编译器使用的是当前作用域中的默认参数return 0;
}
函数重载
函数功能类似,实现细节不同
函数名可以相同,参数列表不同(参数个数不同 或 参数类型不同 或 参数循序不同)就可以
编译器会自动根据实参类型进行调用
函数名必须相同,参数的返回值可以相同,也可以不相同
函数重载,本质上是不同的函数,占用不同的内存,入口地址不一样
注意:参数名不同不可以;参数名相同的情况下有缺省和无缺省 的重载不可以
注意:函数重载时的二义性问题(多个参数和类型转换的二义性),见文档
传递方式
内置数据类型,可以值传递、指针传递,引用传递没有必要(引用传递一般就是值传递)
数组必须是指针传递
结构体和实例对象可以值传递也可以指针传递
值传递
相当于深拷贝
指针(地址)传递
相当于浅拷贝
引用传递
c语言中没有引用传递
相当于别名
引用必须在定义的同时进行初始化,且不能在改变,即不能在引用其他数据
dataType &name=data;
对于指针
https://blog.csdn.net/llm_hao/article/details/108432323
typedef int * PINT;
PINT p1;
PINT &p2=p1; // p2是p1的别名
引用传递与const
对于自定义类型的参数(非内部类型)
/*在函数体内会产生自定义类型的临时对象用于赋值形参相当于深拷贝,这个临时(拷贝)对象的构造、复制、机构过程都消耗事件**需要注意的是,对于内部类型,int|float等形参,不存在构造、析构过程**
*/
void func(MyClass item){} // 这个方法不会修改源数据// 可以改写为 引用传递的方式
void func(MyClass &item){} // 但是这个方法会修改源数据// 为了不修改源数据,又不消耗额外的内存
void func(const MyClass &item)
指针引用
注意事项: 地址传递的地址(地址)依然是副本(深拷贝、地址传递)
https://blog.csdn.net/llm_hao/article/details/108432323
https://blog.csdn.net/magicdoubi/article/details/98171260
通过地址(指针)传递可以修改指向的内容,但是指针本身是值传递
(当把一个指针作为参数传递给一个函数或方法时,其实是把指针的副本copy传递给了函数,即把指针的值本身传递到ptr,因此当在函数或方法内部修改指针(注意,不是修改指针所指向的值)时,其实修改的是函数内部指针的副本,而非外部的指针本身)
如果不是指针引用:指针的指向改变并不影响原指针的指向,指针指向的值的改变可以影响原值
进阶例子,看算法与数据结构dsa-单链表 - 重要
typedef struct LNode
{int data;struct LNode *next; // 用于指向下一个节点
}LNode,*LinkList;
// typedef struct LNode NODE;
// typedef struct LNode *LinkList; // 下面其实是一样的,不过看起来更优雅
// LNODE * 表示一个节点,一个指向一个节点的指针
// LinkList 表示一个链表/* L1 相当是L的别名 而且是指针别名修改L1的指向,就是修改L的指向如果bool InitList(LinkList L1){}这样一开始形参(局部变量)L1和L指向的是同一块内存,但是L1=NULL后就指向的不是同一块内存了就是错误的
*/
bool InitList(LinkList &L1) // 引用传递
{L1=NULL; //struct LNode* ,这个必须是指针引用,否则,就不对return true;
}int main()
{LinkList L; // 相当于指针引用InitList(L);return 0;
}
引用与函数返回值
返回的是return 数据的别名
注意: 将引用作为函数返回值的时候,不能将局部数据的引用,因为局部数据存在栈区,函数调用结束后会被销毁,有可能下次使用数据的时候就不存在了
int &func(int &r)
{r+=10;return r;
}int main()
{int var=1;cout<<var<<endl; //1int var2=func(var); //11cout<<var<<endl; cout<<&var<<" "<<&var2<<" "<<&func(var)<<endl;cout<<var<<endl; // 21int &var3=func(var);cout<<var<<endl; //32cout<<&var3<<endl;// &var == &func(var)==&var3// &var != &var2return 0;
}
引用与指针
相同
引用就是对指针的封装,底层还是基于指针
int a=10;
int &a2=a;
cout<<&a2<<" "<<&a<<endl;// 在编译器下会被编译成
int a=10;
int *a2=&a;
cout<<a2<<" "<<&a<<endl;
区别
引用必须在定义时进行初始化,且不能被修改
指针可以被修改
数组必须是指针传递,不能使用引用传递(数组型字符串只能是指针,不能是引用)
int &arr2[4]=arr1 没有这种写法
结构体和实例对象可以值传递也可以指针传递
引用++ 是数值+1
指针++ 是地址+1,指向下一个元素
引用与临时数据 - 还要看
见文档
引用不能指代临时数据
只有加上const
还是正确的
int m=10,n=20;// 下面都属于临时数据变量,不能被引用所指代,都是错的
int &a=m+n;
int &a=1+2;
int &a=2*3;
int &a=m+1;
int &a=func();void func(int &a) {}
func(m+n);
func(1+2);
func(m+1);// 下面是正确的
const int &a=m+n;
const int &a=1+2;
const int &a=2*3;
const int &a=m+1;
const int &a=func();void func(const int &a) {}
func(m+n);
func(1+2);
func(m+1);
引用与const 其他注意事项- 还没看
const 与函数
https://blog.csdn.net/u013377887/article/details/108887633
https://blog.csdn.net/cuizhiyi2008/article/details/102784754
const与形参
见上面的引用传递
// 为了不修改源数据,又不消耗额外的内存
void func(const MyClass &item)
const修饰函数(返回值)
修饰的是函数的返回值
返回值的内容不能被修改,只能赋值给同类型的const的内容
const 只修饰指针类型的返回值,值传递方式的返回值没有任何意义
const dataType func();
const var=func(); // 这种是对的// 下面是错的
// const var;
// var=func()
const 成员函数
在成员函数声明和定义的后面加入关键字const,表示const成员函数可以使用类中的所有成员变量,但是不能修改他们的值
见’c+±面向对象’