第04章 C++语言专题(一.01)概述

声明:仅为个人学习总结,还请批判性查看,如有不同观点,欢迎交流。

摘要

本文主要整理了 C++ 标准发展历程、C++ 保留字、C++ 运算符相关内容。


1、C++ 的发展

名称 C++ 来自 C 语言中的递增运算符 ++,以表明 C++ 是 C 的扩充版本。
本节内容主要引用自:

  1. [美] K. N. 金(K. N. King)著,吕秀锋,黄倩译.C语言程序设计:现代方法(第2版·修订版).人民邮电出版社.2021:19.
  2. 罗剑锋著.Boost程序库完全开发指南:深入C++“准”标准库(第5版).电子工业出版社.2020:801.

关于 Boost:1998年,Beman G.Dawes(C++ 标准委员会成员之一)发起倡议并建立了 Boost 社区,其目的是向 C++ 程序员提供免费的、经同行审查的、可移植的、高质量的 C++ 源程序库。Boost 强调程序库要与 C++ 标准库很好地共同工作,建立在“既有的实践”之上并提供参考实现,因此 Boost 库能够适合最后的标准化。自创立以来,C++ 标准库中约有三分之二来自 Boost 库。

1.1 C/C++ 的发展历程

年份C 语言发展历程C++ 语言发展历程
1969年Ken Thompson 在 BCPL 语言的基础上设计了一种小型的 B 语言,用于开发 UNIX 系统
1972年Dennis Ritchie 将其开发的 B 语言的升级版 NB 语言(New B)改名为 C 语言
1978年Brian Kernighan 和 Dennis Ritchie 合作编写第一本 C 语言书《The C Programming Language》出版(Classic C)
1979年Bjarne Stroustrup 基于 C 语言实现了 C++ 的前身:C with Classes
1983年正式命名为 C++
1989年在美国国家标准学会(ANSI)的推动下,美国通过本国的 C 语言标准 ANSI 标准 X3.159-1989(C89)
1990年国际标准化组织(ISO)通过上述标准,将其作为 ISO/IEC 9899:1990 国际标准(C90,与 C89 一致)C++ 标准委员会成立,C++ 标准化进程开始
1994年委员会完成草案登记
1998年发布 C++98,第一个 C++ 正式标准
1999年通过 ISO/IEC 9899:1999 标准,包含了一些重要的改变(C99)
2003年发布 C++03,对 C++98 仅有很少的技术性修订(没有改变语言特性)
2011年通过 ISO/IEC 9899:2011 标准,变化没有从 C89 到 C99 那么显著(C11)发布 C++11,是 C++ 标准的重大升级,增加大量新特性
2014年发布 C++14,小幅度扩充了 C++11 标准
2017年发布 C++17,对 C++14 再做修订,主要增强了标准库
2018年通过 ISO/IEC 9899:2018 标准,仅限于技术修正和澄清(C18)
2020年发布 C++20,增加了概念、模块、协程等重磅特性,堪比 C++11

1.2 C++98(重点学习)

C++98 标准是 C++ 的第一个国际标准,与早期的 C++ 相比,它有着重大的进步,包括:

  • 新的语言特性,如模板、名字空间、布尔类型、类型转换关键字等;
  • 异常处理体系,包括标准的 exception 和若干派生子类,以及异常规范;
  • 输入输出流操作,这是对早期流库的重构标准化;
  • 数值处理,在内建的整数、实数之外增加了复数和数值数组;
  • C89 程序库,涵盖了 C 语言 1989 年的标准所定义的所有内容;
  • 国际化支持,如 wchar_tlocale 等用于国际化软件开发的特性;
  • 字符串类,如标准的 stringwstring,使程序员可以更方便地处理字符串;
  • 最重要的组成部分——标准库(STL),包括泛型容器、泛型算法、迭代器、函数对象、内存分配器等诸多组件。

C++98 标准是 C++ 历史上的一个重要里程碑,编译器厂商、语言用户(程序员)终于拥有了可遵循的统一语言规范,程序员可以更好地写出不依赖于编译器特定扩展的“方言”的实现,极大地便利了跨平台开发。

1.3 C++11

