C++ 参考手册
- C++11
- C++14
- C++17
- C++20
- C++ 编译器支持情况表
- 独立与宿主实现
- C++ 语言
- 变量模板(C++14 起)
- 整数字面量
- 聚合初始化
- 比较运算符
- 默认比较(C++20 起)
- 转义序列
- for 循环
- while 循环
- 用户定义转换
- SFINAE
- 主函数
- ASCII 码表
- 标识符
- 类型
- 内存模型
- 对象
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 类
- 运算符重载
- 模板
- 异常
- 事务性内存
- 占位符类型说明符 (C++11 起)
- decltype 说明符
- 函数声明
- final 说明符 (C++11 起)
- override 说明符(C++11 起)
- 引用声明
- 移动构造函数
- 移动赋值运算符
- 枚举声明
- constexpr 说明符(C++11 起)
- 列表初始化 (C++11 起)
- 构造函数与成员初始化器列表
- using 声明
- nullptr,指针字面量
- 基础类型
- 类型别名,别名模版 (C++11 起)
- 形参包
- 联合体声明
- 字符串字面量
- 用户定义字面量 (C++11 起)
- 属性说明符序列(C++11 起)
- Lambda 表达式 (C++11 起)
- noexcept 说明符 (C++11 起)
- noexcept 运算符 (C++11 起)
- alignof 运算符(C++11 起)
- alignas 说明符 (C++11 起)
- 存储类说明符
- 基于范围的 for 循环 (C++11 起)
- static_assert 声明
- 隐式转换
- 代用运算符表示
- 自增/自减运算符
- 折叠表达式(C++17 起)
- 类模板实参推导(C++17 起)
- 模板形参与模板实参
- if 语句
- inline 说明符
- 结构化绑定声明 (C++17 起)
- switch 语句
- 字符字面量
- 命名空间
- 求值顺序
- 复制消除
- consteval 说明符 (C++20 起)
- constinit 说明符 (C++20 起)
- 协程 (C++20)
- 模块 (C++20 起)
- 约束与概念 (C++20 起)
- new 表达式
- do-while 循环
- continue 语句
- break 语句
- goto 语句
- return 语句
- 动态异常说明
- throw 表达式
- try 块
- 命名空间别名
- 类声明
- cv(const 与 volatile)类型限定符
- 默认初始化
- 值初始化(C++03 起)
- 零初始化
- 复制初始化
- 直接初始化
- 常量初始化
- 引用初始化
- 值类别
- C++ 运算符优先级
- 布尔字面量
- 浮点字面量
- typedef 说明符
- 显式类型转换
- static_cast 转换
- dynamic_cast 转换
- const_cast 转换
- reinterpret_cast 转换
- delete 表达式
- 构造函数与成员初始化器列表
- this 指针
- 访问说明符
- 友元声明
- virtual 函数说明符
- explicit 说明符
- 静态成员
- 默认构造函数
- 复制构造函数
- 复制赋值运算符
- 析构函数
- 类模板
- 函数模板
- 显式(全)模板特化
- 汇编声明
- C++ 的历史
- 作用域
- 生存期
- 定义与单一定义规则(ODR)
- 名字查找
- 有限定的名字查找
- 无限定的名字查找
- 如同规则
- 未定义行为
- 翻译阶段
- 常量表达式
- 赋值运算符
- 算术运算符
- 逻辑运算符
- 成员访问运算符
- 其他运算符
- sizeof 运算符
- typeid 运算符
- 指针声明
- 数组声明
- 语言链接
- 详述类型说明符
- 默认实参
- 变长实参
- 实参依赖查找
- 重载决议
- 重载函数的地址
- 注入类名
- 非静态数据成员
- 非静态成员函数
- 嵌套类
- 派生类
- 空基类优化
- 抽象类
- 位域
- 转换构造函数
- 成员模板
- 模板实参推导
- 部分模板特化
- sizeof... 运算符
- 待决名
- 函数 try 块
- 扩充命名空间 std
- 字母缩写
- RAII
- 三/五/零之法则
- PImpl
- 零开销原则
- 类型
- 隐式转换
- 注释
- C++ 关键词
- 预处理器
- C++ 标准库头文件
- 具名要求
- 功能特性测试 (C++20)
- 工具库
- 类型支持(基本类型、RTTI、类型特性)
- 概念库 (C++20)
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 容器库
- 迭代器库
- 范围库 (C++20)
- 算法库
- 数值库
- 输入/输出库
- 文件系统库
- 本地化库
- 正则表达式库
- 原子操作库
- 线程支持库
- 实验性 C++ 特性
- 有用的资源
- 索引
- std 符号索引
- 协程支持 (C++20)
- C++ 关键词
非静态成员函数
非静态成员函数是声明于类的成员说明中,不带 static
或 friend
说明符的函数。
class S { int mf1(); // 非静态成员函数声明 void mf2() volatile, mf3() &&; // 可为 cv 限定或引用限定 int mf4() const { return data; } // 可内联定义 virtual void mf5() final; // 可为虚函数,可使用 final/override S() : data(12) {} // 构造函数亦是成员函数 int data; }; int S::mf1() { return 7; } // 若不内联定义,则必须定义于命名空间
允许任何函数声明,并带有仅可用于非静态成员函数的额外语法元素:final
与 override
说明符,纯说明符,cv 限定符,引用限定符,以及成员初始化列表。
可以用以下方式调用类 X 的非静态成员函数
在任何其他类型的对象上调用类 X 的成员函数导致未定义行为。
在 X 的非静态成员函数的体内,任何解析为 X 或 X 的某个基类的非类型非静态成员的标识表达式 E(例如一个标识符),均被变换为成员访问表达式 (*this).E 除非它已是成员访问表达式的一部分)。模板定义语境中不会发生这种变换,因而可能必须明确地对某个名字前附 this->,以使其成为待决的名字。
struct S { int n; void f(); }; void S::f() { n = 1; // 变换为 (*this).n = 1; } int main() { S s1, s2; s1.f(); // 更改 s1.n }
在 X 的非静态成员函数体内,任何解析到 X 或 X 的某个基类的静态成员、枚举项或嵌套类型的无限定标识,均被变换为对应的有限定标识。
struct S { static int n; void f(); }; void S::f() { n = 1; // 变换为 S::n = 1; } int main() { S s1, s2; s1.f(); // 更改 S::n }
const、volatile 及引用限定的成员函数
非静态成员函数可声明为带有 const、volatile 或 const volatile 限定符(这些限定符出现在函数声明中的形参列表之后)。cv 限定性不同的函数具有不同类型,从而可以相互重载。
在 cv 限定的函数体内,this
指针被 cv 限定,例如 const 成员函数中,只能正常地调用其他 const 成员函数。(如果应用了 const_cast
,或通过不涉及 this
的访问路径,则仍可调用非 const 成员函数。)
#include <vector> struct Array { std::vector<int> data; Array(int sz) : data(sz) {} // const 成员函数 int operator[](int idx) const { // this 具有类型 const Array* return data[idx]; // 变换为 (*this).data[idx]; } // non-const member function int& operator[](int idx) { // this 具有类型 Array* return data[idx]; // 变换为 (*this).data[idx] } }; int main() { Array a(10); a[1] = 1; // OK:a[1] 的类型是 int& const Array ca(10); ca[1] = 2; // 错误:ca[1] 的类型是 int }
非静态成员函数可声明为无引用限定符,带有左值引用限定符(函数名后的
注意:不同于 cv 限定性,引用限定性不改变 |
(C++11 起) |
虚函数和纯虚函数
特殊成员函数
构造函数和析构函数是非静态成员函数,在其声明中使用特殊的语法(细节见其相应页面)。
一些成员函数是特殊的:在某些环境下,即使用户不定义编译器也会定义它们。它们是:
(C++11 起) |
(C++11 起) |
特殊成员函数以及比较运算符 (C++20 起)是仅有能被预置的函数,即使用 = default 替代函数体进行定义(细节见其相应页面)
示例
#include <iostream> #include <string> #include <utility> #include <exception> struct S { int data; // 简单的转换构造函数(声明) S(int val); // 简单的显式构造函数(声明) explicit S(std::string str); // const 成员函数(定义) virtual int getData() const { return data; } }; // 构造函数的定义 S::S(int val) : data(val) { std::cout << "ctor1 called, data = " << data << '\n'; } // 此构造函数拥有 catch 子句 S::S(std::string str) try : data(std::stoi(str)) { std::cout << "ctor2 called, data = " << data << '\n'; } catch(const std::exception&) { std::cout << "ctor2 failed, string was '" << str << "'\n"; throw; // 构造函数的 catch 子句应该始终再抛出异常 } struct D : S { int data2; // 带默认实参的构造函数 D(int v1, int v2 = 11) : S(v1), data2(v2) {} // 虚成员函数 int getData() const override { return data*data2; } // 左值限定的赋值运算符 D& operator=(D other) & { std::swap(other.data, data); std::swap(other.data2, data2); return *this; } }; int main() { D d1 = 1; S s2("2"); try { S s3("not a number"); } catch(const std::exception&) {} std::cout << s2.getData() << '\n'; D d2(3, 4); d2 = d1; // OK :赋值给左值 // D(5) = d1; // 错误:无适合的 operator= 重载 }
输出:
ctor1 called, data = 1 ctor2 called, data = 2 ctor2 failed, string was 'not a number' 2 ctor1 called, data = 3