目录
一、命名空间
下面是我们C++刚入门就会写的一个打印hello world的简单程序,
#include <iostream>
using namespace std;
int main()
{
count << "hello world" << endl;
}
很多人不知道为什么要这么写
首先我们需要了解命名空间这个概念
我们在使用C语言时知道不能定义和库函数同名的变量,这就导致我们在做项目时如果需要和其他人共同完成时容易产生同名变量导致程序无法正常链接起来,C++为了弥补这个缺陷,便有了命名空间。
下面是对命名空间的使用:(下面的::符号是域作用限定符,当::前面没有指定域即为空白时,表示为全局)
#include <stdio.h>
namespace xie
{
int rand = 0;//可以定义变量
void func()//可以定义函数
{
printf("func()\n");
}
struct TreeNode()//可以定义结构体
{
struct TreeNode* left;
struct TreeNode* right;
int val;
};
}
namespace xie//命名空间可以是不连续,下面的rand1变量依旧是在bit这个命名空间里。
{
int rand1 = 1;
}
namespace a//命名空间可以嵌套使用
{
namespace xie
{
int rand2 = 2;
}
}
int x = 0;
int main()
{
int x = 1;
printf("%d", ::x);//打印0
printf("%d", xie::rand);//打印0
printf("%d", a::xie::rand2);//打印2
xie::func();//打印func()
struct xie::TreeNode Node;
}
不过对于命名空间内变量的使用需要频繁的使用域作用限定符::,会感觉很麻烦,如果使用using
如下代码
#include <stdio.h>
namespace bit
{
int a = 1;
int b = 2;
int c = 3;
}
using namespace bit;
int b = 0;
int c = 0;
int main()
{
int c = -1;
printf("a:%d ", a);//打印1
//printf("%d", b);//此时编译器无法确定b是bit::b还是全局变量中的b
printf("c:%d", c);//打印-1,优先使用mian函数局部域的变量。
}
这样确实方便了许多,但是我们展开命名空间,反而将命名空间暴露出来,依旧会产生命名冲突的问题,所以有以下几点需要注意。
- 项目中,尽量不使用using namespace std;//std的标准库的命名空间。
- 日常练习中使用using namespace std;
- 项目中使用指定命名空间访问或者展开常用的。(下面代码为如何展开常用的)
#include <iostream>
using namespace std:count;//展开常用的
int main()
{
count << "hello world" << std::endl;//std::endl是指定命名空间访问
}
二、缺省参数
缺省参数是声明或定义时为函数参数指定的一个默认值。在调用函数时,如果没有指定实参则采用该默认值,否则使用该实参。(缺省值必须为常量或者全局变量)
#include <iostream>
using namespace std;
void Func(int a = 0)
{
count<< a <<endl;
}
int main()
{
Func(1);//打印1
Func();//打印0
}
缺省参数分为全缺省和半缺省
#include <iostream>
using namespace std;
//全缺省
void Func1(int a = 10, int b = 20, int c = 30)
{
count << "a= " << a << endl;
count << "b= " << b << endl;
count << "c= " << c << endl;
}
//半缺省(从右往左依次缺省)
void Func2(int a, int b = 20, int c = 30)
{
count << "a= " << a << endl;
count << "b= " << b << endl;
count << "c= " << c << endl;
}
//错误写法:void Func3(int a = 10, int b, int c)
int main()
{
Func1(1);//打印a= 1 b= 20 c= 30
Func1(1, 2);//打印a= 1 b= 2 c= 30
//传参数从左往右依次给
//Func1(, 1, 2);//这种写法是错误的不能跳过参数a传参给b,c。
}
由于声明和定义时都可以指定一个默认值,那么以什么为准呢?
答案是以声明为准,如果声明中没有缺省参数,定义中有时,无法使用缺省参数。
如果声明和定义都有缺省参数,但是缺省的参数不同时,以声明中的缺省参数为准。
三、函数重载
函数重载是函数的一种特殊情况,C++允许同一作用域中声明几个功能类似的同名函数,这些同名函数的形参(参数个数或参数类型或顺序)至少其中一种不同,常用于处理功能类似数据类型不同的问题。
#include <iostream>
using namespace std;
using std;
int Add(int left, int right)
{
return left + right;
}
double Add(double left, double right)
{
return left + right;
}
void func(char ch, int i)
{
}
void func(int i, char ch)//与第一个func构成重载函数
{
}
//下面举例与第一个func不构成重载函数
//void func(char i, int ch)形参名交换
//double func(char ch, int i)返回值不同
int main()
{
count << Add(1, 2); << endl;//调用第一个函数
count << Add(1.1, 2.2); << endl;//调用第二个函数
}
为什么C++支持重载而C语言不支持呢?
我们知道一个程序需要经过预处理、编译、汇编、链接四个阶段才能产生。
.c和.h文件
预处理:头文件的展开、宏替换、条件编译、去掉注释。
.i文件
编译:语法检查,生成汇编代码。
.s文件
汇编:把汇编代码转化为二进制机器码。
.o文件(每个.o文件有一个对应的符号表)
链接:把.o的目标文件合并到一起,其次找到一些只给声明的函数的地址
在C编译器下.o文件的符号表没有函数名修饰规则,在符号表中只有函数名,所以编译器无法分辨同名的重载函数。
而在C++编译器下.o文件的符号表有对应的函数名修饰规则,函数的形参(参数个数或参数类型或顺序)至少其中一种不同,则该同名函数在符号表中便是不同的,编译器能够分辨同名的重载函数。
四、引用
引用不是定义了一个新变量,而是给已有变量的去了一个别名,编译器不会为引用变量开辟内存空间,它和它的变量共用同一块内存空间。
引用的特性:
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体
#include <iostream>
using namespace std;
int main
{
int a = 0;
int x = 1;
//一下b、c、d都是变量a的引用
int& b = a;
int& c = a;
int& d = c;
b = x;//b不是x的别名,这段代码是将x的值赋给b。
return 0;
}
引用的使用场景
- 做参数 -- a、输出型参数 b、大对象传参,提高效率
- 做返回值(返回的对象出函数作用域不会销毁时才能使用)
#include <iostream>
using namespace std;
void Swap(int& r1, int& r2)
{
int tmp = r1;
r1 = r2;
r2 = tmp;
}
int main()
{
int a = 0;
int b = 2;
Swap(a, b);//a和b交换值
return 0;
}
常引用