命名空间
变体
操作

类声明

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
 
 

类是用户定义类型,由 class-specifier 定义,它出现在声明语法的 decl-specifier-seq 中。

目录

[编辑] 语法

类说明符具有以下语法:

class-key attr (可选) class-head-name class-property-specs (可选) base-clause (可选)
{ member-specification }
(1)
class-key attr (可选) base-clause (可选)
{ member-specification }
(2)
1) 命名类定义
2) 匿名类定义
类键 - 其中之一是 classstructunion。关键字 classstruct 除了默认成员访问权限和默认基类访问权限外是相同的。如果它是 union,则此声明引入一个联合类型
属性 - (C++11 起) 任意数量的属性,可以包含 alignas 说明符
class-head-name - 正在定义的类的名称,可选地限定
class-property-specs - 以下说明符的列表,每个说明符在每个序列中最多允许出现一次。
说明符 效果
final
(C++11 起)
指定类不能被派生
trivially_relocatable_if_eligible     
(C++26 起)
如果符合条件,将类标记为可平凡重定位
replaceable_if_eligible     
(C++26 起)
如果符合条件,将类标记为可替换
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 (可选) decl-specifier-seq (可选) member-declarator-list (可选) ;
属性 - (自 C++11 起) 任意数量的属性
声明说明符序列 - 说明符序列。它仅在构造函数、析构函数和用户定义的类型转换函数的声明中可选。
member-declarator-list - 类似于init-declarator-list,但额外允许位域声明纯说明符,以及 virt-specifier(overridefinal(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;
    };
};
7) 别名声明
template<typename T>
struct identity
{
    using type = T;
};
(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 起)
9) using-enum-声明
enum class color { red, orange, yellow };
 
struct highlight
{
    using enum color;
};
(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()); // since C++11
 
    for (int n : v)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出

3 2 1

[编辑] 关键字

classstructunion

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 发布时的行为 正确的行为
CWG 1693 C++98 成员声明不能为空 允许空声明
CWG 1930 C++98 member-declarator-list 可能为空,当 decl-specifier-seq
包含存储类说明符或 cv 限定符时
列表不能为空
CWG 2890 C++98 嵌套类成员可以在何处声明尚不清楚 已明确

[编辑] 另请参阅

C 文档,关于 结构体声明