STL之迭代器(Iterator)

STL---迭代器 阅读详情

目录


一、迭代器是什么?

1.1、本质

迭代器本质上是什么?当然,任何一种特定的迭代器都是某种类型的对象。不过,迭代器的类型非常多,毕竟每个迭代器都是与某个特定容器类型相关联的。它需要保存一些必要的信息,以便我们对容器执行某些特定的任务。因此,有多少种容器就有多少种迭代器,有多少种特殊要求就有多少种迭代器。

1.2、作用

STL的中心思想在于:将数据容器和算法分开,彼此独立设计,最后再以一帖胶着剂将它们撮合在一起。这个胶着剂就是迭代器。反过来,也可以说迭代器机制是为了最小化算法与所操作的数据结构间的依赖性:
在这里插入图片描述

1.3、迭代器与指针

迭代器是一种行为类似指针的对象,迭代器提供了间接访问的操作(如解引用操作*)和移动到新元素的操作(例如,++操作移动到下一个元素)。

迭代器并未实现为指针,它们是所谓的“泛型指针”。你甚至可以反过来思考它,由于迭代器是泛型的,这意味着指针是迭代器,在任何可以使用迭代器的地方,都可以使用指针。1

从实现的角度来看,迭代器是一种将operator*、operator->、operator++、operator-- 等指针相关操作予以重载的class template。

1.4、迭代器类别

标准库提供了5种迭代器(5个迭代器类别,Iterator category):

  • 输入迭代器(input Iterator):只用于顺序访问,只读。
  • 输出迭代器(output Iterator):顺序访问,只写。
  • 前向迭代器(forward iterator):只能在序列中沿一个方向移动,可以读写元素。
  • 双向迭代器(bidirectional Iterator):可以正向/反向移动,可读写元素。
  • 随机访问迭代器(random-access iterator):提供在常量时间内访问序列中任意元素的能力。

1.4.1、5种迭代器的关系

在这里插入图片描述
图中直线与箭头代表的并非C++的继承关系,而是所谓concept(概念)与refinement(强化)的关系。

二、Traits编程技法

2.1、引子

在算法中运用迭代器时,很可能会用到其相应类型。什么是相应类型?迭代器所指之物的类型便是其一。假设算法中有必要声明一个变量,以“迭代器所指对象的类型”为类型,如何是好?毕竟C++只支持sizeof(),并未支持typeof()!即便动用RTTI性质中的typeid(),获得的也只是类型名称,不能拿来做变量声明之用。

解决办法是:利用function template的参数推导机制。如:
在这里插入图片描述
以func()为对外接口,却把实际操作全部置于func_impl()之中。由于func_impl()是一个function template,一旦被调用,编译器会自动进行template参数推导,于是导出类型T,顺利解决了问题。

迭代器相应类型不只是"迭代器所指对象的类型"一种而已。根据经验,最常用的相应类型有五种:value_type、differencee_type、pointer、reference、Iterator_category,并非任何情况下任何一种都可以利用上述的template参数推导机制来取得。

2.2、Traits编程技法

上述参数类型推导技巧虽然可以用于value_type,却非全面可用:万一value_type必须用于函数的返回值,就束手无策了,毕竟函数的"template参数推导机制"推而导之的只是参数,无法推导函数的返回值类型。2

声明内嵌类型似乎是个好主意,像这样:
在这里插入图片描述
看起来不错,但是有个隐晦的陷阱:并不是所有迭代器都是class type。原生指针就不是。如果不是class type,就无法为它定义内嵌类型。但STL绝对必须接受原生指针作为一种迭代器,所以上面这样还不够。

为了让上述一般化概念针对特定情况(例如针对原生指针)做特殊化处理,可以使用模板部分特例化(template partial specialization)。

先前的问题是,原生指针并非class,因此无法为它们定义内嵌类型。现在,我们可以针对“迭代器之template参数为指针”者,设计特例化版本的迭代器。

