C++三部曲|C++核心思想

36254aa5bd1f0425af0c0a3aa71068b1.png

| 导语 C++ 的起源可以追溯到 40 年前,但它仍然是当今使用最广泛的编程语言之一,C++发明人Bjarne Stroustrup 一开始没想到 C++ 会获得如此大的成功,他说:“C++ 的成功显然令人惊讶。我认为它的成功取决于其最初的设计目标,就是有效的使用硬件,再加上强大的抽象机制,以及它根据来自实际使用情况的反馈进行谨慎的发展”。

目录

3f58b7bec859c018650316137f5adc45.png

C++历史背景

C++历史背景

C ++编程语言的历史可以追溯到1979年,当时Bjarne Stroustrup为博士学位论文进行了一些开发。在Stroustrup可以使用的所有单词中,有一种被称为Simula的语言,顾名思义,它可能是一种主要为仿真而设计的语言。Simula 67语言是Stroustrup使用的变体,被认为是支持面向对象编程范例的主要语言。Stroustrup发现这种范例对包装开发很有帮助。但是,Simula语言对于实践和实际使用而言太慢了;

随后不久,Bjarne Stroustrup希望通过支持面向对象范例来增强C。他深入研究了Smalltalk的OO实现,以获取有关实现的想法。但是他不愿意为此放弃性能,因此他开始从事“C with Classes (带有类的C) ”的工作,希望C ++代码运行时应具有与C代码相似(或更好)的性能。

第一个带有类别编译器的C称为Cfront,它是从称为CPre的C编译器派生而来的。它曾经是一个旨在将带有类别代码的C转换为通用C的程序。值得注意的目的是Cfront主要是用C用类编写的,从而创建了一个自举的编译器(可以自行编译的编译器) 。Cfront后来在1993年被放弃,但是Cfront对未来的编译器和Unix操作系统的实现产生了巨大影响。

1983年,语言的名称从“带有类的C”更改为C ++。C语言中的++运算符是用于递增变量的运算符,它使您可以深入了解Stroustrup如何看待该语言。在此期间添加了许多新功能,其中最引人注目的是虚函数,函数重载,带有&符号的引用,const关键字和使用两个正斜杠的单行注释。

1985年,Stroustrup引用了名为“ C ++编程语言”的语言。已出版。同年,C ++被实现为商业产品。该语言尚未正式标准化,因此使该书成为非常重要的参考。该语言在1989年再次进行了更新,以包括受保护的成员和静态成员,以及从多个类的继承.

1990年,发行了《带注释的C ++参考手册》。同年,Borland的Turbo C ++编译器将作为商业产品发布。Turbo C ++添加了许多其他库,这些库会对C ++的开发产生相当大的影响。尽管Turbo C ++的最后一个稳定版本是2006年,但该编译器仍被广泛使用。

1998年,C ++标准委员会发布了第一个C ++ ISO / IEC 14882:1998国际标准,其非正式名称为C ++ 98。据说《带注释的C ++参考手册》对标准的制定产生了很大的影响。还包括标准模板库,该模板库于1979年开始概念开发。2003年,该委员会对1998年标准所报告的多个问题做出了回应,并对其进行了相应的修订。更改的语言称为C ++ 03。

2005年,C ++标准委员会发布了一份技术报告(称为TR1),详细介绍了他们计划添加到最新C ++标准中的各种功能。新标准被非正式地称为C ++ 0x,因为它有望在第一个十年结束之前的某个时间发布。具有讽刺意味的是,新标准要到2011年年中才会发布。直到那时为止,已经发布了几份技术报告,并且一些编译器开始为新功能添加实验性支持。

2011年中,新的C ++标准(称为C ++ 11)完成。Boost库项目对新标准产生了重大影响,其中一些新模块直接来自相应的Boost库。一些新功能包括正则表达式支持,全面的随机化库,新的C ++时间库,原子支持,标准线程库 ,一种新的for循环语法,提供的功能类似于某些其他语言中的foreach循环,auto关键字,新的容器类,对联合和数组初始化列表以及可变参数模板的更好支持。

