static
static
修饰的内容,其作用域不变,生命周期与程序相同,且在整个程序执行过程中,仅会被初始化一次。
静态局部变量
- 在实际开发中,若使用静态局部变量可以替代全局变量,优先使用静态局部变量。
静态成员
- 把类的成员声明为静态后,则可以认为该成员独立于类,该成员仅在逻辑上属于该类。
- 静态成员使用
类名::静态成员
就能够访问,不需要创建对象。
const
const
修饰其左侧(若左侧为空则修饰右侧)内容,const
修饰谁,谁就不能变。
const
表示只读,表达常量的语义使用constexpr
。
const与指针
char const * str
(const char * str
):const
修饰类型,即类型的值不能改变,但指针的指向可以改变。char * const str
:const
修饰指针,即类型的值可以改变,但指针的指向不能改变(引用的本质)。
const与成员函数
- 在成员函数后添加
const
,则成员函数不能修改成员变量的值。 const
不能修饰构造函数与析构函数。
指针
- 请确保指针在使用前被正确初始化。
- 在实际开发中,尽可能避免使用裸指针。
void指针
void*
表示任意类型的指针。
- 只关心地址,不在乎指针指向的内容时可以使用void指针。
- void指针仅表示指针,不能解引用,需要转换为具体类型的指针。
- 不能直接对void指针做
delete
操作。
函数指针
一般形式:数据类型(*指针变量名)(参数列表);
。
- 使用函数指针可以实现对函数的回调。
指针与数组名
int main() {
int arr[5];
printf("%p\n%p\n", arr, &arr);
int *pointer = new int[5];
printf("%p\n%p\n", pointer, &pointer);
return 0;
}
上面这段代码描述了指针与函数名的差异。执行这段代码可以得到如下结果:
0x7ffed71574e0
0x7ffed71574e0
0x603000000010
0x7ffed7157520
在该例中,pointer
与&pointer
的值不相同,其原因是,pointer
是一个指针且指向数组的首地址,&pointer
是存储指针的地址。但此处arr
与&arr
的值却相同,这说明,数组名arr
不是指向数组首地址的指针。为了讨论arr
到底是什么,再来看下面一段代码。
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
printf("%p\n", arr + 1);
printf("%p\n", &arr[1]);
printf("%p\n", ((int*)(&arr + 1) - 1));
printf("%p\n", &arr[4]);
return 0;
}
执行这段代码可以得到如下结果:
0x7ffdf366d3c0
0x7ffdf366d3c0
0x7ffdf366d3c4
0x7ffdf366d3c4
0x7ffdf366d3d0
0x7ffdf366d3d0
在该例中,arr
相当于&arr[0]
,而arr + 1
就相当于&arr[1]
。值得注意的是,(&arr + 1)-1
的地址与&arr[4]
的地址相同。这说明,&arr
表示的是指向整块数组内存的指针,它的类型实际是行指针int(*)[5]
。
类
类的初始化能否使用memset?
- 当类中存在虚函数时,不能使用。虚函数通过虚函数表中的指针实现,
memset
会将虚函数表中的指针置空,使得后续的函数调用出现异常。 - 当类中存在其它类的对象时,不能使用。类中包含的对象会先于该类完成初始化,
memset
会将该对象清空。 - 在对象内部清空对象自身是不安全的,不要这么做。
友元
- 语法:
friend
。 - 类型:全局友元函数、友元类、友元成员函数。
- 友元不能被继承,友元关系是有向的。
多态
调用派生类中的非虚函数
- 语法:
派生类指针 = dynamic_cast<派生类类型 *>(基类指针);
。 - 检查虚函数表。如果转换成功,
dynamic_cast
返回对象的地址,如果失败,返回nullptr
。
模板
函数模板
- 语法:
template <typename T>
。 - 在调用函数时,可使用
<类型名>
指定模板类型。 - 虚函数和析构函数不能创建模板。
- 匹配条件一致的前提下,普通函数 > 具体化模板 > 常规模板。
- 分文件编写时,常规函数模板的定义和声明均要放在头文件中;具体化模板仅将声明放在头文件中,定义放在源文件中。
auto
和decltype()
均能实现自动类型推导,不清楚返回值时,返回值可以使用auto
。
类模板
- 语法:
template <class T>
。 - 类模板的成员函数只会在对象实例化后被创建。
C++11标准
左值与右值
- 左值:表达式结束后仍存在的持久化对象。
- 右值:表达式结束后就消失的临时对象。
- 能取地址的为左值,不能取地址的为右值。
- 右值引用(将右值转化为左值,给临时变量续命)语法:
数据类型&& 变量名 = 右值
。 - 模板中使用
T&&
可以同时接收两种引用。 - 套一层
std::forward<T>(参数)
可以实现完美转发。
lambda表达式
- 把函数名替换为
[]
捕获列表即可实现lambda表达式。 [&]
表示引用捕获,[=]
表示值捕获。- 值捕获时,相当于值被
const
修饰,不能对值进行修改。(可使用mutable
关键字进行修改)。