下面这个class template专门用来“萃取”迭代器的特性,而value_type正是迭代器的特性之一:
在这里插入图片描述
这个所谓的traits,其意义是,如果 I 定义有自己的value_type,那么通过这个traits的作用,萃取出来的value_type就是 I::value_type。换句话说,如果 I 定义有自己的value_type,先前那个func()可以改写成这样:
在这里插入图片描述
除了多一层间接性,带来的好处是什么呢?好处是traits可以拥有特例化版本。现在,我们令iterator_traits拥有一个partial specialization如下:
在这里插入图片描述
于是,原生指针int*虽然不是一种class type,亦可以通过traits取其value_type。这就解决了先前的问题。

针对“指向常量对象的指针(pointer to const)”,设计的特例化版本如下:
在这里插入图片描述
traits扮演的“特性萃取机”,萃取各个迭代器的特性,这里所谓的迭代器特性,指的是迭代器的相应类型。当然,若要这个“特性萃取机”traits能够有效运作,每一个迭代器必须遵循约定,自行以内嵌类型定义的方式定义出相应类型。
在这里插入图片描述

三、迭代器相应类型

本节只介绍iterator_category,其他迭代器相应类型的具体实现,请参看下一节四、具体迭代器示例。

共有5种迭代器,详情请参考1.4、迭代器类别。设计算法时,如果可能,我们应尽量针对某种迭代器提供一个明确定义,并针对更强化的某种迭代器提供另一种定义,这样才能在不同情况下提供最大效率。

为了区别不同的迭代器,traits中定义了5个类,代表5种迭代器类型:
文件位置:libstdc++ -v3\include\bits\stl_iterator_base_types.h

  /**
   *  @defgroup iterator_tags Iterator Tags
   *  These are empty types, used to distinguish different iterators.  The
   *  distinction is not made by what they contain, but simply by what they
   *  are.  Different underlying algorithms can then be used based on the
   *  different operations supported by different iterator types.
  */
  //@{ 
  ///  Marking input iterators.
  struct input_iterator_tag { };

  ///  Marking output iterators.
  struct output_iterator_tag { };

  /// Forward iterators support a superset of input iterator operations.
  struct forward_iterator_tag : public input_iterator_tag { };

  /// Bidirectional iterators support a superset of forward iterator
  /// operations.
  struct bidirectional_iterator_tag : public forward_iterator_tag { };

  /// Random-access iterators support a superset of bidirectional
  /// iterator operations.
  struct random_access_iterator_tag : public bidirectional_iterator_tag { };
  //@}

四、具体迭代器示例

4.1、__iterator_traits

文件位置:libstdc++ -v3\include\bits\stl_iterator_base_types.h

#if __cplusplus >= 201103L
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 2408. SFINAE-friendly common_type/iterator_traits is missing in C++14
  template<typename _Iterator, typename = __void_t<>>
    struct __iterator_traits { };

  template<typename _Iterator>
    struct __iterator_traits<_Iterator,
			     __void_t<typename _Iterator::iterator_category,
				      typename _Iterator::value_type,
				      typename _Iterator::difference_type,
				      typename _Iterator::pointer,
				      typename _Iterator::reference>>
    {
      typedef typename _Iterator::iterator_category iterator_category;
      typedef typename _Iterator::value_type        value_type;
      typedef typename _Iterator::difference_type   difference_type;
      typedef typename _Iterator::pointer           pointer;
      typedef typename _Iterator::reference         reference;
    };

  template<typename _Iterator>
    struct iterator_traits
    : public __iterator_traits<_Iterator> { };
#else
  template<typename _Iterator>
    struct iterator_traits
    {
      typedef typename _Iterator::iterator_category iterator_category;
      typedef typename _Iterator::value_type        value_type;
      typedef typename _Iterator::difference_type   difference_type;
      typedef typename _Iterator::pointer           pointer;
      typedef typename _Iterator::reference         reference;
    };