C++98 标准并没有解决所有问题,比如它遗漏了 hash_table 这样重要的数据结构。新的 C++11 标准较 C++98 提供了众多“与时俱进”的新特性,更容易学习和使用,对程序员更加“友好”,也更加安全。例如:

  • 新的 nullptr 关键字,取代了容易引起错误的 NULL 宏或 0;
  • 新的 noexcept 关键字,取代了原有的异常规范;
  • 新的 constexpr 关键字,编译期常量表达式,有利于模板元编程;
  • 新的 auto/decltype 关键字,可以自动推导类型声明;
  • 新的 defaultdelete 用法,可以明确地控制函数的实现(默认或禁用);
  • 新的 for 循环语法,可以更容易地遍历容器,代码更简洁;
  • 原始(raw)字符串,用形如 R"(...)" 的方式来书写字符串,不必用 “\” 转义;
  • 右值引用、完美转发和转移(move)语义,可以更高效地返回对象;
  • 可变参数模板,可以更容易地编写泛型代码,不必使用晦涩的预处理;
  • 语言级别的 lambda 表达式,可以非常容易地编写匿名函数对象;
  • 废弃了异常规范、auto_ptr 和关键字 exportregister
  • 极大地增强了标准库,添加了许多新的组件,其中有数个基于 Boost,如 arraybindfunctionrandomshared_ptrthreadtuple 等。

1.4 C++14

虽然 C++11 经历了十多年的时间才发布,但仍有很多工作尚未完成。标准委员会表示将会以三年一个版本的速度持续更新 C++ 标准,使 C++ 能够紧跟时代发展的步伐。
C++14 虽然没有 C++11 那么多的新增特性,但很多小的扩展也相当实用。例如:

  • 模板变量,如 template<typename T> T val
  • 属性 [[deprecated]],用于声明废弃的对象、函数或类;
  • 新的 decltype(auto) 类型推导语法;
  • 泛型 lambda 表达式,可以用 auto 声明入口参数;
  • 使用 auto 关键字自动推导函数返回类型;
  • 使用单引号 ' 作为数字分位符;
  • “0b/0B” 格式的二进制字面值;
  • 时、分、秒(h/min/s)等预定义字面值;
  • 用于创建 unique_ptr 的工厂函数 make_unique

1.5 C++17

C++17 侧重于对 C++14 进行补充和完善,增强了标准库,也改善了部分语言特性,但总体而言,C++17 仍然不能算有大的进步,值得注意的新特性如下:

  • 检查是否已经包含了头文件的宏 __has_include
  • 简化的嵌套名字空间定义,如 namespace a::b::c
  • std::invoke(),统一的函数调用方式;
  • std::apply(),使用 tuple 发起函数调用,基于 std::invoke()
  • 并行算法,可以传入参数 std::execution::par 显式要求并行处理;
  • 无效值包装器 optional,基于 boost.optional
  • 字符串引用 string_view,基于 boost.string_ref
  • 支持 UTF-8 编码的字符串,如 u8"string"
  • 增强的联合体 variant,基于 boost.variant
  • 操纵文件系统的 filesystem,几乎与 boost.filesystem 相同。

1.6 C++20(暂不学习)

C++20 是继 C++11 之后的另一个重大升级,之前被移出的部分特性和库在经过更充分的讨论后终于再次加入标准,其中,某些库已经被广大用户期待和呼吁了多年,具体如下:

  • range :类似 boost.range,可以用 | 串联起多个算法;
  • span :类似 string_view,是序列容器的子视图;
  • module :取代 include 语句,更“现代化”的模块机制;
  • coroutine :语言级别的协程功能;
  • concurrency :语言级别的并发支持;
  • concept :重新设计、精简后的概念检查库;
  • networking :标准内置的网络开发库。

2、C++ 保留字

C++ 保留了一些单词供语言本身以及标准库使用,这些保留字不能被程序员用作标识符(变量、函数、宏和其他实体的名字等)。保留字分为三类:关键字、操作符替代标记和 C++ 库保留名称。

2.1 C++ 关键字

关键字(keyword),是程序语言预先定义的一些具有特殊意义的名称。

下表根据类别对关键字进行分组(TODO: 可能有误)整理,内容参考 C语言入门专题(上) => 1.2 关键字cppreference.com => C++ 关键词

