类(class)与结构体(struct)是用户定义类型,以 类说明符 定义,它在声明语法的 声明说明符序列 中出现。类说明符拥有下列语法:

类关键词 attr 类头名 基类子句 { 成员说明 }
类关键词 - classstruct 之一。除了默认成员访问和默认基类访问之外,两个关键词是等同的。
attr(C++11) - 可选的任何数量属性序列,可包含 alignas 指定符
类头名 - 所定义的类的名字。可选地有限定,可选地后随关键词 final。名字可以省略,该情况下类是无名的(注意无名类不能为 final
基类子句 - 一或多个父类以及各自所用的继承模型的可选列表(见派生类
成员说明 - 访问说明符、成员对象及成员函数的声明和定义的列表(见下文)

语法综述见。若 类关键词 为 union,则声明引入一个联合体类型

前置声明

下列形式的声明

类关键词 attr 标识符 ;

声明一个将稍后在此作用域定义的类类型。直到定义出现前,此类名具有不完整类型。这允许类之间彼此引用:

  1. class Vector; // 前置声明
  2. class Matrix {
  3. // ...
  4. friend Vector operator*(const Matrix&, const Vector&);
  5. };
  6. class Vector {
  7. // ...
  8. friend Vector operator*(const Matrix&, const Vector&);
  9. };

而且若特定的源文件仅使用到该类的指针和引用,这亦使得减少 #include 依赖成为可能:

  1. // 在 MyStruct.h 中
  2. #include <iosfwd> // 含有 std::ostream 的前置声明
  3. struct MyStruct {
  4. int value;
  5. friend std::ostream& operator<<(std::ostream& os, const S& s);
  6. // 其定义在 MyStruct.cpp 文件中提供,该文件使用 #include <ostream>
  7. };

若前置声明出现于局部作用域,则它隐藏其外围作用域中可出现的先前声明的相同名字的类、变量、函数,以及所有其他声明:

  1. struct s { int a; };
  2. struct s; // 不做任何事(s 已定义于此作用域)
  3. void g() {
  4. struct s; // 新的局部类“s”的前置声明
  5. // 它隐藏全局的 struct s 直至此块结尾
  6. s* p; // 指向局部 struct s 的指针
  7. struct s { char* p; }; // 局部 struct s 的定义
  8. }

注意,通过作为其他声明一部分的详述类型说明符,也可以引入新的类名,但仅当名字查找无法找到先前声明的有此名的类时才行。

  1. class U;
  2. namespace ns{
  3. class Y f(class T p); // 声明函数 ns::f 并声明 ns::T 与 ns::Y
  4. class U f(); // U 指代 ::U
  5. Y* p; T* q; // 可使用到 T 和 Y 的指针及引用
  6. }

成员说明

成员说明,或类定义的,是花括号环绕的任何数量下列各项的序列:

1) 具有下列形式的成员声明

attr(可选) 声明说明符序列(可选) 成员声明符列表(可选) ;
attr(C++11) - 可选的任何数量属性序列
声明说明符序列 - 说明符的序列。它只在构造函数,析构函数,以及用户定义转换函数中可选。
成员声明符列表 -初始化声明符列表相同,但额外允许位域定义纯说明符和虚说明符( overridefinal) (C++11 起),并且不允许直接非列表初始化语法

这种声明可以声明静态及非静态的数据成员成员函数、成员 typedef、成员枚举以及嵌套类。它亦可为友元声明

  1. class S {
  2. int d1; // 非静态数据成员
  3. int a[10] = {1,2}; // 带初始化器的非静态数据成员 (C++11)
  4. static const int d2 = 1; // 带初始化器的静态数据成员
  5. virtual void f1(int) = 0; // 纯虚成员函数
  6. std::string d3, *d4, f2(int); // 两个数据成员和一个成员函数
  7. enum {NORTH, SOUTH, EAST, WEST};
  8. struct NestedS {
  9. std::string s;
  10. } d5, *d6;
  11. typedef NestedS value_type, *pointer_type;
  12. };

2) 函数定义,同时声明并定义成员函数或者友元函数。成员函数定义之后的分号是可选的。所有定义于类体之内的函数自动为内联

  1. class M {
  2. std::size_t C;
  3. std::vector<int> data;
  4. public:
  5. M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // 构造函数定义
  6. int operator()(size_t r, size_t c) const { // 成员函数定义
  7. return data[r*C+c];
  8. }
  9. int& operator()(size_t r, size_t c) { // 另一个成员函数定义
  10. return data[r*C+c];
  11. }
  12. };

3) 访问说明符 public:protected:private:

  1. class S {
  2. public:
  3. S(); // 公开构造函数
  4. S(const S&); // 公开复制构造函数
  5. virtual ~S(); // 公开虚析构函数
  6. private:
  7. int* ptr; // 私有数据成员
  8. };

4) using 声明

  1. class Base {
  2. protected:
  3. int d;
  4. };
  5. class Derived : public Base {
  6. public:
  7. using Base::d; // 令 Base 的受保护成员 d 为 Derived 的公开成员
  8. using Base::Base; // 继承父类的全部构造函数 (C++11)
  9. };

5) static_assert 声明

  1. template<typename T>
  2. struct Foo {
  3. static_assert(std::is_floating_point<T>::value, "Foo<T>: T must be floating point");
  4. };

6) 成员模板声明

  1. struct S {
  2. template<typename T>
  3. void f(T&& n);
  4.  
  5. template<class CharT>
  6. struct NestedS {
  7. std::basic_string<CharT> s;
  8. };
  9. };

7) 别名声明

  1. template <typename T>
  2. struct identity
  3. {
  4. using type = T;
  5. };

8) 成员类模板的推导指引



  1. 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++14 起)局部类不能拥有成员模板
  • 局部类不能拥有友元模板
  • 局部类不能在类定义内定义友元函数
  • 函数(包括成员函数)内的局部类可以访问其外围函数能访问的相同名字。


- 局部类不能用作模板实参
(C++11 前)

运行此代码

  1. #include <vector>
  2. #include <algorithm>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::vector<int> v{1,2,3};
  8. struct Local {
  9. bool operator()(int n, int m) {
  10. return n > m;
  11. }
  12. };
  13. std::sort(v.begin(), v.end(), Local()); // C++11 起
  14. for(int n: v) std::cout << n << ' ';
  15. }

输出:

  1. 3 2 1