#endif

  /// Partial specialization for pointer types.
  template<typename _Tp>
    struct iterator_traits<_Tp*>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef _Tp*                        pointer;
      typedef _Tp&                        reference;
    };

  /// Partial specialization for const pointer types.
  template<typename _Tp>
    struct iterator_traits<const _Tp*>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef _Tp                         value_type;
      typedef ptrdiff_t                   difference_type;
      typedef const _Tp*                  pointer;
      typedef const _Tp&                  reference;
    };

4.2、iterator

为了符合规范,任何迭代器都应该提供5个内嵌相应类型,以利于traits萃取,否则便是自别于整个STL架构,可能无法与其他STL组件顺利搭配。因此,STL提供了一个iterator class,如果每个新设计的迭代器都继承自它,就可以保证符合STL所需规范:

 /**
   *  @brief  Common %iterator class.
   *
   *  This class does nothing but define nested typedefs.  %Iterator classes
   *  can inherit from this class to save some work.  The typedefs are then
   *  used in specializations and overloading.
   *
   *  In particular, there are no default implementations of requirements
   *  such as @c operator++ and the like.  (How could there be?)
  */
  template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
           typename _Pointer = _Tp*, typename _Reference = _Tp&>
    struct iterator
    {
      /// One of the @link iterator_tags tag types@endlink.
      typedef _Category  iterator_category;
      /// The type "pointed to" by the iterator.
      typedef _Tp        value_type;
      /// Distance between iterators is represented as this type.
      typedef _Distance  difference_type;
      /// This type represents a pointer-to-value_type.
      typedef _Pointer   pointer;
      /// This type represents a reference-to-value_type.
      typedef _Reference reference;
    };

五、迭代器、容器和算法

设计适当的相应类型是迭代器的责任,设计适当的迭代器则容器的责任。只有容器本身,才知道该设计出怎样的迭代器来遍历自己,并执行迭代器该有的各种行为(前进、后退、取值…)。至于算法,完全可以独立于容器和迭代器之外自行发展,只要设计时以迭代器为对外接口就行。


  1. https://gcc.gnu.org/onlinedocs/libstdc++/manual/iterators.html ↩︎

  2. 可以使用尾置返回类型和decltype()。 ↩︎

C++ STL六大组件-4-Iterator(迭代器) 视C++为一个语言联邦: 理解C++的全貌,学习C++的编程范式:过程/面向对象/函数式/元编程/泛型编程。 尽量以const/enum/inline替换#define:对于单纯的常量,最好用const对象/enums来替换#define,对于形似函数的宏,最好用inline函数替换#define. 尽可能使用const:const可以用于任何作用域内的对象/函数参数/函数返回类型/成员函数本体。可以帮助避免出错。 确定对象被使用前已经先被初始化:读取未初始化的值会导致不明确的行为。 了解C++ . 阅读详情

相关推荐

莫比乌斯反演

本文从算法竞赛和数论角度出发,系统介绍了狄利克雷卷积与莫比乌斯反演的核心概念。首先定义了数论函数及其基本性质,重点阐述了狄利克雷卷积的代数结构(交换环)和关键恒等式(如μ*1=ε)。随后通过卷积视角简化了莫比乌斯反演的证明过程。最后将理论提升至抽象代数层面,揭示这些数论工具本质上是偏序集关联代数在整除关系下的特例,其中莫比乌斯函数对应Zeta函数的逆元。全文展现了数学概念从具体到抽象的升华过程,为理解这些工具提供了更深刻的代数视角。

aichitang2024的博客 391

STL迭代器

目录 一、迭代器 基本概念 (1)内置迭代器的使用 (2)自己模拟迭代器的实现 (3)流型迭代器 二、lambda表达式 (1)基本概念 (2)捕获方式的区别 三、仿函数 包含头文件functional 基本概念 使用 四、函数适配器 包含头文件functional (1)普通函数绑定 (2)类内成员函数绑定 (3)占位符表示原来的参数去第几位 五、函数包装器 包含头文件functional (1)包装普通函数 (2)包装成员函数和静态函数 (3)包装仿函数 ...

weixin_61438881的博客 3334