序号类别关键字C/C++版本说明
1基本数据类型intC90基本整数类型。如果没有长度修饰符,那么它保证拥有至少 16 位宽度。然而在 32/64 位系统上,几乎专门保证它拥有至少 32 位宽度。
2charC90能在目标系统上最有效地处理的字符表示的类型符号性取决于编译器和目标平台:ARM 和 PowerPC 的默认设置通常没有符号,而 x86 与 x64 的默认设置通常有符号。
3floatC90单精度浮点类型,如果支持就会匹配 IEEE-754 binary32 格式。
4doubleC90双精度浮点类型,如果支持就会匹配 IEEE-754 binary64 格式。
5voidC90值为空集的类型,是无法变为完整的不完整类型,不允许存在 void 类型的对象,允许存在 指向 void 的指针和返回 void 类型的函数。
无形参函数的形参列表。
6boolC++98布尔类型,足以存放两个值 true 或 false 之一的类型sizeof(bool) 的值由实现定义,而且不一定是 1。
7字面值常量falseC++98布尔字面值常量。
8trueC++98布尔字面值常量。
9nullptrC++11指针字面量,是 std::nullptr_t 类型的纯右值,存在从 nullptr 到任何指针类型及任何成员指针类型的隐式转换。
10基本类型变式shortC90整数类型大小修饰符,目标类型将为空间优化,且将有至少 16 位的宽度。
11longC90整数类型大小修饰符,目标类型将有至少 32 位的宽度。
long double - 扩展精度浮点类型。
C++11long long - 目标类型将有至少 64 位的宽度。
12unsignedC90整数类型符号性修饰符,目标类型将拥有无符号表示。
unsigned char - 无符号字符类型修饰符。也会用来审查对象表示(无修饰内存)。
13signedC90整数类型符号性修饰符,目标类型将拥有有符号表示(默认符号性)。
signed char - 有符号字符表示的类型。
14char8_tC++20UTF-8 字符表示的类型,要求大到足以表示任何 UTF-8 编码单元(8 位)。它与 unsigned char 具有相同的大小、符号性和对齐(从而与 char 和 signed char 具有相同的大小和对齐),但它是独立的类型。
15char16_tC++11UTF-16 字符表示的类型,要求大到足以表示任何 UTF-16 编码单元(16 位)。它与 std::uint_least16_t 具有相同的大小、符号性和对齐,但它是独立的类型。
16char32_tC++11UTF-32 字符表示的类型,要求大到足以表示任何 UTF-32 编码单元(32 位)。它与 std::uint_least32_t 具有相同的大小、符号性和对齐,但它是独立的类型。
17wchar_tC++98宽字符表示的类型。与整数类型之一具有相同的大小、符号性和对齐,但它是独立的类型。实践中,它在 Linux 与许多其他非 Windows 系统上为 32 位并保有 UTF-32,但在 Windows 上为 16 位并保有 UTF-16 编码单元。标准曾要求 wchar_t 足够大以保有任何受支持的字符码位。然而该要求无法在 Windows 上满足,从而它被视为缺陷并被移除。
18复合数据类型structC90结构体声明,把多种信息都放在一个单元内。
C++98如果作用域中存在某个函数或变量,其名称与某个非联合类类型的名称相同,则可以将 struct 加在名称前面以消除歧义,从而产生一个详细的类型说明符。
C++11有作用域枚举类型 enum struct 的声明。
19unionC90共用体声明,成员共享相同的存储空间,同一时间内只能有一个成员。
C++98如果作用域中存在某个函数或变量,其名称与某个联合体类型的名称相同,则可以将 union 加在名称前面以消除歧义,从而产生一个详细的类型说明符。
20enumC90枚举声明,声明符号名称来表示整型常量,提高程序的可读性。
C++11有作用域枚举 enum class 或 enum struct。
21classC++98声明类。
在模板声明中,class 可用于引入类型模板形参与模板模板形参。
若作用域中存在具有与某个类类型的名字相同的名字的函数或变量,则 class 可附于类名之前以消歧义,这产生一个详述类型说明符。
C++11声明有作用域枚举类型 enum class。
22templateC++98模板声明;。
在模板定义中,template 可用于将某个待决名声明为模板。
23conceptC++20声明具名类型要求,概念(concept)的目的是塑造语义分类而非语法上的限制。
24存储类别说明符typedefC90为某一类型自定义名称【与内存存储无关,根据语法归类,不能在声明中使用多个存储类别说明符(_Thread_local 和 static/extern 例外)】。
25存储类别说明符autoC90指定为自动变量,由编译器自动分配及释放。通常在栈上分配。只能用于块作用域的变量声明。主要是为了明确表达要使用与外部变量同名的局部变量的意图。
C++11auto 占位符类型说明符(对于变量,指定要从它的初始化器自动推导出它的类型)。
带尾随返回类型的函数声明(尾随返回类型只能在最外层函数声明符中使用)。
C++17对于函数,指定要从它的 return 语句推导出它的返回类型。
对于非类型模板形参,指定要从实参推导出它的类型。
结构化绑定声明,绑定指定名称到初始化器的子对象或元素。
C++20简写函数模板,当函数声明或函数模板声明的形参列表中出现占位符类型(auto 或 概念 auto)时,该声明会声明一个函数模板,并且为每个占位符向模板形参列表追加一个虚设的模板形参。
C++23显式转型到纯右值副本。
26registerC90自动存储期说明符,可以用来提示优化器将此变量的值存储到 CPU 寄存器。
C++17不使用并保留该关键词。
27staticC90定义具有静态存储期且仅初始化一次的块作用域变量。
C++98声明具有静态存储期和内部链接的命名空间成员。
声明不绑定到特定实例的类成员。
28externC90具有外部连接的静态存储期说明符。
C++98提供以不同程序语言编写的模块间的链接。
C++11显式模板实例化声明(extern 模板)跳过隐式的实例化步骤。
29exportC++98用于标记模板定义为被导出,这允许在其他翻译单元中声明但不定义同一模板。
C++11不使用并保留该关键词。
C++20标记一个声明、一组声明或另一模块为当前模块所导出。
30thread_localC/C++11对象具有线程存储期,在该线程运行期间一直存在,且在线程开始时被初始化,为线程私有,不能在多线程之间共享。
31类型限定符asmC++98内联汇编块的声明,提供在C++程序中嵌入汇编语言源代码的能力(和具体的实现相关)。
32类型限定符constC90const 类型限定符,不能改变初始化以后的 const 变量。
C++98const 限定的成员函数。
33constevalC++20声明说明符,指定函数是即时函数,也就是说,对该函数的每次调用都必须产生一个编译时常量。
显式指定函数调用运算符为立即函数的 lambda-声明符。
C++23consteval if 语句。
34constexprC++11声明说明符,指定变量或函数的值可以在常量表达式中出现。
C++17在 constexpr if 语句中,条件 的值必须是可经转换常量表达式转换到 bool 的表达式。
35constinitC++20声明说明符,断言变量拥有静态初始化,即零初始化与常量初始化,否则程序是病态的。
36volatileC90类型限定符,指定被声明对象或被命名类型的易变性(volatility)。
C++98volatile 限定的非静态成员函数,在函数体内,*this 有同样的 cv 限定。
37mutableC++98可变类型说明符。
C++11从按复制捕获的形参中移除 const 限定性的 lambda 声明符 。
38requiresC++20对模板形参指定一个用于评估要求的常量表达式 。
在模板声明中,指定一个关联的约束。
39typenameC++98在模板的声明或定义中,typename 可用于声明某个 待决的有限定名 是类型。
C++17在模板声明的模板形参列表中,typename 可用作 class 的代替品,以声明类型模板形参和模板模板形参。
C++20用于类型要求的“要求”中。
40访问类别说明符friendC++98友元声明,在类体内出现,向一个函数或另一个类授予对包含友元声明的类的私有及受保护成员的访问权。
41privateC++98私有访问说明符。
42protectedC++98受保护访问说明符。
43publicC++98公有访问说明符。
44对齐指定符alignasC/C++11对齐说明符,指定类型或对象的对齐要求。
45运算符alignofC/C++11对齐运算符,查询类型的对齐要求。
46sizeofC90以字节为单位返回运算对象的大小,运算对象可以是具体的数据对象(如,变量名)或类型。
C++11sizeof… 运算符,查询形参包中的元素数量。
47typeidC++98查询类型的信息,用于必须知晓多态对象的动态类型的场合,以及静态类型鉴别。
48decltypeC++11说明符,在编译时期检查一个实体的声明类型或一个表达式的类型和值类别。
C++17对于非类型模板形参,指定要从实参推导出它的类型。
49operatorC++98重载运算符的声明,为用户定义类型的操作数定制 C++ 运算符。
50const_castC++98类型转换表达式声明,在有不同 cv 限定的类型间转换。
51dynamic_castC++98类型转换表达式声明,沿继承层级向上、向下及侧向,安全地转换到其他类的指针和引用。
52reinterpret_castC++98类型转换表达式声明,通过重新解释底层位模式在类型间转换。
53static_castC++98类型转换表达式声明,用隐式和用户定义转换的组合在类型间转换。
54newC++98new 表达式,创建并初始化拥有动态存储期的对象。
分配函数,作为运算符式的函数名。
55deleteC++98delete 表达式,销毁先前由 new 表达式分配的对象,并释放获得的内存区域。
解分配函数,作为运算符式的函数名。
C++11弃置函数,如果使用 “= delete ;” 取代函数体,那么该函数被定义为弃置的(deleted)。任何弃置函数的使用都是无法通过编译的。
56控制循环forC90for 循环结构,入口条件循环,在执行循环之前判断是否需要执行循环。
C++11用于基于范围的 for 循环的声明。
57whileC90while 循环结构,入口条件循环,在执行循环之前判断是否需要执行循环。
58doC90do 循环结构,do while 语句是一种出口条件循环,在执行完循环体后根据测试条件决定是否再次执行循环。
59控制分支ifC90使用 if 语句进行分支选择。
C++17constexpr if 语句,用于需要基于编译时条件执行的代码。
C++23consteval if 语句,用于 if 是否在明显常量求值语境下求值执行的代码。
60elseC90if 条件语句为假分支。
61switchC90多分支选择语句。
62caseC90switch 语句分支标记,程序控制根据 expression 的值跳转至相应的 case 标签处。
63defaultC90如果没有匹配的 case 标签,控制则转至 default 语句(如果有的话)。
C++11在函数声明后面添加 “=default ;”,显式地指示编译器生成某个类成员函数的默认定义。
64控制跳转continueC90导致外围 for、范围 for、while 或 do-while 循环体的剩余部分被跳过。
65breakC90使程序控制跳出当前循环或 switch 语句的剩余部分,并继续执行跟在循环或 switch 后面的语句。
66gotoC90使程序控制跳转至相应标签语句。标签语句可以出现在goto的前面或后面。
67returnC90从函数中返回值(如果需要),终止函数并把控制返回给主调函数的下一条语句。
68函数说明符inlineC/C++98说明符,在用于函数的 声明说明符序列 时,将函数声明为一个 内联(inline)函数。
C++11inline namespace 定义。
C++17说明符,在用于具有静态存储期的变量(静态类成员或命名空间作用域变量)的 声明说明符序列 时,将变量声明为内联变量。
69explicitC++98显式说明符。
70virtualC++98虚函数说明符,指定非静态成员函数为虚函数并支持动态调用派发。
虚基类说明符,对于每个指定为 virtual 的不同基类,最终派生对象(以 virtual 继承)中仅含有该类型的一个基类子对象。
71断言声明static_assertC/C++11static_assert 声明,进行编译时断言检查。
72异常处理throwC++98throw 表达式,对错误条件发信号。
动态异常说明,列出函数可能直接或间接抛出的异常(C++17 前)。
73tryC++98try 块,将一或多个异常处理块(catch 子句)与复合语句关联。
74catchC++98用于 try-catch 块,catch 子句的形参决定何种类型的异常导致进入此 catch 子句 。
75noexceptC++11运算符,进行编译时检查,如果表达式不会抛出任何异常则返回 true。
说明符,指定函数是否抛出异常。
76协程控制co_awaitC++20co_await 表达式,用于暂停协程执行,直到恢复(协程是能暂停执行以在之后恢复的函数)。
77co_yieldC++20co_yield 表达式,用于暂停协程执行并返回一个值。
78co_returnC++20co_return 语句,用于完成协程执行并返回一个值:。
79命名空间namespaceC++98命名空间声明。
命名空间别名声明(常用作长的或嵌套过深的命名空间的简便使用方式)。
"using 指令:using namespace 命名空间名 ;
80usingC++98对命名空间的 using 指令,对命名空间成员的 using 声明。
对类成员的 using 声明。
C++11声明类型别名(指代先前定义的类型的名字)与别名模板(指代一族类型的名字)。
81其它thisC++98This 指针,是一个纯右值表达式,它的值是隐式对象形参(调用非静态成员函数的对象)的地址。
C++23值是隐式对象形参(调用隐式对象成员函数的对象)的地址。
标记显式对象形参。