2014年,C ++ 14(也称为C ++ 1y)作为C++11的一个小扩展发布,主要功能是错误修复和小的改进,国际标准投票程序草案于2014年8月中完成,加强lambda函数,constexpr和类型推导特性;

2017年,发布C++17标准,C++17提供了很多东西。增强了核心语言和库;

2020年,发布C++20标准,推出了很多重量级功能,其中比较重要:

  • Concepts:概念改变了我们思考和编程模板的方式。它们是模板参数的语义类别。它们使您可以直接在类型系统中表达您的意图。如果出了什么问题,您会收到清晰的错误消息。

  • Ranges library:新的ranges库使它可以直接在容器上执行算法,用管道符号组成算法,并将其应用于无限数据流。

  • Coroutines:由于协程,C ++中的异步编程成为主流。协程是协作任务,事件循环,无限数据流或管道的基础。

  • Modules:模块克服了头文件的限制。他们承诺很多。例如,头文件和源文件的分离变得和预处理器一样过时了。最后,我们有更快的构建时间和更轻松的构建软件包的方法。

  • Concurrency:

    Atomic Smart Pointers,

    Joining & Cancellable Threads,

    The C++20 Synchronization Library,增强了C++并发编程能力;

  总结一下,C++标准演进路线如下图:

3d032ee57e98293cf055c764094c48fc.png

 从C++发展历史背景来看,C++产生的根本原因有两点:

  • 面向对象编程:  Bjarne Stroustrup研究Simula OOP编程思想,觉得这个是应对大型软件开发的绝佳武器,拥有很好的现实抽象能力和代码组织能力;

  • 高性能:Bjarne Stroustrup准备开发一套通信系统,需要编写接近硬件的低级代码,例如内存管理器、进程调度器和设备驱动程序来分离软件组件,由于当时计算机硬件性能限制,对软件性能要求苛刻,广泛使用的C语言有比较接近硬件工作的能力,所以Bjarne Stroustrup基于C语言创造可以面向对象编程的C++语言;

推荐学习:

《An Overview of the C++ Programming Language》Bjarne Stroustrup 

《Design and Evolution of C++》Bjarne Stroustrup

C++面向对象编程

怎么才能深刻理解面向对象思想?

面向对象程序设计的雏形,早在1960年的Simula语言中即可发现,当时的程序设计领域正面临着一种危机:在软硬件环境逐渐复杂的情况下,软件如何得到良好的维护?面向对象程序设计在某种程度上通过强调可重复性解决了这一问题。20世纪70年代的Smalltalk语言在面向对象方面堪称经典——以至于30年后的今天依然将这一语言视为面向对象语言的基础。

维基百科:

面向对象程序设计(英语:Object-oriented programming,缩写:OOP)是种具有对象概念的编程典范,同时也是一种程序开发的抽象方针。它可能包含数据、属性、代码与方法。对象则指的是类(class)的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。

面向对象编程就是通过对象把现实世界映射到计算机模型的一种编程方法,是抽象思维的一种体现。而抽象是计算机科学中最重要的一种思维方式; 

面向对象方法的本质就是主张从客观世界固有的事物出发的构造系统,提倡用人类在现实生活中常用的思维方法来认识、理解和描述客观事物,具体实现采用对象为基础,对象是面向对象方法中最基本的概念。对象可以用来表示客观世界中的任何实体,它既可以是具体的物理实体的抽象,也可以是人为的概念,或者是任何有明确边界和意义的东西;

程序的本质是人的意志延伸到计算机的可识别的指令。计算机(CPU)仅能识别 01代码,本身不能解决任何问题(无意识),只能由人编写程序控制计算机解决问题,因此编程的本质就是人“教会”计算机解决问题。

7b89964ed3dab28e6d23ed957f8eefc1.png

面向对象的编程技术有助于减小这一隔阂、并使这两个空间尽量趋于一致;

抽象思维一直推动着计算机技术不断向前发展,科学技术本身就是现实世界的抽象和演绎:

电路信号->01二进制->指令汇编->高级编程->模块设计->框架设计->单机系统->分布式系统-->云计算

推荐学习:

《深入理解计算机系统》

《编码:隐匿在计算机软硬件背后的语言(美.佩措尔德)》

C++面向对象编程三个核心技术