MATLAB 2022b 用户专属:保姆级IPOPT求解器安装配置全流程(含OPTI工具箱)

本文为MATLAB 2022b用户提供IPOPT求解器的详细安装与配置指南,涵盖OPTI工具箱的适配安装、环境变量设置及常见问题解决方案。通过实战案例演示非线性优化问题的求解过程,帮助用户高效部署这一强大的优化工具,提升工程计算效率。

weixin_29092031的博客 405

STL组件之——迭代器

当然我们也可以使用非常量迭代器,这时迭代器是非常量类型的、元素类型也是非常量类型的,我们就可以对容器中的元素进行修改。所有容器类别都提供一些成员函数,使我们得以获得迭代器并以之访问所有元素,其中最重要的两个函数是。迭代器是一个”可遍历STL容器内全部或部分元素“,一个迭代器用来指出容器中的一个特定位置。返回一个迭代器,指向容器起始点,也就是第一元素的位置;返回一个迭代器,指向容器最后一个元素的下一个位置;operator==和operator!这里我们将上一个程序的输出全部变为大写。

yangSHU21的博客 1691

熵编码(五)-CABAC(一) 基础篇

前两篇算术编码文章介绍了算术编码原理和步骤。本篇文章介绍CABAC,基于上下文自适应的二进制算术编码。本文对CABAC的基本原理进行了详细的介绍和分析,下篇文章将会对H264编码中的CABAC熵编码的实际应用进行介绍。

尹佑壮的博客 3880

Halcon深度图转点云实战:从XYZ映射到3D可视化全解析

本文详细解析了如何使用Halcon将深度图转换为点云图,涵盖从XYZ映射到3D可视化的全流程。通过实战案例和代码示例,介绍了深度图预处理、xyz_to_object_model_3d核心转换及3D可视化技巧,适用于工业检测、三维重建等场景。

stem5的博客 766

STL六大组件之迭代器(Iterator)

在STL的设计理念中,将存储数据的类型(容器)和操作容器的动作(算法)二者彼此独立开来,这就导致我们无法直接通过算法来去操作存储在容器中的数据,而Iteratror的设计,就是为了提供一种统一的访问容器中元素的方式,无论容器的内部结构如何,通过迭代器,我们的算法就能够去操作相应的数据。以标准库find()为例,我们只需要告诉find查找元素的起始位置和终点位置,以及一个目标值,而不需要告诉它容器的类型,它就可以帮我们在该范围内找是否有目标值。

qq_57198230的博客 853

别再只跑memtester了!嵌入式Linux内存压力测试,这5个参数和场景你试过吗?

本文深入探讨了嵌入式Linux内存压力测试的高级技巧,重点解析了memtester工具的5个关键参数和实战场景。通过物理地址测试、迭代控制、内存分配策略等调优方法,帮助开发者有效检测内存稳定性问题,适用于长期运行设备、特定故障重现等复杂场景,提升嵌入式系统可靠性。

weixin_30838873的博客 424

C++STL之迭代器(iterator)详解

答:迭代器是一种检查容器内元素并且遍历容器内元素的数据类型。😧(看不懂,没关系,c语言学过吧,指针知道吧,没错,这就和访问数组的指针类似,指针是C语言里面就有的东西,而迭代器是C++里面才有的,二者还有其他区别,之后再整理😁)

weixin_74334323的博客 7239

Unity开源游戏源码精选:17个亲测可运行教学项目

Unity游戏开发中,掌握真实项目结构与工程实践远比熟记API更重要。本文围绕‘Unity开源项目’和‘游戏源码’两大核心概念,解析高质量开源资源的本质特征——结构清晰、逻辑可溯、修改即时反馈。从基础的MonoBehaviour生命周期组织,到进阶的ScriptableObject数据驱动、事件总线解耦,再到架构级的DOTS ECS设计与网络同步模式,技术价值在于将抽象原理落地为可调试、可验证、可迁移的代码范式。适用于新手建立开发直觉、中级开发者突破系统设计瓶颈,以及团队构建可维护框架。所有项目均基于Uni

