类声明
来自 cppreference.cn
类是用户定义的类型,由类说明符定义,类说明符出现在声明语法的 decl-specifier-seq 中。
目录 |
[编辑] 语法
类说明符具有以下语法
class-key attr (optional) class-head-name class-property-specs (optional) base-clause (optional){ member-specification } |
(1) | ||||||||
class-key attr (optional) base-clause (optional){ member-specification } |
(2) | ||||||||
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-key attr identifier ; |
|||||||||
声明一个类类型,该类型将在稍后在此作用域中定义。在定义出现之前,此类名称具有不完整类型。这允许类相互引用
class Vector; // forward declaration class Matrix { // ... friend Vector operator*(const Matrix&, const Vector&); }; class Vector { // ... friend Vector operator*(const Matrix&, const Vector&); };
并且如果特定的源文件仅使用指向该类的指针和引用,这使得减少 #include 依赖成为可能
// In MyStruct.h #include <iosfwd> // contains forward declaration of std::ostream struct MyStruct { int value; friend std::ostream& operator<<(std::ostream& os, const S& s); // definition provided in MyStruct.cpp file which uses #include <ostream> };
如果前向声明出现在局部作用域中,它会隐藏先前声明的类、变量、函数以及可能出现在封闭作用域中所有其他同名声明
struct s { int a; }; struct s; // does nothing (s already defined in this scope) void g() { struct s; // forward declaration of a new, local struct "s" // this hides global struct s until the end of this block s* p; // pointer to local struct s struct s { char* p; }; // definitions of the local struct s }
请注意,新的类名也可以通过作为另一个声明一部分出现的详述类型说明符引入,但前提是名称查找找不到先前声明的同名类。
class U; namespace ns { class Y f(class T p); // declares function ns::f and declares ns::T and ns::Y class U f(); // U refers to ::U // can use pointers and references to T and Y Y* p; T* q; }
[编辑] 成员规范
成员规范,或类定义的正文,是用大括号括起来的以下任意数量项的序列
1) 形式为成员声明
attr (optional) decl-specifier-seq (optional) member-declarator-list (optional) ; |
|||||||||
attr | - | (C++11 起) 任意数量的特性 |
decl-specifier-seq | - | 说明符序列。它仅在构造函数、析构函数和用户定义的类型转换函数的声明中是可选的 |
member-declarator-list | - | 类似于 init-declarator-list,但另外允许 位域声明、纯说明符,和 virt-specifier (override 或 final )(C++11 起),并且不允许 直接非列表初始化语法。 |
此声明可以声明 静态 和 非静态 数据成员 和 成员函数、成员 typedefs、成员 枚举,和 嵌套类。它也可以是 友元声明。
class S { int d1; // non-static data member int a[10] = {1, 2}; // non-static data member with initializer (C++11) static const int d2 = 1; // static data member with initializer virtual void f1(int) = 0; // pure virtual member function std::string d3, *d4, f2(int); // two data members and a member function enum { NORTH, SOUTH, EAST, WEST }; struct NestedS { std::string s; } d5, *d6; typedef NestedS value_type, *pointer_type; };
2) 函数定义,既声明又定义 成员函数 或 友元函数。成员函数定义后的分号是可选的。在类体内部定义的所有函数都自动为 内联,除非它们附加到 命名模块(C++20 起)。
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]; } };
3) 访问说明符
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 };
4) Using-声明
class Base { protected: int d; }; class Derived : public Base { public: using Base::d; // make Base's protected member d a public member of Derived using Base::Base; // inherit all bases' constructors (C++11) };
5)
static_assert
声明template<typename T> struct Foo { static_assert(std::is_floating_point<T>::value, "Foo<T>: T must be floating point"); };
6) 成员模板声明
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++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()); // since C++11 for (int n : v) std::cout << n << ' '; std::cout << '\n'; }
输出
3 2 1
[编辑] 关键字
[编辑] 缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
CWG 1693 | C++98 | 成员声明不能为空 | 允许空声明 |
CWG 1930 | C++98 | 当 decl-specifier-seq 时,member-declarator-list 可以为空 包含存储类说明符或 cv 限定符 |
列表不能为空 |
CWG 2890 | C++98 | 不清楚嵌套类的成员可以在哪里声明 | 已明确 |