类声明

来自cppreference.com
< cpp‎ | language


 
 
 
 

类(class)是用户定义类型,以 类说明符 定义,它在声明语法的 声明说明符序列 中出现。

目录

[编辑]语法

类说明符拥有下列语法:

类关键词属性 (可选)类头名类特性说明 (可选)基类子句 (可选)
{成员说明}
(1)
类关键词属性 (可选)基类子句 (可选)
{成员说明}
(2)
1) 具名类定义
2) 无名类定义
类关键词 - classstructunion 之一。除了默认成员访问和默认基类访问之外,关键词 structclass 是等同的。如果关键词是 union,那么声明引入一个联合体类型
属性 - (C++11 起) 任意数量的属性,可以包含 alignas 说明符
类头名 - 所定义的类的名字,可以有限定
类特性说明 - 以下说明符的列表,各说明符在每个序列中最多允许出现一次。
说明符 效果
final
(C++11 起)
指定类不能有派生
trivially_relocatable_if_eligible     
(C++26 起)
将类标记为有资格时可平凡重定位
replaceable_if_eligible     
(C++26 起)
将类标记为有资格时可重定位
基类子句 - 一个或多个基类以及各自所用的继承模型的列表(见派生类
成员说明 - 访问说明符、成员对象及成员函数的声明和定义的列表(见下文

[编辑]前置声明

以下形式的声明

类关键词属性标识符;

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

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;friendstd::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;}

[编辑]成员说明

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

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

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

class S {int d1;// 非静态数据成员int a[10]={1, 2};// 带初始化器的非静态数据成员(C++11)   staticconstint d2 =1;// 带初始化器的静态数据成员   virtualvoid 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;};
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){}// 构造函数定义   int operator()(std::size_t r, std::size_t c)const// 成员函数定义{return data[r * C + c];}   int& operator()(size_t r, size_t c)// 另一个成员函数定义{return data[r * C + c];}};
3)访问说明符public:protected:private:
class S {public: S();// 公开的构造函数 S(const S&);// 公开的复制构造函数virtual ~S();// 公开的虚析构函数private:int* ptr;// 私有的数据成员};
4)using 声明
class Base {protected:int d;};   class Derived :public Base {public:using Base::d;// 令 Base 的受保护成员 d 成为 Derived 的公开成员using Base::Base;// 继承基类的所有构造函数(C++11)};
5)static_assert 声明:
template<typename T>struct Foo { static_assert(std::is_floating_point<T>::value, "Foo<T>: T 必须是浮点数");};
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 声明
enumclass color { red, orange, yellow };   struct highlight {usingenum 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());// C++11 起   for(int n : v)std::cout<< n <<' ';std::cout<<'\n';}

输出:

3 2 1

[编辑]关键词

class, struct, union

[编辑]缺陷报告

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

缺陷报告 应用于 出版时的行为 正确行为
CWG 1693 C++98 成员声明不能为空 允许空声明
CWG 1930 C++98 声明说明符序列 包含存储类声明符或 cv 限定符时成员声明符列表 可以为空 类别不能为空
CWG 2890 C++98 不明确可以在哪里声明嵌套类的成员 使之明确

[编辑]参阅

结构体声明C 文档
close