weixin_31528001的博客 719

【Unity3D优化】优化内置shader的内存占用

在打AB包的过程中,并不会把这些Built-in的shader单独打包,并与材质球和预设体做好依赖,因此打AB包时,Unity会自行在材质球和预制体的AB包内每一个都包含进去用到的Built-in的Shader,而且运行时,由于加载的是不同的AB包,shader也是不同的实例,占用的也是多份内存。结合项目特点可以分析,由于项目里使用了大量的粒子特效,一些特殊的效果,会给特效师写定制的shader,但是这些常见的效果,特效师直接使用了Unity Built-in的shader。继续优化内存占用。

a310989583的专栏 2313

C++ STL const_iterator转换为iterator类型迭代器(深入了解,一文学会)

在 advance() 和 distance() 函数各自的功能和用法基础上,继续讲解如何利用这 2 个函数实现将 const_iterator 迭代器转换为 iterator 迭代器,或者将 const_reverse_iterator 迭代器转换为 reverse_iterator 迭代器。 注意,上面提到的 iterator、const_iterator、reverse_iterator 和 const_reverse_iterator 是 C++ STL 标准库提供了 4 种基础迭...

断点 1944

Android Telephony主要模块及功能

Telephony的代码主要由五个模块组成 1.Telephony Frameworks 代码区域: frameworks/opt/telephony/ 其中主要的文件在如下目录 /frameworks/opt/telephony/src/java/com/android/internal/telephony/ 其中比较常见的有以下几类文件 1.BaseCommands、RIL构成R

泊客 7723

C++ STL stream_iterator流迭代器(深入了解,一文学会)

流迭代器也是一种迭代器适配器,不过和之前讲的迭代器适配器有所差别,它的操作对象不再是某个容器,而是流对象。即通过流迭代器,我们可以读取指定流对象中的数据,也可以将数据写入到流对象中。 介于流对象又可细分为输入流对象(istream)和输出流对象(ostream),C++ STL 标准库中,也对应的提供了 2 类流迭代器: 将绑定到输入流对象的迭代器称为输入流迭代器(istream_iterator),其可以用来读取输入流中的数据; 将绑定到输出流对象的迭代器称为输出流迭...

断点 3635

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

STL的迭代器--Iterator

       STL中的迭代器类似指针,但不仅仅是指针。迭代器和指针很像,功能很像指针,但是实际上,迭代器是通过重载一元的”*”和”->”来从容器中间接地返回一个值。将这些值存储在容器中并不是一个好主意,因为每当一个新值添加到容器中或者有一个值从容器中删除,这些值就会失效。在某种程度上,迭代器可以看作是句柄(handle)。通常情况下迭代器(iterator)的类型可以有所变化,这样容器也会有几种

roger007的专栏 9988

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

STL::iterator迭代器

迭代器是一种泛化的指针。 iterator遵循的原则: 因为迭代器是算法连接容器的桥梁,算法通过迭代器操作容器实现算法的目标。所以算法有时需要去了解迭代器的特征(trait)来更好的使用迭代器。 不同容器的迭代器都需要声明5个特征供算法查询: _List_iterator内的5个 特征声明: 算法内获取迭代器特征的方法: 当迭代器I是一个class时可以直接获取 萃取机 traits: 问题...

shayne000的博客 299

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

C++ STL:迭代器特性 iterator_traits

STL的算法需要知道iterator的相关信息(iterator种类、iterator指向的元素的类型...),来决定使用最优化的算法。然而,原生指针本身并不是一个类类型,它们没有定义,但是标准库中泛型算法和容器希望迭代器都有上面提到的5种特性,但是对于原生指针,并没有任何结构定义。支持前面四种Iterator的所有操作,并另外支持it + n、it - n、it += n、 it -= n、it1 - it2和it[n]等操作。不同类型的迭代器支持的操作不同,在算法优化的时候需要用到。

_ 1362

C++ STL 迭代器iterator设计

