C++
编译器支持
自由(freestanding)与宿主(hosted)
语言
标准库
标准库头文件
具名要求
特性测试宏 (C++20)
语言支持库
概念库 (C++20)
诊断库
内存管理库
元编程库 (C++11)
通用工具库
容器库
迭代器库
范围库 (C++20)
算法库
字符串库
文本处理库
数值库
日期和时间库
输入/输出库
文件系统库 (C++17)
并发支持库 (C++11)
执行控制库 (C++26)
技术规范
符号索引
外部库
[编辑] C++ 语言
通用主题
预处理器
注释
关键词
转义序列
流程控制
条件执行语句
if
switch
迭代语句(循环)
for
range-for (C++11)
while
do-while
跳转语句
continue - break
goto - return
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17*)
noexcept 说明符 (C++11)
异常
throw 表达式
try 块
catch 处理程序
命名空间
命名空间声明
命名空间别名
类型
基本类型
枚举类型
函数类型
类/结构体类型
联合类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
默认初始化
值初始化
零初始化
复制初始化
直接初始化
聚合初始化
列表初始化 (C++11)
常量初始化
引用初始化
表达式
值类别
求值顺序
运算符
运算符优先级
替代表示
字面量
布尔 - 整型 - 浮点型
字符 - 字符串 - nullptr (C++11)
用户定义 (C++11)
工具
属性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
类型转换
隐式转换
static_cast
const_cast
显式转换
dynamic_cast
reinterpret_cast
内存分配
new 表达式
delete 表达式
类
类声明
构造函数
this 指针
访问说明符
friend 说明符
类特有的函数属性
虚函数
override 说明符 (C++11)
final 说明符 (C++11)
explicit (C++11)
static
特殊成员函数
默认构造函数
复制构造函数
移动构造函数 (C++11)
复制赋值
移动赋值 (C++11)
析构函数
模板
类模板
函数模板
模板特化
参数包 (C++11)
杂项
内联汇编
C++ 历史
[编辑] 类
通用
概览
class/struct 类型
union 类型
注入类名
类属性说明符 (C++26)
成员
数据成员
静态成员
this 指针
嵌套类
成员模板
位域
using-声明
成员函数
成员访问说明符
构造函数和成员初始化列表
默认成员初始化器 (C++11)
friend 说明符
explicit 说明符
转换构造函数
特殊成员函数
默认构造函数
复制构造函数
移动构造函数 (C++11)
复制赋值运算符
移动赋值运算符 (C++11)
析构函数
继承
基类和派生类
空基类优化 (EBO)
虚成员函数
纯虚函数和抽象类
override 说明符 (C++11)
final 说明符 (C++11)
[编辑]
非静态成员函数是在类的成员声明中声明的函数,没有 static 或 friend 说明符(有关这些关键字的作用,请参见静态成员函数和友元声明)。
class S
{
int mf1(); // non-static member function declaration
void mf2() volatile, mf3() &&; // can have cv-qualifiers and/or a reference-qualifier
// the declaration above is equivalent to two separate declarations:
// void mf2() volatile;
// void mf3() &&;
int mf4() const { return data; } // can be defined inline
virtual void mf5() final; // can be virtual, can use final/override
S() : data(12) {} // constructors are member functions too
int data;
};
int S::mf1() { return 7; } // if not defined inline, has to be defined at namespace
构造函数、析构函数和转换函数使用特殊的语法进行声明。本页描述的规则可能不适用于这些函数。详情请参见各自的页面。
显式对象成员函数是没有显式对象参数的非静态成员函数。
(C++23 起)
隐式对象成员函数是没有显式对象参数的非静态成员函数(在 C++23 之前,这是唯一一种非静态成员函数,因此在文献中被称为“非静态成员函数”)。
目录
1 解释
1.1 带 cv 限定符的成员函数
1.2 带引用限定符的成员函数
1.3 虚函数和纯虚函数
1.4 显式对象成员函数
1.5 特殊成员函数
2 注意
3 示例
4 缺陷报告
5 另请参阅
[编辑] 说明
允许任何函数声明,并附加仅适用于非静态成员函数的语法元素:纯说明符、cv 限定符、引用限定符、final 和 override 说明符(C++11 起)以及成员初始化列表。
类 X 的非静态成员函数可以按以下方式调用:
1) 对于类型为 X 的对象,使用类成员访问运算符
2) 对于从 X 派生的类的对象
3) 直接从 X 的成员函数体内
4) 直接从从 X 派生的类的成员函数体内
在不是类型 X 或从 X 派生的类型的对象上调用类 X 的非静态成员函数会触发未定义行为。
在 X 的非静态成员函数体内,任何解析为 X 或 X 的基类的非类型非静态成员的id-expression e(例如标识符)都会转换为成员访问表达式 (*this).e(除非它已经是成员访问表达式的一部分)。这不会发生在模板定义上下文中,因此名称可能需要显式地加上 this-> 前缀才能成为依赖名称。
struct S
{
int n;
void f();
};
void S::f()
{
n = 1; // transformed to (*this).n = 1;
}
int main()
{
S s1, s2;
s1.f(); // changes s1.n
}
在 X 的非静态成员函数体内,任何解析为 X 或 X 的基类的静态成员、枚举器或嵌套类型的 unqualified-id 都会转换为相应的 qualified-id。
struct S
{
static int n;
void f();
};
void S::f()
{
n = 1; // transformed to S::n = 1;
}
int main()
{
S s1, s2;
s1.f(); // changes S::n
}
[编辑] 带 cv 限定符的成员函数
隐式对象成员函数可以声明为带cv 限定符序列(const、volatile,或 const 和 volatile 的组合),该序列出现在函数声明的参数列表之后。具有不同 cv 限定符序列(或没有序列)的函数具有不同的类型,因此可以相互重载。
在带 cv 限定符序列的函数体内,*this 是 cv 限定的,例如,在带 const 限定符的成员函数中,通常只能调用其他带 const 限定符的成员函数。如果应用了const_cast或通过不涉及this的访问路径,仍然可以调用不带 const 限定符的成员函数。
#include
struct Array
{
std::vector
Array(int sz) : data(sz) {}
// const member function
int operator[](int idx) const
{ // the this pointer has type const Array*
return data[idx]; // transformed to (*this).data[idx];
}
// non-const member function
int& operator[](int idx)
{ // the this pointer has type Array*
return data[idx]; // transformed to (*this).data[idx]
}
};
int main()
{
Array a(10);
a[1] = 1; // OK: the type of a[1] is int&
const Array ca(10);
ca[1] = 2; // Error: the type of ca[1] is int
}
带引用限定符的成员函数
隐式对象成员函数可以声明为不带引用限定符,带左值引用限定符(参数列表后的标记 &)或右值引用限定符(参数列表后的标记 &&)。在重载决议期间,带类 X 的 cv 限定符序列的隐式对象成员函数按以下方式处理:
不带引用限定符:隐式对象参数的类型是 cv 限定 X 的左值引用,并且还允许绑定右值隐含对象参数左值引用限定符:隐式对象参数的类型是 cv 限定 X 的左值引用右值引用限定符:隐式对象参数的类型是 cv 限定 X 的右值引用
#include
struct S
{
void f() & { std::cout << "lvalue\n"; }
void f() && { std::cout << "rvalue\n"; }
};
int main()
{
S s;
s.f(); // prints "lvalue"
std::move(s).f(); // prints "rvalue"
S().f(); // prints "rvalue"
}
注意:与 cv 限定不同,引用限定不会改变this指针的属性:在右值引用限定函数中,*this 仍然是一个左值表达式。
(C++11 起)
[编辑] 虚函数和纯虚函数
非静态成员函数可以声明为虚函数或纯虚函数。详情请参见虚函数和抽象类。
显式对象成员函数
对于未声明 cv 限定符或引用限定符的非静态非虚成员函数,其第一个参数(如果不是函数参数包)可以是显式对象参数(用前缀关键字 this 表示)
struct X
{
void foo(this X const& self, int i); // same as void foo(int i) const &;
// void foo(int i) const &; // Error: already declared
void bar(this X self, int i); // pass object by value: makes a copy of “*this”
};
对于成员函数模板,显式对象参数允许推导类型和值类别,此语言特性称为“推导 this”
struct X
{
template
void foo(this Self&&, int);
};
struct D : X {};
void ex(X& x, D& d)
{
x.foo(1); // Self = X&
move(x).foo(2); // Self = X
d.foo(3); // Self = D&
}
这使得可以消除 const 和非 const 成员函数的重复,请参阅数组下标运算符以获取示例。
在显式对象成员函数的函数体内,不能使用 this 指针:所有成员访问都必须通过第一个参数完成,就像在静态成员函数中一样
struct C
{
void bar();
void foo(this C c)
{
auto x = this; // error: no this
bar(); // error: no implicit this->
c.bar(); // ok
}
};
指向显式对象成员函数的指针是普通的函数指针,而不是成员指针
struct Y
{
int f(int, int) const&;
int g(this Y const&, int, int);
};
auto pf = &Y::f;
pf(y, 1, 2); // error: pointers to member functions are not callable
(y.*pf)(1, 2); // ok
std::invoke(pf, y, 1, 2); // ok
auto pg = &Y::g;
pg(y, 3, 4); // ok
(y.*pg)(3, 4); // error: “pg” is not a pointer to member function
std::invoke(pg, y, 3, 4); // ok
(C++23 起)
[编辑] 特殊成员函数
有些成员函数是特殊的:在某些情况下,即使用户没有定义它们,编译器也会定义它们。它们是:
默认构造函数
复制构造函数
移动构造函数
(C++11 起)
复制赋值运算符
移动赋值运算符
(C++11 起)
析构函数(C++20 前)预期析构函数(C++20 起)
特殊成员函数以及比较运算符(C++20 起)是唯一可以被默认的函数,即使用 = default 而不是函数体来定义(详见其页面)。
[编辑] 注意
功能测试宏
值
标准
特性
__cpp_ref_qualifiers
200710L
(C++11)
ref-限定符
__cpp_explicit_this_parameter
202110L
(C++23)
显式对象参数(推导 this)
[编辑] 示例
运行此代码
#include
#include
#include
#include
struct S
{
int data;
// simple converting constructor (declaration)
S(int val);
// simple explicit constructor (declaration)
explicit S(std::string str);
// const member function (definition)
virtual int getData() const { return data; }
};
// definition of the constructor
S::S(int val) : data(val)
{
std::cout << "ctor1 called, data = " << data << '\n';
}
// this constructor has a catch clause
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; // ctor's catch clause should always rethrow
}
struct D : S
{
int data2;
// constructor with a default argument
D(int v1, int v2 = 11) : S(v1), data2(v2) {}
// virtual member function
int getData() const override { return data * data2; }
// lvalue-only assignment operator
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: assignment to lvalue
// D(5) = d1; // ERROR: no suitable overload of operator=
}
输出
ctor1 called, data = 1
ctor2 called, data = 2
ctor2 failed, string was 'not a number'
2
ctor1 called, data = 3
[编辑] 缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告
应用于
发布时的行为
正确的行为
CWG 194
C++98
非静态成员函数是否可以与外围类同名
添加了显式命名限制
[编辑] 另请参见
类
非静态数据成员
静态数据成员