命名空间
1、命名空间的目的是对标识符的名称进行本地化, 以避免命名冲突或名字污染。这是一种新的语法,决定了编译器的编译原则。
2、命名空间的定义
(1)定义示例
namespace std_total
{
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
namespace std_inside
{
int x = 1;
}
}
①namespace为关键字,后面的是命名空间的名字。
②{}内的为命名空间的成员,里面可以有变量、函数、自定义类型等。
(2)命名空间可以嵌套。
(3)命名空间的合并:同一个工程中可以存在许多个相同的命名空间,编译器最后会合并到同一个命名空间中。
3、命名空间的使用
(1)方式一:域作用限定符:“::”
①默认查找是全局空间查找,不会到命名空间内查找,因此需要域作用限定符,告诉编译器来命名空间查找。
②用作用于限定符是比较安全的访问方式。
(2)方式二:using namespace std;
①含义:命名空间完全展开。展开后就可以去命名空间查找了,不需要域作用限定符了。
②展开后十分危险,相当于命名空间失效了。
(3)方式三:using std::Add;
①含义:命名空间部分展开。
②针对在一个工程中多次使用并且没有命名冲突的变量或者函数等使用。
(4)嵌套命名空间
使用起来需要套娃:printf("%d\n", std::std_inside::x);。
7、cout和endl都是在iostream这个头文件下的std库中。
C++的输入和输出
一、C++标准库
1、概念:std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中。
2、使用
(1)在日常的练习中可以直接using namespace std;
(2)在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。
二、cout和cin
1、使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
2、使用方式
流插入:
cout << i << endl;
cout << &i << endl;
流提取:
int i = 0;
int j = 0;
std::cin >> i>>j;
(1)cout和cin是全局的流对象。
(2)endl是特殊的C++符号,表示换行输出,相当于’\n’, 意思就是end of line,包含在< iostream >头文件中。
(3)<<是流插入运算符、>>是流提取运算符。
(4)使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。 C++的输入输出可以自动识别变量类型。
缺省参数
1、概念:缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实 参则采用该形参的缺省值,否则使用指定的实参。相当于默认参数。
void Func(int a = 1)
{
cout << a << endl;
}
(1)函数调用方式:
正常函数调用:Func(2);此时使用指定的实参。
缺省参数调用法:Func();此时没有传参,使用默认值。
2、缺省参数的分类
(1)当全部参数都是缺省的时候就是全缺省
void Func2(int a = 1, int b = 2, int c = 3)
{
cout << "a=" << a << endl;
cout << "b=" << d << endl;
cout << "c=" << c << endl;
}
(1)显示传参,必须从左往右显示传参,。
可以:Func2(1); Func2(1, 2, 3);
不可以:Func2(, , 3);
(2)半缺省参数:必须从右往左给缺省值,不能间隔着给值。
void Func2(int a, int b = 2, int c = 3)
{
cout << "a=" << a << endl;
cout << "b=" << d << endl;
cout << "c=" << c << endl;
}
4、缺省参数定义和声明不能同时给
(1)建议声明时候给,定义的时候不给。
函数重载
1、函数重载概念:函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表不同,常用来处理实现功能类似数据类型不同的问题,可以理解为一个函数有多个意思。
2、函数重载要求:函数名相同,参数不同
(1)参数不同:
①类型不同
int Add(int left, int right)
{
return left + right;
}
double Add(double left, double right)
{
return left + right;
}
②个数不同
void Fun();
void Fun(int a);
③顺序不同:类型的顺序不同,形参的名字不管用。
void Fun(int a,double b);
void Fun(double a,int b);
(2)返回值不同不能构成重载。
(3)函数重载要在相同的作用域中。
3、函数重载的原理
(1)预处理的时候,会进行头文件展开(将头文件的内容拷贝过来),宏替换,去掉注释,条件编译,生成test.i文件。编译的时候,会检查语法,生成汇编代码,就是move等指令,已经是指令级代码。此时对于一个函数Fun,是call Fun(地址)。这一步生成test.s文件。汇编的时候,将汇编代码生成二进制的机器码,生成test.o的目标文件。之后会进行连接,在合并链接之后,生成可执行程序。在call的时候会跟地址,在符号表里面是函数名和地址的映射,将不同文件中的函数连接起来。在符号表中,C语言是将函数名充当符号表中的名字,通过这个找到函数的地址,从而连接起来。
(2)C++中有函数名修饰规则,不同的编译器不同。在VS中只有声明没有定义的时候会找不到函数。函数的地址是一个跳转指令,只有声明的时候没有转跳指令,没有地址,就会报错。
(3)函数的地址可以理解为第一个指令的地址,因此函数只有声明没有定义的时候是不会有地址的,也不会有栈帧,在符号表中找的时候也找不到。
(4)即使在函数名修饰规则中带入返回值,因为不知道调用谁,除非是修改链接规则,否则无法支持。
引用
一、概念
1、引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
2、类型& 引用变量名(对象名) = 引用实体;
int i = 10;
int& j = i;//定义引用类型
1)跟在类型和变量中间才是引用,否则是取地址。
(2)引用类型必须和引用实体是同种类型的。
二、引用的特性
1、引用必须在定义的时候就初始化。
2、一个变量可以有多个引用,可以给引用取别名。
3、引用一旦引用一个实体,再不能引用其他实体(C++无法脱离指针)。
三、常引用
1、规则:在引用的过程中,权限可以平移恶化缩小,但是权限不能放大。
(1)赋值不受这个规则的影响。
2、实例
int main()
{
const int a = 0;
//int& b = a;//这是一种权限的放大。
const int& c = a;//这是一种权限的平移。
int x = 0;
const int& y = x;//权限的缩小
int i = 0;
const double& d = i;//变量类型变换的时候,会产生一个临时变量,这个时候临时变量是double,由于临时变量具有常性,因此要加const,防止权限的放大
int b = a;//赋值不受影响
return 0;
}
四、引用的使用场景
1、引用做参数
引用作为输出型参数的时候很有用。
void Swap(int& x1, int& x2)
{
int tmp = x1;
x1 = x2;
x2 = tmp;
}
int main()
{
int x = 0, y = 1;
Swap(x, y);
return 0;
}
(1)输出型参数:平时的参数都是为了输入,输出型参数就是为了拿数据,从其他变量那里拿数据
2、引用做返回值
(1)函数在传值返回的时候,可以将n拷贝到寄存器,若n太大会在缝隙中开辟一块空间,保证栈帧销毁的时候不会受到影响。
(2)引用可以拷贝给别人,直接引用类似于用野指针,若栈帧已经被清,这里就会是一个随机值。
(3)如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用 引用返回,如果已经还给系统了,则必须使用传值返回。对于静态对象和全局对象都可以用引用返回,在函数外面的参数也可以用引用返回。
int& Count1()
{
int n = 0;
n++;
return n;//返回的是n的别名
}
3、传值、传引用效率比较
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效 率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。