封装

主要的方法是对象和类:

对象是面向对象方法中最基本的概念。对象可以用来表示客观世界中的任何实体,它既可以是具体的物理实体的抽象,也可以是人为的概念,或者是任何有明确边界和意义的东西;

类是具有共同属性、共同方法的对象的集合,是关于对象的抽象描述,反映属于该对象类型的所有对象的性质,它由一组静态特征(数据)和它可执行的一组操作(方法)组成,一个对象就是类的一个实例;

对象和对象之间隐藏自己内部实现细节,通过标准接口进行通信,这样就可以提高程序内聚,降低耦合,方便系统进行解耦设计,同时也提高了系统稳定性,降低系统风险。

继承

主要的方法通过类的公有继承、保护继承,私有继承,单继承,多继承;结合类成员的三种属性:public、protected 和 private; 来实现共享和限制属性和方法的访问;

继承的优点是:相似的对象可以共享程序代码和数据结构,从而大大减少了程序中的冗余信息,提高软件的可重用性,便于软件迭代;

多态

编译时多态

主要的方法是重载和模板,重载包括运算符重载和函数重载,运算符重载通过重新定义运算符实现函数来实现,底层还是函数重载,函数重载通过参数列表的不同来区分不同的方法,底层是不同的函数签名;

模板是通过参数化类型来区分不同类和函数;

细节请参考:

《C++ Templates: The Complete Guide》

运行时多态

主要方法是重写,子类对父类方法的“重新”实现,底层是通过定义虚函数和构建虚函数表,在虚函数表里面插入RTTI(运行时类型信息)信息,结合继承和动态绑定,程序就可以根据实际类型判断并调用相应的属性和方法。

5fdf96ffac5360e628bfccebc7ba6f3e.png

细节请参考:

《深度搜索c++对象模型》

多态强大的功能允许不修改父类代码和业务逻辑代码,就通过扩展子类来实现功能的扩展。多态使模块在复用的基础上具备了更强的可扩展性;

C++语言核心精神

C ++的设计目标

高效地使用硬件

  • 保持与C语言兼容,C++代码与C代码运行时应具有相似(或更好)的性能;

  • 将内置操作和类型直接映射到硬件,以提供有效的内存使用和有效的低级操作;

零成本的抽象机制

  • 低成本的灵活抽象机制,可为用户定义的类型提供与内置类型相同的符号支持,用途范围和性能;

  • 类,继承,模板,概念,别名等;

任何违反以上两个设计目标之一的建议都可能会遭到拒绝;

C ++的未来目标

更加灵活,支持多种编程范型:

  • 面向过程编程:兼容C语言编程,支持自上而下面向过程编程;

  • 面向对象编程:封装,继承,多态,对象内存模型,构造和析构;

  • 泛型编程:泛型编程是自 STL(标准模板库)纳入到 C++ 标准以后才逐渐流行起来的新范式,核心思想是“一切皆为类型”,或者说是“参数化类型”“类型擦除”,使用模板而不是继承的方式来复用代码,所以运行效率更高,代码也更简洁;

  • 模板元编程:模板元编程是一种高级、复杂的技术,C++模板是图灵完备的,可以在编译期间模拟一个完整的图灵机,也就是说,可以完成任何的计算任务,比如编译期数值计算、类型计算、代码计算(如循环展开),而类型计算和代码计算可以使得代码更加通用,更加易用,性能更好;

  • 函数式编程:核心思想是以函数对象(可以作为入参和返回值),无状态(无副作用),更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,C++已经提供了一些基本元素:Lambda表达式,std::function、函数对象。模板元编程等;

更好的类型系统:内置更多类型(通过标准库扩展),更安全类型系统,更好类型泛化编程支持,支持自省,反射等特性;

更好资源的安全性:更好的对象内存模型,更好对象所有权设计(可以学习借鉴Rust),更好异常安全机制;

更好利用硬件:caches,多核(更好支持并发编程),GPUs,FPGA,SIMD等;

看Bjarne Stroustrup专访,关于程序语言设计哲学讨论,更能体会到C++的核心设计思想;

e96003e4cf4d38cfad2e79899c26031f.png

