一、namespace: 解决命名冲突问题:
:: 表示域作用限定符, 左边没写默认全局域。
printf("%d\n", ::x); //打印全局变量x的值
域分为: 全局域,局部域,命名空间域, 类域。
命名空间域:
namespace bit1
{
int x = 0;
}
namespace bit2
{
int x = 1;
}
// 两个x都是全局变量。
作用域--结构体的使用:
struct bit1:: Node phead;
编译器的搜索原则:
- 当前局部域,
- 全局域
- 如果指定了作用域,直接去指定域搜索。
using namespace scj; //展开命名空间
// 意思是将scj的权限放开,变成公共的,可以去访问到的。
// std 是所有C++库的命名空间
// <iostream> 是流的头文件
二、cin和cout
cout<< "hello world" << endl; //流插入,自动识别类型。将<<流右边的数据输出到控制台上。
cin >> i >> ch; //流提取,从控制台提取数据到变量中。
三、缺省参数
-
全缺省
void func(int a = 10, int b =20, int c= 30);
-
半缺省 – 缺省值必须从右往左连续给
void func(int a, int b =20, int c= 30);//正确 void func(int a=10, int b, int c= 30);//错误
-
如果定义和声明分离,缺省值要写在声明处(不能在定义处同时出现),否则编译时会报错。
四、函数重载
- 函数名相同参数不同。
-
- 参数个数不同
- 参数类型不同
- 参数类型的顺序不同
- 原理是名字修饰,C代码在链接时,找函数名地址,替换。
- C++代码在链接时,找函数名(linux系统下):_Z4funcid
五、引用
int a = 10;
int &b = a; // b是a的别名,b就是a
-
1.引用做参数传递(a.输出型参数, b. 如果对象比较大,减少拷贝,提高效率)
-
void Swap(int& a, int& b);
-
2.引用做返回值(a.修改返回对象, b. 减少拷贝,提高效率)
-
引用必须初始化
-
引用定义后不能改变指向。
不能返回局部变量的引用。
// 运算符重载
int& operator[](int pos)
{
//...
}
六、指针和引用的区别
语法:
-
引用是别名, 不开空间(严格讲,底层要开空间),指针是地址,需要开空间来存储地址。
-
引用必须初始化, 指针可以不初始化。
-
引用不能改变指向,指针可以。
-
引用相对较安全,没有空引用,但会有空指针。容易出现野指针,但不容易出现野引用。
底层:
-
引用的底层是用指针实现的(其实是需要开空间的)
-
在汇编层面上,没有引用,都是指针。引用编译后也转换成指针。
宏替换
频繁调用一个函数100w次,需要建立100w个栈帧
c语言解决办法——使用宏函数
- 宏不是函数
- 不能有分号
- 用括号控制优先级(传递的变量a, b,可能是表达式)
- 核心点:宏是预处理阶段进行替换。
#define ADD(a, b) ((a) + (b))
宏的缺点:
-
语法复杂,坑多,不容易控制
-
代码可读性差,可维护性差,容易误用
-
在预处理阶段进行替换,不能调试
-
没有类型安全的检查。
C++ ——内联函数
C++ 替换宏
- 常量定义 换用const enum
- 短小函数定义换用内联函数inline
七、内联函数 inline
inline int Add(int a, int b)
{
return a+b;
}
使用内联,在编译的时候,不会建立栈帧,直接在调用处“展开”, 提高了效率。
在.h的头文件中既声明又定义函数
解决方案:
- 声明定义分离
- static 修饰函数, 会改变文件的连接属性, 使得该函数只能在当前文件可见。
底层,函数不会进入符号表。所以不会产生冲突。
- inline 和static类似。内联用于小函数。
特性
-
inline 是一种以时间换空间的做法, 在编译阶段,会用函数体替换函数调用。
-
inline适用于函数代码规模较小的情况下,函数体太大,编译器会直接忽略内联。
-
内联不建议声明和定义分离,分离会导致连接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
八、auto关键字(C++11)
定义:自动识别类型
打印数据的类型:
void (*pf1)(int, int) = func;
auto pf2 = func;
cout<< typeid(pf1).name() << endl;
cout<< typeid(pf2).name() << endl;
注意:
-
使用时必须初始化,和 const 使用一样,必须初始化。
-
auto相当于一个占位符,在编译阶段,编译器会将auto替换成变量实际的类型。
const int a; //ERROR const int a = 10; auto a; //ERROR auto a = 10;
-
auto不能作为函数的参数传递
// ERROR 编译器无法对a的实际类型推导 void test(auto a) { // ... }
-
auto不能直接用来声明数组
int a[] = {1,2,3}; // ERROR auto b[] = {4,5,6};
-
auto 经常与for, 和lambda 表达式配合使用
九、范围for的用法(C++11)
遍历/修改数组
for(auto& e : array) // 这里是引用,即数组里面数据的别名
{
e *= 2; // 取出数组的数据,并*2。
cout << e << " ";
}
- 第一部分:范围内用于迭代的对象: e
- 第二部分:被迭代的范围: array
void test(int(&arr)[3])
{
for (auto& e : arr)
{
e *= 2;
}
}
十、指针空置nullptr(C++11)
// sizeof(nullptr) 与 sizeof((void*)0) 所占字节相同
- nullptr 是一个关键词, 表示空指针。