2.2 C++ 替代标记

除关键字外,C++ 还保留了一些运算符的“字母替代表示”,它们被称为替代标记(alternative token)。

序号替代标记运算符
1and&&
2and_eq&=
3bitand&
4bitor`
5compl~
6not!
7not_eq!=
8or`
9or_eq`
10xor^
11xor_eq^=

2.3 C++ 库保留名称

C++ 也为标准库保留了一些名字,包括:

  • 连续出现两个下划线的标识符;
  • 以下划线紧连大写字母开头的标识符;
  • 定义在函数体外的以下划线开头的标识符。

TODO: VS2015 可以使用上述保留名字,原因待查。

3、C++ 运算符

C++ 运算符,及其优先级和结合性:

优先级名称符号结合性
0*作用域解析::/
1分组(表达式)/
1函数调用()从左往右
1*值构造,即 type(expr)()
1数组取下标[]
1间接成员运算符->
1直接成员运算符.
1*专用的类型转换const_cast
1*专用的类型转换dynamic_cast
1*专用的类型转换reinterpret_cast
1*专用的类型转换static_cast
1*类型标识typeid
1自增(后缀)++
1自减(后缀)--
2自增(前缀)++从右往左
2自减(前缀)--
2取地址&
2解引用*
2一元正号+
2一元负号-
2按位取反~
2逻辑非!
2计算所需空间sizeof
2*动态分配内存new
2*动态分配数组new[]
2*动态释放内存delete
2*动态释放数组delete[]
2类型转换,即 (type)expr()从右往左
3*成员解除引用.*从左往右
3*间接成员解除引用->*
4乘法类运算符(3)* / %从左往右
5加法类运算符(2)+ -从左往右
6移位(2)<< >>从左往右
7关系(4)< > <= >=从左往右
8判等(2)== !=从左往右
9按位与 AND&从左往右
10按位异或 XOR^从左往右
11按位或 OR``
12逻辑与 AND&&从左往右
13逻辑或 OR`
14条件?:从右往左
15赋值(11)= *= /= %= += -= <<= >>= &= ^= `=`
16*引发异常throw从左往右
17逗号,从左往右