C++ 的最佳实践

我挑选一些自己觉得比较重要的实践条目,大家可以自行修正补充一下:

  • 尽量使用现代C++(C++11 以上)进行C++编程,开发效率,性能,安全性都有极大提高;

  • 尽量使用智能指针,用RAII模式管理对象生命周期,静态GC(智能指针,RAII,move语义);

  • 理解C++对象的内存模型和布局,方便定位和解决各种C++内存问题;

  • 异常是一个即安全又危险的特性,请谨慎使用;

  • 熟悉常见的设计模式和C++特有的设计范式(C++Idioms),帮助自己设计构建更好的系统,对代码进行必要的重构;

  • 代码一定要做单元测试,测试代码尽量覆盖所有的分支(覆盖率尽量高),可以采用GoogleTest单元测试框架;

  • 代码最好用valgrind等工具跑一遍,检查代码有没有内存泄漏风险和异常;

C++推荐书单

C语言:

《The C Programming Language》

学习C++,离不开C语言的了解,此书被誉为C语言的圣书,需要反复细读。

手册参考书籍:

《C++标准程序库(C++ Standard Library Tutorial and Reference) 》

《C++编程规范(C++ Coding Standards) 》

用来当手册使用,有需要时候查询一下。

C++初学者入门:

《C++ Primer》

此书为入门经典书籍,初学者一定要经常翻看。

如何更好编写C++程序:

《Effective C++ 》:

《Effective STL》

《Exceptional C++》

让你了解C++经验用法,避免踩坑。


C++内存模型:

f768dbc98192758a9fdb38af55dc8a54.png

《深度搜索c++对象模型》

让你理解C++内存布局,对C++各种内存异常问题有帮助。

泛型编程:

《深入浅出STL》

《Beyond the C++ Standard Library(Boost)》

可以学习泛型编程精髓。

modern C++:

《深入理解C++11》

《Effective Modern C++》

C++11版本以后被称为modern C++,代表一个新时代C++诞生,写代码更快,更好,更稳。

高手进阶

模板编程:

《C++ 模板完全指南(C++ Templates: The Complete Guide)》

《C++设计新思维-泛型编程与设计模式之应用(Modern C++ Design ) 》

《C++模板元编程(C++ Template Metaprogramming)》

《Advanced c++ Programming Styles and Idioms 》

如果想看懂标准库STL或者boost库代码,需要了解一些模板编程相关的知识。

设计模式:

《设计模式:可复用面向对象软件的基础》

《Modern C++ Design》

《More C++ Idioms》

《Advanced c++ Programming Styles and Idioms 》

了解一下常用设计模式和C++设计惯用方法,可以更好设计C++系统。

推荐博客:

1. https://www.stroustrup.com

ee4588d705f69098454e14c9b59de7a5.png

Bjarne Stroustrup,C++之父,Bjarne Stroustrup是丹麦人,目前任教于TAMU。他的Homepage和他的书籍The C++ Programming Language一样,都是百科全书级的,如果你认真研究,你也会成为你同事或周围人的C++之父。

2. https://www.fluentcpp.com

8ab21981de4d42bddd5f672ff9d522db.png

博客作者Jonathan Boccara是C++软件工程负责人、博客作者和作家,专注于如何使代码具有表现力,顶级C++高手,想成为专业C++工程师,可以看一看。

3. http://scottmeyers.blogspot.com

be359c8cc05e70c027deae735d3b935f.png

Scott Meyers,不多介绍,世界上几乎每个C++程序员都应该知道的名字,畅销书:Effective C++, More Effective C++的作者。博客长期更新,就凭Scott Meyers这个名字,就值得一读。

4. http://www.modernescpp.com/index.php

7629c4a3a9c8aaf08220f582a83eefa8.png

现代C++编程大神,文章主打modern C++,让你与时俱进;

5. http://purecpp.org/

f8d7bb115f3f40245fb5c840574fac68.png

这个应该算是国内顶级C++社区,举办多届C++大会。如果你想了解一些C++新特性,可以看一看。

两个经典网站

http://www.cplusplus.com

2c988432cf31402a6ac8f90102116ee9.png

https://en.cppreference.com

