1.命名空间
使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员
①.普通的命名空间
c
namespace N1{//命名空间的内容,既可以定义变量,又可以定义函数
int a;
int Add(int left,int right){
return left+right;
}
}
②.命名空间可以嵌套
c
namespace N1{//命名空间的内容,既可以定义变量,又可以定义函数
int a;
int Add(int left,int right){
return left+right;
}
namespace N3{
int c;
int d;
int sub(int left,int right){
return left-right;
}
}
③.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间
命名空间的使用
①.加命名空间名称和域作用限定符
c
int main(){
printf("%d",N::a);
return 0;
}
②.使用using将命名空间中成员引入
c
using N::b
int main(){
pritnf("%d",N::b);
return 0;
}
③.使用using namespace 命名空间名称引入
using namespace N;
using namespace N;//全部展开,全部授权
using N::add;//部分展开,部分授权
using namespace std;
std是c++标准库的命名空间
2.c++输入/输出
<<流插入运算符
流提取运算符
c
cout<<"hello world"<<endl;
endl为换行符
c
cout<<"hello world"<<"\n";
两者效果相同
使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含头文件以及std标准命名空间
使用c++输入输出更加方便,不需增加数据控制格式,比如整形"%d" 字符"%c"
注意cin的特点,与c语言中gets有些类似,gets是遇到换行符停止,而cin是遇到空格,tab或者换行符作为分隔符的,
c
char arr[20]={};
cin>>arr;
输入hello world 但由于中间存在空格,故arr这个数组中只有hello,没有world
3.缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值,在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
void func(int a=10){
cout<<a<<endl;
}
int main(){
func();//没有传参时,使用参数的默认值
func(10);//传参时,使用指定的实参
}
分类
全缺省参数
void func(int a=10;int b=20;int c=30){}
半缺省参数
void func(int a,int b=20;int c=30){}
注意①.半缺省参数必须从右往左依次来给,不能间隔着给
②.缺省参数不能在函数的声明和定义中同时出现
因为如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用哪个缺省值
声明不给定义给
③.缺省值必须是常量或者全局变量
//正确示例
c
int x = 3;//全局变量
void func(int a, int b = 2, int c = x)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
4.函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的
形参列表(参数个数 或类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题
c
#include <iostream>
using namespace std;
int Add(int x, int y)
{
return x + y;
}
double Add(double x, double y)
{
return x + y;
}
int main()
{
cout << Add(0,1) << endl;//打印0+1的结果
cout << Add(1.1,2.2) << endl;//打印1.1+2.2的结果
return 0;
}
注意:若仅仅只有返回值不同,其他都相同,则不构成函数重载。
c语言与c++类似,都要进行编译和链接两个过程
编译后链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址实在b.o中
链接器看到a.o调用Add,但没有Add的地址,就会到b.o的符号表(符号表就是函数名,变量跟地址的映射)中去找Add的地址,然后链接到一起。面对多个Add函数,每个编译器有自己的修饰规则,在gcc下的修饰规则是:【_Z+函数长度+函数名+类型首字母】。
之所以c语言无法支持重载,是因为C编译器和C++编译器对函数名的修饰不同
所以,返回值的不会构成函数重载,因为修饰规则并不会受返回值的影响。
如果函数名修饰规则带入返回值,返回值能否构成重载?
不能,因为不知道要调用谁
5.引用
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它
引用的变量共用同一块内存空间。
类型& 引用变量名(对象名) = 引用实体;
int a=10;
int&b=a; //相当于给a取了一个别名,给b引用了a,同一个变量取了个名字
b=3;//改变b也就相当于改变a了
引用类型必须和引用实体是同种类型的
引用的特性
①.引用在定义时必须初始化
c
//正确示例
int a = 10;
int& b = a;//引用在定义时必须初始化
//错误示例
int a = 10;
int &b;//定义时未初始化
b = a;
②.一个变量可以有多个引用
c
int a = 10;
int& b = a;
int& c = a;
int& d = a;
③.引用一旦引用了一个实体,就不能再引用其他实体(c++的引用不能改变指向)
c
int a = 10;
int& b = a;
int c = 20;
b = c;//错误,b已经引用了a,就不能在引用c
实际效果变为,b的值变为20,而因为a与b相同,故a的值也变成了20
常引用
在引用的过程中,权限可以平移,可以缩小,但不能放大
c
const int a=10;
int&b=a;
会出现错误,相当于权限的放大,因为在这里a为常量,如果用int&b=a;那么,b可以修改,但a不可以修改
c
const int&ra=a;
相当于权限的平移,不会出错
c
int&b=10;
会出现错误,b为常量,需要改为
c
const int&b=10;
c
int i=0;
double&d=i;
会出现错误,因为发生类型转换时会产生一个double类型临时变量,临时变量具有常性
(int到double存在隐式类型的提升,而在提升的过程中系统会创建一个常量区来存放a类型提升后的结果)
需要改为
c
int i=0;
const double&d=i;
c
int func(){
int a=0;
return a;
}
int&ret=func();
会出现问题,因为func的返回值是a的一份临时拷贝,临时变量具有常性
需改成
c
const int&ret=func();
引用的使用场景
①.做参数
c
void swap(int&left,int&right){
int temp=left;
left=right;
right=temp;
}
②.做返回值
当然引用也能做返回值,但是要特别注意,我们返回的数据不能是函数内部创建的普通局部变量,因为在函数内部定义的普通的局部变量会随着函数调用的结束而被销毁。我们返回的数据必须是被static修饰或者是动态开辟的或者是全局变量等不会随着函数调用的结束而被销毁的数据。
c
int& count(){
int n=0;
n++;
return n;
}
int main(){
int ret=count();
return 0;
}
count函数返回n的别名,但是n已经销毁,如果栈帧没有清楚,那么结果为1,否则结果为随机值
c
#include<iostream>
using namespace std;
int&Add(int a,int b){
int c=a+b;
return c;
}
int main(){
int&ans=Add(1,2);
Add(3,4);
cout<<ans<<endl;
}
但如果再加上一句cout<<ans<<endl;打印出的结果将变为随机值
因为在第一次调用cout<<ans<<endl时,函数传参建立栈帧,调用完后被覆盖,第二次调用时已经被覆盖,为随机值
c
#include<iostream>
using namespace std;
int& Add(int a, int b)
{
static int c = a + b;
return c;
}
int main()
{
int& ans = Add(1,2);
Add(3, 4);
cout << ans << endl;
}
为什么会出现随机值,因为你在函数里定义的变量是临时变量,出了函数函数是会销毁的,这时它就随机指向内存中的一块空间了。所以在引用做函数返回值时最好还是给在函数中定义的变量加上static。加上static后,结果将变为3。
因为第二次调用Add函数时,static int c=a+b;并不会执行,而是直接return c;
但如果将该函数修改为
c
int& Add(int a, int b)
{
static int c ;
c=a+b;
return c;
}
总结:
传引用传参(任何时候都可以)
①.提高效率
②.输出型参数(形参的修改影响实参)
传引用返回(出了函数作用域对象还在才可以用)
①.提高效率
②.
顺序表查找和修改可以用一个函数来解决
c
int& SLAT(struct seqlist&ps,int i){
return ps.a[i];
}
想要修改SLAT(s,0)=1;