C++ Keywords

const

  • 避免无意中修改数据。
  • 能够处理 const 和非 const 实参,否则只能接收非 const 数据。
  • 使函数能够正确生成并使用临时变量。

const 是 constant 的缩写,“恒定不变”的意思。被 const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多 C++ 程序设计书籍建议:“Use const whenever you need”。s

如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加 const 修饰,否则该参数将失去输出功能。const 只能修饰输入参数,如果输入参数采用“指针传递”,那么加 const 修饰可以防止意外地改动该指针,起到保护作用。

  • 函数返回值不可作为左值。在“指针传递”和“引用传递”时可以加const修饰,但是在“值传递”的情况下,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const修饰。

    1
    2
    3
    const int *fun(int *xxx) {}
    const int &fun(int &xxx) {}
    int fun(int xxx) {}
  • 形参在本函数内不能作为左值。

    1
    2
    3
    int *fun(const int *xxx) {}
    int &fun(const int &xxx) {}
    int fun(const int xxx) {}
  • 任何不会修改数据成员的函数都应该声明为 const 类型。此种写法表示本函数不会修改本对象中的成员变量。

    1
    int* fun(int* xxx) const {}

extern

  1. 单定义规则
    1. 变量只能被定义一次;
    2. 定义声明(defining declaration,简称定义);
    3. 引用声明(referencing declaration,简称声明);
  2. 一个变量多处使用,仅在其中一个文件中包含定义,在使用该变量的其它文件中使用该关键字声明

static

隐藏,保持内容持久,默认初始化为 0

  • 静态全局变量,全局生命周期,本文件可见。
  • 静态局部变量,全局生命周期,仅局部可见。
  • 静态函数,全局生命周期,全局可见。
  • 静态成员变量,全局生命周期,同类对象共享一份。
  • 静态成员函数,全局生命周期,同类对象共享一份。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int global = 200;               // 全局可见
static int current_file = 100; // 本文件可见
void fun(int a)
{
// code
static llama = 0; // 仅局部可见
}

class A {
public:
static void fun(); // 同类对象共享一份
private:
static int a; // 同类对象共享一份
}

inline

内联函数是函数,有类型检查,语法判断等,在编译时展开,嵌入代码中。
宏定义在预编译阶段展开,只是简单的文本替换。

virtual

虚函数是为了实现多态,析构函数是为了在对象不被使用之后释放它的资源。

那么把析构函数声明为 virtual 有什么作用呢?

直接的讲,C++ 中基类采用 virtual 虚析构函数是为了防止内存泄漏。

具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏。所以,为了防止这种情况的发生,基类的析构函数应采用 virtual 虚析构函数。对象在析构时,先调用派生类的析构函数后,再调用基类的析构函数,从而保证所有申请的资源都被释放。

explicit

  1. 指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。
  2. explicit 说明符可以与常量表达式一同使用。函数在且只会在该常量表达式求值为 true 时是显式的。(C++20 起)

decltype

推导表达式类型:

1
2
int i = 4;
decltype(i) a; // 推导结果为 int,故 a 的类型为 int

usingtypedef配合使用,用于定义类型:

1
2
3
using size_t = decltype(sizeof(0)); // sizeof(a) 的返回值为 size_t 类型
using ptrdiff_t = decltype((int *)0 - (int *)0);
using nullptr_t = decltype(nullptr);

重用匿名类型:

1
decltype(anon_s) as ; // 定义了一个上面匿名的结构体

泛型编程中结合 auto,用于追踪函数的返回值类型:

1
2
3
4
5
template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty)
{
return x*y;
}

template

函数模板,类模板。

特化与偏特化:模板特殊化和部分特殊化。

  1. 函数模板只有特化,没有偏特化;
  2. 模板、模板的特化和模板的偏特化都存在的情况下,编译器在编译阶段进行匹配,优先特殊的;
  3. 模板函数不能是虚函数;因为每个包含虚函数的类具有一个 virtual table,包含该类的所有虚函数的地址,因此 vtable 的大小是确定的。模板只有被使用时才会被实例化,将其声明为虚函数会使 vtable 的大小不确定。所以,成员函数模板不能为虚函数。

参考文献


C++ Keywords
https://laplac2.github.io/cpp/keywords/
作者
Laplace
发布于
2022年3月18日
许可协议