Class declaration
类是由类说明符定义的用户定义类型,它出现在 声明 语法的 decl-specifier-seq 中。
目录 |
语法
类说明符具有以下语法:
类关键字
属性
(可选)
类头名称
类属性说明
(可选)
基句
(可选)
{
成员声明
}
|
(1) | ||||||||
类关键字
属性
(可选)
基句
(可选)
{
成员声明
}
|
(2) | ||||||||
| class-key | - | class 、 struct 和 union 三者之一。 class 与 struct 关键字仅在默认 成员访问权限 和默认 基类访问权限 方面存在差异。若使用 union ,则声明引入一个 联合体类型 。 | ||||||||
| attr | - |
(C++11 起)
任意数量的
属性
,可包含
alignas
说明符
|
||||||||
| class-head-name | - | 正在定义的类名,可选择进行 限定修饰 | ||||||||
| class-property-specs | - |
以下说明符的列表,每个说明符在序列中最多出现一次。
|
||||||||
| base-clause | - | 一个或多个基类及其继承模式的列表(参见 派生类 ) | ||||||||
| member-specification | - | 访问说明符、成员对象及成员函数声明与定义的列表( 参见下文 ) |
前置声明
以下形式的声明
类关键字
属性
标识符
;
|
|||||||||
声明一个稍后将在当前作用域中定义的类类型。在定义出现之前,该类名具有 不完整类型 。这允许类之间相互引用:
class Vector; // 前向声明 class Matrix { // ... friend Vector operator*(const Matrix&, const Vector&); }; class Vector { // ... friend Vector operator*(const Matrix&, const Vector&); };
如果某个源文件仅使用类的指针和引用,这将有助于减少 #include 依赖:
// 在 MyStruct.h 文件中 #include <iosfwd> // 包含 std::ostream 的前置声明 struct MyStruct { int value; friend std::ostream& operator<<(std::ostream& os, const S& s); // 定义在 MyStruct.cpp 文件中提供,该文件使用 #include <ostream> };
如果在局部作用域中出现前向声明,它会 隐藏 先前声明的类、变量、函数以及可能出现在外围作用域中的所有同名声明:
struct s { int a; }; struct s; // 无实际作用(s 已在当前作用域内定义) void g() { struct s; // 新局部结构体 s 的前向声明 // 这将隐藏全局结构体 s 直至当前块结束 s* p; // 指向局部结构体 s 的指针 struct s { char* p; }; // 局部结构体 s 的定义 }
请注意,新的类名也可能通过 详细类型说明符 引入,该说明符作为其他声明的一部分出现,但前提是 名称查找 无法找到先前声明的同名类。
class U; namespace ns { class Y f(class T p); // 声明函数 ns::f 并声明 ns::T 和 ns::Y class U f(); // U 指向 ::U // 可以使用指向 T 和 Y 的指针及引用 Y* p; T* q; }
成员声明
成员规范,即类定义的 主体 ,是由花括号括起的任意数量以下元素的序列:
attr
(可选)
decl-specifier-seq
(可选)
member-declarator-list
(可选)
;
|
|||||||||
| attr | - | (C++11 起) 任意数量的 属性 |
| decl-specifier-seq | - | 说明符 序列。仅在构造函数、析构函数和用户定义类型 转换函数 的声明中可选 |
| member-declarator-list | - |
类似于
初始化声明符列表
,但额外允许
位域声明
、
纯说明符
和虚函数说明符(
override
或
final
)
(C++11 起)
,且不允许
直接非列表初始化语法
|
此声明可以声明 静态 和非静态 数据成员 与 成员函数 、成员 类型别名 、成员 枚举 以及 嵌套类 。也可以是 友元声明 。
class S { int d1; // 非静态数据成员 int a[10] = {1, 2}; // 带初始化器的非静态数据成员 (C++11) static const int d2 = 1; // 带初始化器的静态数据成员 virtual void f1(int) = 0; // 纯虚成员函数 std::string d3, *d4, f2(int); // 两个数据成员和一个成员函数 enum { NORTH, SOUTH, EAST, WEST }; struct NestedS { std::string s; } d5, *d6; typedef NestedS value_type, *pointer_type; };
class M { std::size_t C; std::vector<int> data; public: M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // constructor definition int operator()(std::size_t r, std::size_t c) const // member function definition { return data[r * C + c]; } int& operator()(std::size_t r, std::size_t c) // another member function definition { return data[r * C + c]; } };
public:
,
protected:
, 和
private:
class S { public: S(); // public constructor S(const S&); // public copy constructor virtual ~S(); // public virtual destructor private: int* ptr; // private data member };
class Base { protected: int d; }; class Derived : public Base { public: using Base::d; // 将Base的受保护成员d设为Derived的公开成员 using Base::Base; // 继承所有基类的构造函数(C++11) };
static_assert
声明:
template<typename T> struct Foo { static_assert(std::is_floating_point<T>::value, "Foo<T>: T must be floating point"); };
struct S { template<typename T> void f(T&& n); template<class CharT> struct NestedS { std::basic_string<CharT> s; }; };
| (C++11 起) |
|
8)
成员类模板的
推导指引
:
struct S { template<class CharT> struct NestedS { std::basic_string<CharT> s; }; template<class CharT> NestedS(std::basic_string<CharT>) -> NestedS<CharT>; }; |
(C++17 起) |
| (自 C++20 起) |
局部类
类声明可以出现在函数体内,这种情况下它定义的是 局部类 。此类名称仅存在于函数作用域内,在外部无法访问。
- 局部类的成员只能在该类的定义中声明,但 嵌套类 成员还可以在该类最近的封闭 块作用域 中声明。
- 局部类内部嵌套的类同样是局部类。
- 局部类不能拥有静态数据成员。
- 局部类的成员函数没有链接属性。
- 局部类的成员函数必须在类体内完整定义。
- 局部类 (除 闭包类型 外) (C++14 起) 不能拥有成员模板。
- 局部类不能拥有 友元模板 。
- 局部类不能在类定义内定义 友元函数 。
- 函数(包括成员函数)内部的局部类可以访问与外围函数相同的名称。
|
(C++11 前) |
#include <algorithm> #include <iostream> #include <vector> int main() { std::vector<int> v{1, 2, 3}; struct Local { bool operator()(int n, int m) { return n > m; } }; std::sort(v.begin(), v.end(), Local()); // 自 C++11 起 for (int n : v) std::cout << n << ' '; std::cout << '\n'; }
输出:
3 2 1
关键词
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用标准 | 发布时行为 | 正确行为 |
|---|---|---|---|
| CWG 1693 | C++98 | 成员声明不能为空 | 允许空声明 |
| CWG 1930 | C++98 |
当
decl-specifier-seq
包含存储类说明符或cv限定符时,
member-declarator-list 可为空 |
该列表必须非空 |
| CWG 2890 | C++98 | 未明确嵌套类的成员可在何处声明 | 已明确说明 |
参见
|
C 文档
关于
结构体声明
|