一、命名空间
1.命名空间(namespace)的定义
在C/C++中,变量,函数以及后面C++要学的:类都是大量存在的,这些变量函数和类都存在于全局作用域中,这样可能会导致很多冲突,也就是命名冲突。使用命名空间的目的就是对这些标志符也就是变量函数等名称进行本地化,以此来避免命名冲突或名字污染。于是namespace关键字就应运而生来针对解决这种问题。
在定义一个新的命名空间的时候,使用关键字namespace加后面命名空间的名称,然后再接一对{}就可以了,{}里面就是命名空间的成员。
(1)命名空间的格式:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <iostream>
using namespace std;
namespace N1
{
//命名空间的内容,既可以定义变量,也可以定义函数
int a = 0;
int ADD(int x, int y)
{
return x + y;
}
}
(2)命名空间可以嵌套
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;
}
}
}
(3)可以有多个命名空间
一个程序中可以有多个命运空间不会冲突,当编译器运行时,会将两个命令空间的内容合并到一起。
注意:
- 在同一块命名空间中,不能有相同的变量和函数名。
- 一个新的命名空间定义了一块新的作用域,里面的所有内容都只局限于该命名空间。
- C++为了防止命名冲突,把自己库里面的所有东西都定义到std的命名空间中(std:C++标准库)
2.域 以及 编译器的搜索原则
对于全局域和局部域来说,他们不仅影响生命周期,还影响访问。
但是命名空间域只影响访问,最初的变量是什么,在namespace之后生命周期不变。
(::)域作用限定符,如果域作用限定符左边是空白,就默认是在全局域中进行搜索。
如果域作用限定符左边有指定域,那就只会在指定域进行搜索。
3.namespace的三种使用方式
(1)加命名空间名称及作用域限定符(N1::a),比较麻烦,每个用到域中成员的地方都得指定成员的域
(2)用using将命名空间成员或函数引入(using N1::a,访问a时就不需要加访问限定符”::”)
(3)使用using namespace 命名空间名称引入(using namespace N1,访问a时就不需要加访问限定符”::”)
二、C++的输入与输出
1.标准输出流:cout
标准输入流:cin
2.cout(流插入,可自动识别数据类型)
3.endl(相当于换行符:printf(“n”))
4.对于浮点数的精度控制:
cout和cin不好写,所以在C++中写浮点数是就写:printf和scanf
注意:
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
- cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
- <<是流插入运算符,>>是流提取运算符
- C++的输入输出(cout,cin)可以自动识别变量类型
#include <iostream>
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;
}
三、缺省参数
1.缺省参数的定义
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
void func(int a = 0)
{
cout << a << endl;
}
int main()
{
func();//该语句没有对函数进行传参,那么就用我的缺省参数a=0
func(10);//该语句实参给形参传了,那么a==10
return 0;
}
2.缺省参数的分类
(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)注意:
- 半缺省参数必须从右往左依次来给出,不能间隔着给
- 缺省参数不能在函数声明和定义中同时出现
- 缺省值必须是常量或者全局变量
四、函数重载
1.函数重载的概念
函数重载:是函数的一种特殊情况,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;
}
2.C++支持函数重载的原因
在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
1.通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
2.如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分
五、引用
1.引用的定义
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
比如:李逵,在家称为”铁牛”,江湖上人称”黑旋风”。无论是使用引用变量,还是它本身的变量都是同一个值同一个内容。
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;
}
2.引用的特性
(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;
}
3.使用场景
(1)做参数
引用可以做参数,可以代替指针的作用
如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;
}
(2)做返回值
1.传值返回
传值返回,返回的是返回对象c的拷贝,不拿c做返回值,c只是Add的临时变量,Add函数调用结束后,c就不在了,因此不能返回c,返回的是临时变量。
#include<iostream>
using namespace std;
int Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int ret = Add(1, 2);
return 0;
}
2.传引用返回
传引用返回,返回的是返回对象c的引用(别名),当调用完Add函数,return返回后,Add的栈帧被销毁了,但是它使用的内存空间还在,只是使用权不属于它了,所以再去访问那块内存空间时,内存空间有可能没被清空,也有可能被清空了,因此有可能是以前的值,也有可能是随机值,所以代码的运行结果是不确定的。
#include<iostream>
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函数调用完毕,栈帧销毁,但是静态区不会销毁,栈帧销毁对函数局部变量没有影响。
什么时候使用传值返回,什么时候使用传引用返回呢?
如果函数返回时,出了函数作用域,如果返回对象还在(还没还给操作系统) ,可以使用引用返回,如果已经还给系统了,必须要用传值返回。
3.传值和传引用的区别
传值传参和传值返回:在传参和返回期间,形参是实参的一份拷贝,返回变量是变量本身的一份拷贝,实参和变量本身占多大空间,形参和返回变量就占多大空间,在函数内操作副本,对该变量的修改并不会修改函数外部的变量。
传引用传参:形参和实参是同一个东西,实际操作的就是该变量,由于引用是指向某个变量的,对引用的操作其实就是对他指向的变量的操作,因此函数内对变量进行修改的话,外部变量也会被相应修改。
4.引用和指针
1.在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
2.在底层实现上实际是有空间的,因为引用是按照指针方式来实现的(汇编层面:引用也是通过指针实现的,所以在底层没有引用一说,只有指针)
引用和指针的不同点
- 引用概念上定义一个变量的别名,指针存储一个变量地址。
- 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
- 没有NULL引用,但有NULL指针
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
六、内联函数
1.内联函数的概念
以inline修饰的函数叫做内联函数 编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
2.特性
- inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
- inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性
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;
}
七、auto和 nullptr
1.关键字:auto
1.auto:自动识别变量的数据类型
注意:
- auto必须初始化
- auto不能作为函数的参数
- auto不能定义数组
- auto可以做函数返回值,但是你就别用,因为真的很坑!!!
int main()
{
int a = 10;
double b = 100.19;
auto c = b;//c和b一样是double类型的!!!
cout << typeid(c).name() << endl;
return 0;
}
2.nullptr
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函数:
注意:
- 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
- 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
- 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。
好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!
原文地址:https://blog.csdn.net/weixin_75128035/article/details/135941046
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_66293.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!