在C/C++中,变量,函数以及后面C++要学的:类都是大量存在的,这些变量函数和类都存在于全局作用域中,这样可能会导致很多冲突,也就是命名冲突。使用命名空间的目的就是对这些标志符也就是变量函数等名称进行本地化,以此来避免命名冲突或名字污染。于是namespace关键字就应运而生来针对解决这种问题。
在定义一个新的命名空间的时候,使用关键字namespace加后面命名空间的名称,然后再接一对{}就可以了,{}里面就是命名空间的成员。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
namespace N1
{
//命名空间的内容,既可以定义变量,也可以定义函数
int a = 0;
int ADD(int x, int y)
{
return x + y;
}
}
namespace N1
{
//命名空间的内容,既可以定义变量,也可以定义函数
int a = 0;
int ADD(int x, int y)
{
return x + y;
}
//命名空间可以套命名空间
namespace N2
{
int SUB(int a, int b)
{
return a - b;
}
}
}
一个程序中可以有多个命运空间不会冲突,当编译器运行时,会将两个命令空间的内容合并到一起。
注意:
对于全局域和局部域来说,他们不仅影响生命周期,还影响访问。
但是命名空间域只影响访问,最初的变量是什么,在namespace之后生命周期不变。
(::)域作用限定符,如果域作用限定符左边是空白,就默认是在全局域中进行搜索。
如果域作用限定符左边有指定域,那就只会在指定域进行搜索。
(1)加命名空间名称及作用域限定符(N1::a),比较麻烦,每个用到域中成员的地方都得指定成员的域
(2)用using将命名空间成员或函数引入(using N1::a,访问a时就不需要加访问限定符"::")
(3)使用using namespace 命名空间名称引入(using namespace N1,访问a时就不需要加访问限定符"::")
1.标准输出流:cout
标准输入流:cin
2.cout(流插入,可自动识别数据类型)
3.endl(相当于换行符:printf(“\n”))
4.对于浮点数的精度控制:
cout和cin不好写,所以在C++中写浮点数是就写:printf和scanf
#include
using namespace std;
int main()
{
int a;
double b;
char c;
cin >> a;
cin >> b >> c;
cout << a << " ";
cout << b << " ";
cout << c << endl;
return 0;
}
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
void func(int a = 0)
{
cout << a << endl;
}
int main()
{
func();//该语句没有对函数进行传参,那么就用我的缺省参数a=0
func(10);//该语句实参给形参传了,那么a==10
return 0;
}
(1)全缺省参数:在函数声明或定义时为所有参数都指定一个默认值,调用函数时只给传了实参的参数赋值为实参,否则为默认值:
void func(int a = 0, int b = 10 ,int c = 100)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
func();
return 0;
}
(2)半缺省参数:在函数声明或定义时从右向左为部分参数指定一个默认值,且不能间隔给出
//void func(int a = 0, int b, int c = 100)//错误,缺省参数不能间隔着赋值
//void func(int a = 0, int b=10,int c )//错误,缺省参数必须从右往左赋值
void func(int a , int b=10, int c = 100)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
func(0);
return 0;
}
(3)注意:
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的 同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题
//1.参数的类型不同
int ADD(int a, int b)
{
return a + b;
}
double ADD(double a, double b)
{
return a + b;
}
//2.参数的个数不同
void f(int a = 1)
{
cout << a << endl;
}
void f()
{
int a = 10;
cout << a << endl;
}
//3.参数的类型顺序不同
void f(int a, char b)
{
cout << a << endl;
}
void f(char b, int a)
{
cout << a << endl;
}
在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
1.通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
2.如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。无论是使用引用变量,还是它本身的变量都是同一个值同一个内容。
int main()
{
int a = 10;
int& b = a;//b是a的引用(别名)a就是b,b就是a!!!
//注意:引用类型必须和引用实体是同种类型的
cout << a << endl;
cout << b << endl;
printf("%p \n", &a);
printf("%p ", &b);
return 0;
}
(1)引用在定义时必须初始化
int main()
{
int a = 10;
int& c;//错误,没有初始化!!!
int& b = a;//b是a的引用(别名)a就是b,b就是a!!!
return 0;
}
(2)一个变量可以有多个引用
int main()
{
int a = 10;
int& b = a;//b是a的引用(别名)a就是b,b就是a!!!
int& c = a;
int& d = a;
return 0;
}
(3)引用一旦引用一个实体,再不能引用其他实体
int main()
{
int a = 10;
int c = 100;
int& b = a;//b是a的引用(别名)a就是b,b就是a!!!
int& b = c;// b已经作为a的引用,不能再作为c的引用了
return 0;
}
引用可以做参数,可以代替指针的作用
如Swap函数,指针的写法如下,有多处使用"*"解引用
void Swap(int* left,int* right)
{
int tmp=*left;
*left=*right;
*right=tmp;
}
如果用引用做参数,不需要解引用,不需要使用"*"
void Swap(int& left,int& right)
{
int tmp=left;
left=right;
right=tmp;
}
传值返回,返回的是返回对象c的拷贝,不拿c做返回值,c只是Add的临时变量,Add函数调用结束后,c就不在了,因此不能返回c,返回的是临时变量。
#include
using namespace std;
int Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int ret = Add(1, 2);
return 0;
}
传引用返回,返回的是返回对象c的引用(别名),当调用完Add函数,return返回后,Add的栈帧被销毁了,但是它使用的内存空间还在,只是使用权不属于它了,所以再去访问那块内存空间时,内存空间有可能没被清空,也有可能被清空了,因此有可能是以前的值,也有可能是随机值,所以代码的运行结果是不确定的。
#include
using namespace std;
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(5, 7);
cout << "ret = "<<ret << endl;
return 0;
}
当调用Add(5,7) 时,调用的是同一个函数,在同一位置上再建立一个栈帧,栈帧大小是一样的,c的位置也一样,仅仅只是把c的位置的内容由3改成了12,因此ret的值也为12。
因此实际中,如果出了函数作用域,返回对象就不存在了,不能用引用返回。如果非要用引用返回,就要使用static关键字,延长变量的生命周期,Add函数调用完毕,栈帧销毁,但是静态区不会销毁,栈帧销毁对函数局部变量没有影响。
什么时候使用传值返回,什么时候使用传引用返回呢?
如果函数返回时,出了函数作用域,如果返回对象还在(还没还给操作系统) ,可以使用引用返回,如果已经还给系统了,必须要用传值返回。
传值传参和传值返回:在传参和返回期间,形参是实参的一份拷贝,返回变量是变量本身的一份拷贝,实参和变量本身占多大空间,形参和返回变量就占多大空间,在函数内操作副本,对该变量的修改并不会修改函数外部的变量。
传引用传参:形参和实参是同一个东西,实际操作的就是该变量,由于引用是指向某个变量的,对引用的操作其实就是对他指向的变量的操作,因此函数内对变量进行修改的话,外部变量也会被相应修改。
1.在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
2.在底层实现上实际是有空间的,因为引用是按照指针方式来实现的(汇编层面:引用也是通过指针实现的,所以在底层没有引用一说,只有指针)
以inline修饰的函数叫做内联函数 编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
inline void Swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a = 10;
int b = 100;
cout << a << " " << b << endl;
Swap(&a, &b);
cout << a << " " << b << endl;
return 0;
}
1.auto:自动识别变量的数据类型
注意:
int main()
{
int a = 10;
double b = 100.19;
auto c = b;//c和b一样是double类型的!!!
cout << typeid(c).name() << endl;
return 0;
}
NULL实际是一个宏,NULL的定义:
NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。但对于如下代码:
void f(int)
{
cout<<"f(int)"<<endl;
}
void f(int*)
{
cout<<"f(int*)"<<endl;
}
int main()
{
f(NULL);
f((int*)NULL);
return 0;
}
在c++中,NULL被定义为0,想用f(NULL)用空指针NULL作为参数,但是根据打印结果,发现 f(NULL)调用的是参数为int的f函数:
好了,今天的分享就到这里了
如果对你有帮助,记得点赞+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!