注:与 C语言入门专题(上)=> 4、运算符 比较,C++ 特有的运算符通过在优先级后面加 * 标识。

4、C++ 程序示例

// iostream 是 C++ 标准的“输入/输出库”,其中包含了相关的整套 class,用以支持对终端和文件的输入与输出
#include <iostream>
// string 类定义隐藏了字符串的数组性质,可以像处理普通变量那样处理字符串
#include <string>
// 暴露命名空间中的名称(标准库所提供的所有事物都被封装在命名空间 std 内)
using namespace std;

int main()
{
  // 通过“声明语句(declaration statement)”定义一个 string class 类型的对象,用以储存数据
  string user_name;

  // 通过 output 运算符(<<)将数据定向到已定义好的 cout 对象,也就是将信息写到用户的终端中
  cout << "Please enter your first name: ";

  // 通过 input 运算符(>>)将输入内容定向到已定义好的 cin 对象,也就是读取用户在终端上的输入内容
  cin >> user_name;

  cout << '\n' << "Hello, " << user_name << " ... and goodbye! " << endl;

  return 0;
}

参考

  1. [美] Stanley B.Lippman著.Essential C++ 中文版.电子工业出版社.2013.
  2. [美] Stanley B.Lippman著.C++ Primer 中文版(第5版).电子工业出版社.2013.
  3. [美] Stephen Prata著.C++ Primer Plus(第6版)中文版.人民邮电出版社.2012.

宁静以致远,感谢 Vico 老师。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值