49be1086b41cf50f568773f771b36f8c.png

用来查询标准库API和使用说明,以及标准说明解释

81fc00cd4a5424df7eaa1e8c3deb187c.png

如果想和我有更多交流,可以加我个人微信:

0bcb36aaf9f589019211ea00ae0798b3.jpeg

欢迎大家加入极客星球圈子:

全网独家专业的技术学习圈子:

  • 修炼基本功:直播分享多年工作经验和基础技术深度理解(比如深入理解系列,基础概念的深入理解等);

  • 扩展视野:真正的分享海内外技术发展,大厂技术内幕,业界解决方案;

  • 找工作系列:面试问题,简历修改,问题答疑,各类大厂(芯片,自动驾驶,嵌入式,互联网等)制定学习路线和指导;

  • 职场普升:可以分享各种不同公司宝贵的职场工作经验, 项目经验,做事经验,普升经验,少走弯路;

2a97640d95f71b7a5b168f8cb7cb217a.png

还有更多的精彩分享:

  • 深入理解计算机系统

  • 深入理解操作系统(调度,内存,网络,IO)

  • 深入理解并发技术全景指南

  • 深入理解编程语言

  • 深入理解算法与数据结构

  • 深入理解网络协议

  • 深入理解网络编程

  • 深入理解性能优化

  • 深入理解分布式技术

  • 深入理解数据库

  • 深入理解代码设计

  • 深入理解架构设计

...

e478b6ff38edceed0bc730bdd11cd38b.jpeg

深入理解Linux网络子系统

488f33a78fdf5152c3ace738f9be4e57.jpeg

TCP/IP协议精华指南pdf

5d5f32c1519ad28b05a5c337ee45c46c.jpeg

深入理解并发/并行技术


227a3224d479097a38429964ea67b819.jpeg

如何才能掌握所有的编程语言


78da584d2e50a4491ee0f2dc4b52db41.jpeg

一文掌握网络编程精华

e9ba7c22e32e87b5b7c86fc2713ff8d8.jpeg

掌握性能优化神功心法,进阶高薪


看完一键三连
在看转发点赞