迭代器是一种抽象的设计概念,现实设计语言中并没有直接对应于这个概念的实物。iterator模式定义:提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该聚合物的内部表达方式。

surfaceyan的博客 721

STL中 auto和迭代器iterator的区别

1.auto基本用法: (1)auto的原理就是根据后面的值,来自己推测前面的类型是什么; (2)auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替; 注意点: a、用auto声明的变量必须初始化(auto是根据后面的值来推测这个变量的类型,如果后面没有值,自然会报错); b、函数和模板参数不能被声明为auto; c、因为auto是一个占位符,并不是...

WPP BLOG 6864

【STL】iterator迭代器

STL中的iterator是关联algorithms和containers的纽带,algorithms想要通过iterator处理元素,即需要调用containers中的_constainer_iterator变量,但是_constainer_iterator变量却无法完整应答algorithm所需要的信息,例如_containers_iterator中的T为class类型或者non-class类型(例int),两种类型所提供的iterator_category以及其他信息各有千秋不能一概而论 所以这时就

weixin_45005811的博客 128

迭代器修改元素_C++ STL六大组件4Iterator(迭代器)

C++ STL 迭代器STL概述的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得算法变得非常通用。例如,由于函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组。在C++ STL 中,对容器中数据的读和写,是通过迭代器完成的,扮演着容器和算法之间的胶合剂。只要容器提供迭代器的接口,同一套算法代码可以利用在完全不同的容器中,这是抽象思想的经...

weixin_39880337的博客 1246

stl之再看迭代器 迭代器相应型别之五 iterator_category

根据移动特性和施行操作,迭代器分为5类: Input iterator:只读 Output iterator:只写 Forward iterator:在此迭代器所形成的区间上进行读写操作 Bidirectional iterator:forward iterator+双向移动 Random Access iterator:随机存储迭代器 前四种迭代器+随机存储(p+n,p-n,p1-p2,p[n

cow0377的专栏 580

STL迭代器back_insert_iterator、front_insert_iterator和insert_iterator

模板使得算法独立于存储的数据类型。 迭代器使得算法独立于使用的容器类型。 迭代器类型 输入迭代器 输出迭代器 正向迭代器 双向迭代器 随机访问迭代器 迭代器具有层级结构: 正向迭代器具有输入输出迭代器的全部功能,同时有自己的功能。 双向迭代器具有输入输出迭代器的全部功能,同时还有自己的功能。 随机访问迭代器具有正向迭代器的全部功能,同时还有自己的功能。 每个容器都定义了一个类级typedef名称–iterator,因此vector< int >类的迭代器类型为vector< int &g

DayDayUp 839

iterator_triats 如何识别STL容器中迭代器特性

实现iterator_triats 并识别STL容器中迭代器特性 ​ 最近在研究STL中迭代器的实现,并编写了自己的iterator_triats,在测试中发现,除了原生指针T*版本和 const T*版本可以很好的提取triats之外,对于STL中容器的迭代器则不能提取其triats。究其原因,是因为我自己实现的iterator_traits 中判断条件原因: // 版本1, 如果第二个模版参数为false执行 template <typename Iterator, bool> struc

Tuffy 208

STL Iterator 迭代器全揭秘

Iterator 是 STL 的基础,STL 算法都是基于 iterator。本文基于 gcc-12.2 分析了迭代器实现。

谢谢大家的关注 634

从零开始学C++之STL(十):迭代器适配器{(插入迭代器back_insert_iterator)、IO流迭代器(istream_iterator、ostream_iterator)}

一、迭代器适配器 反向迭代器 插入迭代器 IO流迭代器 其中反向迭代器可以参考以前的文章。 二、插入迭代器 插入迭代器实际上是一个输出迭代器(*it=; ++) back_insert_iterator back_inserter front_insert_iterator front_inserter 先来看示例:

Meditation 3553
上一篇: STL之空间配置器(Allocator)
下一篇: STL之顺序容器
Spring_24
博客等级 码龄12年 46粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spring_24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值