目录
命名空间
C语言中会有命名冲突,C++为了解决这个问题增加了namespace(命名空间)的用法。
在了解命名空间之前,我们先复习一下编译器的查找顺序:
但编译器不会主动查找命名空间域,需要我们展开使用。
代码示例:
#include<iostream>
using namespace std;
namespace bit
{
// 命名空间中可以定义变量/函数/类型
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
using namespace bit;
int main()
{
printf("%d\n", bit::a);
printf("%d\n", b);
}
IO流
IO流也被称为输入输出流。
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
// << 流插入 >> 流提取
using namespace std;
int main()
{
cout<<"Hello world!!!"<<endl;
return 0;
}
缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实 参则采用该形参的缺省值,否则使用指定的实参。
void Func(int a, int b = 20, int c = 30)
{
cout << "a= " << a << endl;
cout << "b= " << b << endl;
cout << "c= " << c << endl;
}
//全缺省
void Func1(int a = 10, int b = 20, int c = 30)
{
cout << "a= " << a << endl;
cout << "b= " << b << endl;
cout << "c= " << c << endl;
}
int main()
{
Func(1, 2, 3);
Func(1, 2);
Func(1);
Func1(1, 2, 3);
Func1(1, 2);
Func1(1);
Func1();
}
代码运行结果:
函数重载
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这 些同名函数的形参列表(参数个数或类型或类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
为什么C语言不支持重载而C++支持重载?
编译链接的过程:
- 预处理
- 编译
- 汇编
- 链接
- 链接时,C语言直接用函数名去查找,无法区分,所以不支持重载,而C++是以修饰后的函数名查找,所以支持重载。
引用
引用相当于别名。
引用特性:
- 引用在定义时必须初始化。
- 一个变量可以有多个引用,就相当于人有多个外号一样。
- 引用一旦引用一个实体,就不能引用其他实体。
void TestRef()
{
int a = 10;
// int& ra; // 该条语句编译时会出错
int& ra = a;
int& rra = a;
printf("%p %p %p\n", &a, &ra, &rra);
}
常引用
void TestConstRef()
{
const int a = 10;
//int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
// int& b = 10; // 该语句编译时会出错,b为常量
const int& b = 10;
double d = 12.34;
//int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
}
使用场景
- 做参数或者做返回值
//做参数
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
//做返回值
int& Count()
{
static int n = 0;
n++;
// ...
return n;
}
引用和指针的区别
在语法概念上,引用就是一个别名,和引用实体共用一块空间。
在底层实现上,是有空间的,因为引用是按指针方式来实现的。
内联函数的定义以及注意
inline int func(int x)
{
retrun x * x;
}
这个函数将被内联到调用该函数的地方,而不会创建新的栈帧和参数传递过程。
内联函数并不是在所有情况下都会内联,在某些情况下,编译器可能会选择不内联一个函数,例如函数体太大或者过于复杂。
此外内联函数也可能对程序的性能产生负面影响,因为他可能导致代码量增加,从而增加内存占和执行的时间。
auto关键字
自动类型推断
auto关键字使得编译器能够根据变量初始化表达式自动推断处变量的类型,例如
auto x = 5;
auto y = 3.14;
auto z = "hello";
这种用法减少了代码的冗长性,特别视在处理复杂类型时。
基于范围的for循环
for(范围声明 : 范围表达式)
{
循环语句
}
//范围声明:定义一个变量用于存储范围表达式中的元素,通常使用auto关键字进行类型推断。
//范围表达式:表示要遍历的序列,如数组、容器、字符串等。
优点
- 简洁性:相比传统的for循环,基于范围的for循环不需要显式定义迭代器或索引变量。
- 安全性:减少了因索引错误或迭代器操作错误导致的bug。
- 易读性:代码更加直观,易于理解。
注意事项
- 基于范围的for循环适用于数组、容器、字符串等支持范围访问的对象。
- 对于空容器或序列,循环体不会执行。
- 在遍历中修改容器大小,可能导致未定义行为。