是对文章最大的赞赏,极客重生感谢你f569b41f18e2627deb99c3742e069396.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++编程思想 目 录 译者序 前言 第1章 对象的演化 1 1.1 基本概念 1 1.1.1 对象:特性+行为 1 1.1.2 继承:类型关系 1 1.1.3 多态性 2 1.1.4 操作概念:OOP程序像什么 3 1.2 为什么C++会成功 3 1.2.1 较好的C 3 1.2.2 采用渐进的学习方式 4 1.2.3 运行效率 4 1.2.4 系统更容易表达和理解 4 1.2.5 “库”使你事半功倍 4 1.2.6 错误处理 5 1.2.7 大程序设计 5 1.3 方法学介绍 5 1.3.1 复杂性 5 1.3.2 内部原则 6 1.3.3 外部原则 7 1.3.4 对象设计的五个阶段 9 1.3.5 方法承诺什么 10 1.3.6 方法应当提供什么 10 1.4 起草:最小的方法 12 1.4.1 前提 13 1.4.2 高概念 14 1.4.3 论述(treatment) 14 1.4.4 结构化 14 1.4.5 开发 16 1.4.6 重写 17 1.4.7 逻辑 17 1.5 其他方法 17 1.5.1 Booch 18 1.5.2 责任驱动的设计(RDD) 19 1.5.3 对象建模技术(OMT) 19 1.6 为向OOP转变而采取的策略 19 1.6.1 逐步进入OOP 19 1.6.2 管理障碍 20 1.7 小结 21 第2章 数据抽象 22 2.1 声明与定义 22 2.2 一个袖珍C库 23 2.3 放在一起:项目创建工具 29 2.4 什么是非正常 29 2.5 基本对象 30 2.6 什么是对象 34 2.7 抽象数据类型 35 2.8 对象细节 35 2.9 头文件形式 36 2.10 嵌套结构 37 2.11 小结 41 2.12 练习 41 第3章 隐藏实现 42 3.1 设置限制 42 3.2 C++的存取控制 42 3.3 友元 44 3.3.1 嵌套友元 45 3.3.2 它是纯的吗 48 3.4 对象布局 48 3.5 类 48 3.5.1 用存取控制来修改stash 50 3.5.2 用存取控制来修改stack 51 3.6 句柄类(handle classes) 51 3.6.1 可见的实现部分 51 3.6.2 减少重复编译 52 3.7 小结 54 3.8 练习 54 第4章 初始化与清除 55 4.1 用构造函数确保初始化 55 4.2 用析构函数确保清除 56 4.3 清除定义块 58 4.3.1 for循环 59 4.3.2 空间分配 60 4.4 含有构造函数和析构函数的stash 61 4.5 含有构造函数和析构函数的stack 63 4.6 集合初始化 65 4.7 缺省构造函数 67 4.8 小结 68 4.9 练习 68 第5章 函数重载与缺省参数 69 5.1 范围分解 69 5.1.1 用返回值重载 70 5.1.2 安全类型连接 70 5.2 重载的例子 71 5.3 缺省参数 74 5.4 小结 81 5.5 练习 82 第6章 输入输出流介绍 83 6.1 为什么要用输入输出流 83 6.2 解决输入输出流问题 86 6.2.1 预先了解操作符重载 86 6.2.2 插入符与提取符 87 6.2.3 通常用法 88 6.2.4 面向行的输入 90 6.3 文件输入输出流 91 6.4 输入输出流缓冲 93 6.5 在输入输出流中查找 94 6.6 strstreams 96 6.6.1 为用户分配的存储 96 6.6.2 自动存储分配 98 6.7 输出流格式化 100 6.7.1 内部格式化数据 101 6.7.2 例子 102 6.8 格式化操纵算子 106 6.9 建立操纵算子 108 6.10 输入输出流实例 111 6.10.1 代码生成 111 6.10.2 一个简单的数据记录 117 6.11 小结 123 6.12 练习 123 第7章 常量 124 7.1 值替代 124 7.1.1 头文件里的const 124 7.1.2 const的安全性 125 7.1.3 集合 126 7.1.4 与C语言的区别 126 7.2 指针 127 7.2.1 指向const的指针 127 7.2.2 const指针 127 7.2.3 赋值和类型检查 128 7.3 函数参数和返回值 128 7.3.1 传递const值 128 7.3.2 返回const值 129 7.3.3 传递和返回地址 131 7.4 类 133 7.4.1 类里的const和enum 133 7.4.2 编译期间类里的常量 134 7.4.3 const对象和成员函数 136 7.4.4 只读存储能力 139 7.5 可变的(volatile) 140 7.6 小结 141 7.7 练习 141 第8章 内联函数 142 8.1 预处理器的缺陷 142 8.2 内联函数 144 8.2.1 类内部的内联函数 145 8.2.2 存取函数 146 8.3 内联函数和编译器 150 8.3.1 局限性 150 8.3.2 赋值顺序 150 8.3.3 在构造函数和析构函数里隐藏行为 151 8.4 减少混乱 152 8.5 预处理器的特点 153 8.6 改进的错误检查 154 8.7 小结 155 8.8 练习 155 第9章 命名控制 157 9.1 来自C语言中的静态成员 157 9.1.1 函数内部的静态变量 157 9.1.2 控制连接 160 9.1.3 其他的存储类型指定符 161 9.2 名字空间 161 9.2.1 产生一个名字空间 162 9.2.2 使用名字空间 163 9.3 C++中的静态成员 166 9.3.1 定义静态数据成员的存储 166 9.3.2 嵌套类和局部类 168 9.3.3 静态成员函数 169 9.4 静态初始化的依赖因素 171 9.5 转换连接指定 174 9.6 小结 174 9.7 练习 174 第10章 引用和拷贝构造函数 176 10.1 C++中的指针 176 10.2 C++中的引用 176 10.2.1 函数中的引用 177 10.2.2 参数传递准则 178 10.3 拷贝构造函数 179 10.3.1 传值方式传递和返回 179 10.3.2 拷贝构造函数 182 10.3.3 缺省拷贝构造函数 187 10.3.4 拷贝构造函数方法的选择 188 10.4 指向成员的指针 ......

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值