0%

C++ 中的声明与定义关键字

记录 C++ 中一些常见的声明与定义的关键字作用

static 声明

static 修饰类成员时,表示成员仅属于类,不属于实例;

并且 static 修饰的类成员不能直接指定类内初始值,除非为 const;

而且必须在类外初始化,初始化时不能再次写 static

1
2
3
4
5
6
7
8
class A {
public:
// static int num = 0; // 报错
static const int size = 20; // 正确, 若类外再次初始化则重复定义
static int count; // 如果类外没有初始化, 则编译出错
};
// const int A::size = 20; // 不能重复定义, 类内初始值与类外初始化只能有一个
int A::count = 30; // 类外初始化

inline 定义 (声明)

inline 只是给编译器的处理建议,编译器可以自行选择, 如果函数中出现 switch, 循环,递归,或者有函数指针对该函数的调用, 编译器会忽略 inline 建议

inline 函数在哪里声明就在哪里实现

inline 函数的声明和实现应该放在头文件中, 应该在函数实现的地方加上 inline; 对于声明的地方是否加上 inline, 貌似并没有影响

virtual 声明

仅在函数声明时使用,函数定义时再加 virtual 会报错

当一个成员函数被声明为 virtual 之后, 其子类中相同签名的函数自动成为虚函数,即使子类没有显式写上 virtual, 不过为了阅读清晰,子类中也应该显式加上 virtual 声明

const 声明 + 定义

1
2
3
void test() const;
void test();

上面两个成员函数可以同时存在,const 对象调用只能调用 const 的成员函数, 而非 const 对象在两种函数都存在时调用不带 const 的版本, 如果只有 const 版本也可以调用不会报错

所以函数后加 const 与不加 const 是两个不同函数, 声明和定义时都要表述清楚

final 声明

C++ 11 新增关键字,用于阻止成员函数被重写,或者阻止类继承;

只能声明时使用,定义处使用报错

用在虚函数之后,表示在之后的子类中,不能重写该函数

用在类名之后,表示该类不可以被继承

1
2
class A final {}; // 表示A类不能被继承
class B: public A {}; // 编译报错
1
2
3
4
5
6
7
8
9
class A : public Base{
public:
virtual void show() override final {} // 从父类继承而来, 但不允许子类重写
};
class B : public A {
public:
virtual void show() {} // 编译报错, 不允许重写
virtual void special() final {} // 不允许子类重写
};

override 声明

C++ 11 新增关键字,用于子类中显式说明一个函数是重写父类函数, 编译器可以检查错误

只能声明时使用,定义处使用报错

1
2
3
4
5
6
7
8
9
class A {
public:
virtual void show() = 0;
};
class B : public A {
public:
// 如果没有override, 这段错误代码会编译通过
virtual void sh0w() override; // 报错, 没有sh0w函数可以重写, 让编译器检查错误
};

default 声明

C++ 11 新增,表示类的特殊函数使用默认实现

特殊函数: 默认构造函数、复制 / 移动构造函数、复制 / 移动赋值运算符和析构函数

默认构造函数是没有参数的

1
2
3
4
5
6
7
8
9
class A {
public:
A() = default; // 默认构造
A(const A& a) = default; // 复制构造
A(A&& a) = default; // 移动构造
virtual ~A() = default; // 析构函数
A& operator=(const A& a) = default; // 复制赋值 (默认实现为浅拷贝)
A& operator=(A&& a) = default; // 移动赋值 (浅拷贝)
};

delete 声明

C++ 11 新增 表示删除默认提供的特殊函数,禁止默认操作

1
2
3
4
5
6
7
8
9
class A {
public:
A(const A& a) = delete; // 禁止复制构造
};
A a;
// A b(a); // 报错, 禁止
// A b = a; // 报错, 禁止
A b;
b = a; // 调用了默认赋值函数, 没有delete, 允许; 浅复制

explicit 声明

仅声明,函数外写会报错

表示构造函数必须显式调用,而不能隐式转换

C++ 中的 explicit 关键字只能用于修饰只有一个参数的类构造函数 (或者除了第一个参数外, 其它参数有默认值的构造) C++11 后已经可以修饰任意参数的构造函数, 它的作用是表明该构造函数是显示的,而非隐式的, 跟它相对应的另一个关键字是 implicit, 意思是隐藏的,类构造函数默认情况下即声明为 implicit (隐式)

1
2
3
4
5
6
7
class A {
public:
A(int i) {}
A(int i, int j) {}
};
A a = 30; // 正确, 隐式调用构造函数, 自动隐式转换
A b = {1, 2}; // 正确, 复制列表初始化
1
2
3
4
5
6
7
8
class A {
public:
explicit A(int i) {} // 显式构造函数, 不能隐式调用
explicit A(int i, int j) {}
}
A a(30); // 显式调用, 正确
// A a = 30; // 隐式调用, 错误
// A a = {2, 3}; // 隐式调用, 错误

详情: C++ 中的 explicit 关键字