C/C++编程:流的基类std :: ios_base

1060 篇文章 307 订阅
class ios_base;

流的基类:管理格式化标志和输入/输出异常

  • 标准输入输出库中流类整个层次结构的基类,描述了所有流对象共有的流最基本部分(与字符类型无关)

  • 它没有公共构造函数,因此无法声明此类的对象

 

该类ios_base是一个多用途类,可作为所有I / O流类的基类。它维护几种数据:

1) 状态信息:流状态标志
2) 控制信息:控制输入和输出序列以及输入区域的格式化的标志
3) 私有存储:索引可扩展的数据结构,允许两者  long 和  void * 成员,可以实现为两个任意长度的数组或两个元素的结构的单个数组或另一个容器。
4) 回调:从imbue(),copyfmt()和〜ios_base()调用的任意数量的用户定义函数
 

更具体的说,ios_base 类维护流的以下信息:

 field成员函数描述
Formattingformat 标识flags
setf
unsetf
一组内部标志,这些标志影响解释或生成某些输入/输出操作的方式.
具体见成员类型 fmtflags.
field widthwidth下一个要插入的格式化元素的宽度。
显示精度precision下一个插入的浮点值的十进制精度。
地区getloc
imbue
The locale object 用于受本地化属性影响的格式化输入/输出操作的区域设置对象。
Other回调堆栈register_callback指向某些事件发生时调用的函数的指针的堆栈。
可扩展数组iword
pword
xalloc
用于存储long和void*类型对象的内部数组。
典型的实现方式包含与以下所示的fmtflags,iostate,openmode和seekdir的所有值相对应的成员常量,用于维护当前精度,宽度和格式标志的成员变量,异常掩码,缓冲区错误状态,可调整大小的容器(用于保存回调),当前使用的语言环境,私有存储以及xalloc()的静态整数变量。

目录

 

 


Member Functions

(constructor)

Construct object (public member function )

(destructor)

Destruct object (public member function )

std :: ios_base :: ios_base

protected: ios_base();
ios_base (const ios_base&) = delete;

构造对象

  • ios_base对象在构造时具有不确定的值。每个ios_base基类对象都应该通过调用basic_ios :: init来初始化。
  • 该类作为基类,因此没有公共构造函数,这就防止了构造该类的对象——只有派生类的对象可以构造。

ios_base也删除了它的复制赋值成员函数。和复制构造函数一样,这个函数也被删除:

  ios_base (const ios_base&) = delete;
  ios_base& operator= (const ios_base&) = delete;

异常安全

  • 强有力的保证:如果引发异常,则没有副作用。

std :: ios_base ::〜ios_base

virtual ~ios_base();

销毁对象

  • 在对象被销毁之前,所有用成员register_callback注册的回调函数都以erase_event作为第一个参数被调用。

Data races

  • 对象被修改。

异常安全

  • No-throw保证:从不抛出异常。
Formatting:

flags

获取/设置格式标志(公共成员函数)

setf

设置特定的格式标志(公共成员函数)

unsetf

清除特定格式的标志(公共成员函数)

precision

获取/设置浮点十进制精度(公共成员函数)

width

获取/设置字段宽度(公共成员函数)

std::ios_base::flags

get (1)
fmtflags flags() const;
set (2)
fmtflags flags (fmtflags fmtfl);

获取/设置格式标志

  • (1)返回流中当前选择的格式标志。
  • (2)为流设置新的格式标志,返回先前的值。

流的格式标志影响数据在特定输入函数中的解释方式,以及特定输出函数如何写入数据。

该函数的第二种形式为流的所有格式标记设置值,覆盖现有值并清除参数中未显式设置的任何标记。要访问单个标记,请参见成员setf 和 unsetf

参数

fmtfl   

返回值

Data races

  • 访问(1)或修改(2)流对象。
  • 同时访问同一个流对象可能会导致数据竞争。

异常安全

基本保证:如果抛出异常,则流处于有效状态。

// modify flags
#include <iostream>     // std::cout, std::ios

int main () {
  std::cout.flags ( std::ios::right | std::ios::hex | std::ios::showbase );
  std::cout.width (10);
  std::cout << 100 << '\n';
  return 0;
}

std :: ios_base :: setf、std::ios_base::unsetf

set (1)
fmtflags setf (fmtflags fmtfl);
mask (2)
fmtflags setf (fmtflags fmtfl, fmtflags mask);

设置特定的格式标志

(1)设置流的格式标志,其位在fmmtfl中设置,其余的保持不变,相当于flags(fmtfl|flags())

(2)设置流的格式标志,其位在fmtfl和mask中都设置,并清除其位在mask中设置但不在fmtfl中设置的格式标志,就像调用flags((fmtfl&mask)|(flags()&~mask))。

两者都返回调用前流的格式标志的值。

流的格式标志影响在某些输入函数中解释数据的方式以及某些输出函数如何写入数据。有关此函数参数的可能值,请参见ios_base::fmtflags。

1)的第一种形式通常用于设置独立的格式标志:boolalpha、showbase、showpoint、showpos、skipws、unitbuf和uppercase,也可以直接用member unset设置。

2)通常用于使用一个字段位掩码作为掩码参数来设置一个选择标志的值:

fmtfl
format flag value
mask
field bitmask
left, right or internaladjustfield
dec, oct or hexbasefield
scientific or fixedfloatfield

参数化操纵器 setiosflags行为与此成员函数(1)的第一种形式类似。

参数:

fmtfl要设置的格式标志。如果使用第二种语法,只有在fmtfl和mask中设置的位在流的格式标志中设置;在mask中设置但在fmtfl中没有设置的标志被清除
unmask包含要修改的标志的掩码。

Data races

  • 修改流对象。
  • 对同一流对象的并发访问可能会导致数据争用。

异常安全:

  • 基本保证:如果抛出异常,则流处于有效状态。
void unsetf (fmtflags mask);
清除特定格式的标志
  • 清除mask中选择的格式标志。
  • 参数化操纵符resetiosflags的行为方式与这个成员函数类似。

参数:

mask指定要清除的标志的位掩码。这些标志被指定为fmtflags成员类型的标志的组合。

Data races

  • 修改流对象。
  • 对同一流对象的并发访问可能会导致数据争用。

异常安全:

  • 基本保证:如果抛出异常,则流处于有效状态。
// modifying flags with setf/unsetf
#include <iostream>     // std::cout, std::ios

int main () {
  std::cout.setf ( std::ios::hex, std::ios::basefield );  // set hex as the basefield
  std::cout.setf ( std::ios::showbase );                  // activate showbase
  std::cout << 100 << '\n';
  std::cout.unsetf ( std::ios::showbase );                // deactivate showbase
  std::cout << 100 << '\n';
  return 0;
}

std::ios_base::precision

get (1)
streamsize precision() const;
set (2)
streamsize precision (streamsize prec);

作用:获取/设置浮点十进制精度

  • 1) 返回当前精度。
  • 2)将精度设置为给定的精度。返回上一个精度。

浮点精度决定了在表示浮点值的插入操作中要写入的最大数字数。如何解释它取决于floatfield  format flag是设置为特定的符号( fixedscientific)还是未设置(使用默认的符号,不一定等于 fixedscientific)。

这个十进制精度也可以使用setprecision进行修改。

默认精度由std :: basic_ios :: init建立,为6。

返回值

  • 调用前在流中选择 的精度

Data races

  • 访问(1)或修改(2)流对象。
  • 同时访问同一个流对象可能会导致数据竞争。

异常安全

基本保证:如果抛出异常,则流处于有效状态。

// modify precision
#include <iostream>     // std::cout, std::ios

int main () {
  double f = 3.14159;
  std::cout.unsetf ( std::ios::floatfield );                // floatfield not set
  std::cout.precision(5);
  std::cout << f << '\n';
  std::cout.precision(10);
  std::cout << f << '\n';
  std::cout.setf( std::ios::fixed, std:: ios::floatfield ); // floatfield set to fixed
  std::cout << f << '\n';
  return 0;
}

 std :: ios_base :: width

get (1)
streamsize width() const;
set (2)
streamsize width (streamsize wide);

作用:获取/设置字段宽度

    1) 返回当前字段的宽度。

     2)将字段宽度设置为给定的宽度。返回上一个字段的 fill

字段宽度决定要在某些输出表示形式中写入的最小字符数。如果表示的标准宽度小于字段宽度,表示将在格式标志adjustfield确定的点用填充字符填充(left, right or internal)

可以通过调用成员函数fill来检索或更改填充字符。

可以通过调用成员函数flags或setf来修改格式标记调整字段,方法是插入以下操作符之一: leftright 和 internal,或者插入参数化操作符setiosflags.。

也可以通过 setw修改字段宽度。

返回:

调用前字段宽度的值。

// field width
#include <iostream>     // std::cout, std::left

int main () {
    std::cout << 100 << '\n';
    std::cout.width(10);
    std::cout << 100 << '\n';
    std::cout.fill('x');
    std::cout.width(15);
    std::cout << std::left << 100 << '\n';
    return 0;
}

语言环境

imbue

Imbue语言环境(公共成员函数)

getloc

获取当前语言环境(公共成员函数)

std :: ios_base :: imbue

locale imbue (const locale& loc);

作用:将loc作为流的新语言环境

  • 将loc与流关联起来,作为新的locale对象,与语言环境敏感的操作一起使用。
  • 在此之前,该函数以imbue_event作为第一个参数,调用所有通过成员register_callback注册的函数。
  • 标准流类不继承这个成员,而是继承调用这个函数的basic_ios::imbue,但也会将区域设置注入到相关的流缓冲区(如果有的话)。

返回值:调用前与流关联的locale 对象。

 

// imbue example
#include <iostream>     // std::cout
#include <locale>       // std::locale

int main()
{
  std::locale mylocale("");   // get global locale
  std::cout.imbue(mylocale);  // imbue global locale
  std::cout << 3.14159 << '\n';
  return 0;
}

std::ios_base::getloc

locale getloc() const;

作用:返回与流关联的当前语言环境。

内部可扩展数组

xalloc

获取可扩展数组的新索引[静态] (公共静态成员函数)

iword

获取可扩展数组的整数元素(公共成员函数)

pword

获取可扩展数组的指针元素(公共成员函数)

std :: ios_base :: xalloc

static int xalloc();

作用:获取可扩展数组的新索引[静态]

内部可扩展数组是long(如果使用成员iword访问)或void*(如果使用成员pword访问)类型的对象的通用数组。

返回值:

  • 可以与成员iword或成员pword一起使用的新索引。

Data races:

  • 同时调用这个函数可能会引入数据竞争。

异常安全:

  • 强保证:如果抛出异常,则任何流中都不会发生更改。
#include <iostream>
 
template<class charT, class traits = std::char_traits<charT> >
class mystream : public std::basic_ostream<charT, traits>
{
 public:
    static const int xindex;
    mystream(std::basic_ostream<charT, traits>& ostr) :
        std::basic_ostream<charT, traits>(ostr.rdbuf())
    {
         this->pword(xindex) = this;
    }
 
    void myfn()
    {
        *this << "[special handling for mystream]";
    }
};
 
// each specialization of mystream obtains a unique index from xalloc()
template<class charT, class traits>
const int mystream<charT, traits>::xindex = std::ios_base::xalloc();
 
// This I/O manipulator will be able to recognize ostreams that are mystreams
// by looking up the pointer stored in pword
template<class charT, class traits>
std::basic_ostream<charT,traits>& mymanip(std::basic_ostream<charT,traits>& os)
{
 if (os.pword(mystream<charT,traits>::xindex) == &os) 
    static_cast<mystream<charT,traits>&>(os).myfn();
 return os;
}
 
int main()
{
    std::cout << "cout, narrow-character test " << mymanip << '\n';
 
    mystream<char> myout(std::cout);
    myout << "myout, narrow-character test " << mymanip << '\n';
 
    std::wcout << "wcout, wide-character test " << mymanip << '\n';
 
    mystream<wchar_t> mywout(std::wcout);
    mywout << "mywout, wide-character test " << mymanip << '\n';
}

std :: ios_base :: iword

long& iword( int index );

作用:获取可扩展数组的整数元素

#include <iostream>

// custom manipulator with per-stream static data:
std::ostream& Counter (std::ostream& os) {
    const static int index = os.xalloc();
    return os << ++os.iword(index);
}


int main()
{
    std::cout << Counter << ": first line\n";
    std::cout << Counter << ": second line\n";
    std::cout << Counter << ": third line\n";
    // cerr has its own count
    std::cerr << Counter << ": error line\n";
}

#include <iostream>
#include <string>
 
struct Foo {
    static int foo_xalloc;
    std::string data; 
    Foo(const std::string& s) : data(s) {}
};
 
// allocates the iword storage for use with Foo objects
int Foo::foo_xalloc = std::ios_base::xalloc();
 
// This user-defined operator<< prints the string in reverse if the iword holds 1
std::ostream& operator<<(std::ostream& os, Foo& f)
{
    if(os.iword(Foo::foo_xalloc) == 1)
        return os << std::string(f.data.rbegin(), f.data.rend());
    else
        return os << f.data;
}
 
// This I/O manipulator flips the number stored in iword between 0 and 1
std::ios_base& rev(std::ios_base& os)
{
    os.iword(Foo::foo_xalloc) = !os.iword(Foo::foo_xalloc);
    return os;
}
 
int main()
{
    Foo f("example");
    std::cout << f << '\n' << rev << f << '\n' << rev << f << '\n';
}

std :: ios_base :: pword

void *&pword(int idx);

作用:获取可扩展数组的指针元素

// pword example
#include <iostream>     // std::ios, std::cout, std::cerr, std::clog

const int name_index = std::ios::xalloc();

// stores pointer in extensible array:
void SetStreamName (std::ios& stream, const char* name) {
  stream.pword(name_index) = const_cast<char*>(name);
}

// custom manipulator that uses stored pointer:
std::ostream& StreamName (std::ostream& os) {
  const char* name = static_cast<const char*>(os.pword(name_index));
  if (name) os << name;
  else os << "(unknown)";
  return os;
}

int main()
{
  SetStreamName(std::cout, "standard output stream");
  SetStreamName(std::cerr, "standard error stream");
  std::cout << StreamName << '\n';
  std::cerr << StreamName << '\n';
  std::clog << StreamName << '\n';
  return 0;
}
其他

register_callback

注册事件回调函数(公共成员函数)

sync_with_stdio

设置每个输入输出操作后是否将标准C++流同步到标准C流

std :: ios_base :: register_callback

void register_callback(event_callback fn,int索引);

作用:

  • 注册一个用户定义的函数,该函数将被imbue()、std::basic_ios::copyfmt()和~ios_base()调用。
  • 每个注册的回调函数每次都会被调用:事件类型(event类型的值)作为它的第一个参数传递,可以用来区分调用者。
  •  如果注册了多个回调函数,则会以注册的相反顺序全部调用它们。
  • 用户定义的回调函数不允许引发异常。
  • 一旦注册,回调就无法取消注册:在其整个生命周期中,它仍是流对象的一部分。如果需要更改回调的行为,则可以通过iword()pword()进行控制。
  • 如果同一功能被多次注册,则将被多次调用。

  • 与回调一起存储的整数值通常是从xalloc()获得的索​​引

Data races:

  • 同时调用这个函数可能会引入数据竞争。

异常安全

  • 基本保证:如果引发异常,则流处于有效状态。
// stream callbacks
#include <iostream>     // std::cout, std::ios_base
#include <fstream>      // ofstream

void testfn (std::ios::event ev, std::ios_base& stream, int index)
{
  switch (ev)
  {
    case stream.copyfmt_event:
      std::cout << "copyfmt_event\n"; break;
    case stream.imbue_event:
      std::cout << "imbue_event\n"; break;
    case stream.erase_event:
      std::cout << "erase_event\n"; break;
  }
}

int main () {
  std::ofstream filestr;
  filestr.register_callback (testfn,0);
  filestr.imbue (std::cout.getloc());
  return 0;
}

std :: ios_base :: sync_with_stdio

bool sync_with_stdio(bool sync = true);

作用:设置每个输入输出操作后是否将标准C++流同步到标准C流

  • 如果流是同步的,程序可以混合iostream操作和stdio操作,并且它们的可观察效果保证与线程中使用的顺序相同。
  • 并发访问同步流(即该函数返回true的流)从不引入数据竞争:字符是单独读写的,尽管没有进一步保证线程之间的顺序。这可能会导致线程之间的交错字符,除非程序强制执行整个操作的适当同步。

Data races:

  • 同时调用这个函数可能会引入数据竞争。

异常安全

  • 基本保证:如果引发异常,则流处于有效状态。
#include <iostream>
#include <cstdio>
 
int main()
{
    std::ios::sync_with_stdio(false);
    std::cout << "a\n";
    std::printf("b\n");
    std::cout << "c\n";
}

 

Member types

event

表示事件类型的类型(公共成员类型)
event_callback事件回调函数类型(公共成员类型)

fmtflags

流格式标志的类型(公共成员类型)

iostate

流状态标志的类型(公共成员类型)

openmode

流打开模式标志的类型(公共成员类型)

seekdir

流搜索方向标志的类型(公共成员类型)

std :: ios_base :: event

enum event {erase_event, imbue_event, copyfmt_event};

指定事件类型

  • 指定传递给register_callback()在特定事件上注册的函数的事件类型。定义了以下常量:
Constant事件触发
erase_event调用 ~ios_base() or basic_ios::copyfmt() (在复制成员之前)
imbue_event调用 ios_base :: imbue (就在函数返回之前)。
copyfmt_event调用 basic_ios::copyfmt() (在复制成员之后,但在复制异常设置之前)

std :: ios_base :: event_callback

typedef void (*event_callback)(event type, ios_base& ios, int index);

函数回调的类型,可以使用register_callback()注册,在特定事件上调用。

  • type是ios_base::event类型的值,它指示了将调用这个回调的事件的类型。
  • 当回调函数被std::ios_base和std::basic_ios成员函数调用时,this作为参数传递。
  • index是注册函数时传递给register_callback()的用户提供的值。

std :: ios_base :: seekdir

typedef /*implementation defined*/ seekdir;
static constexpr seekdir beg = /*implementation defined*/
static constexpr seekdir end = /*implementation defined*/
static constexpr seekdir cur = /*implementation defined*/

指定文件搜索方向类型。定义了以下常量:

ConstantExplanation
beg流的开始
end流的结尾
cur
流位置指示器的当前位置
#include <iostream>
#include <string>
#include <sstream>
 
int main()
{
    std::istringstream in("Hello, World!");
    std::string word1, word2, word3, word4, word5;
 
    in >> word1;
    in.seekg(0, std::ios_base::beg); // <- rewind
    in >> word2;
    in.seekg(1, std::ios_base::cur); // -> seek from cur pos toward the end
    in >> word3;
    in.seekg(-6, std::ios_base::cur); // <- seek from cur pos (end) toward begin
    in >> word4;
    in.seekg(-6, std::ios_base::end); // <- seek from end toward begin
    in >> word5;
 
    std::cout << "word1 = " << word1 << '\n'
              << "word2 = " << word2 << '\n'
              << "word3 = " << word3 << '\n'
              << "word4 = " << word4 << '\n'
              << "word5 = " << word5 << '\n';
}

std::ios_base::iostate

typedef /*implementation defined*/ iostate;
static constexpr iostate goodbit = 0;
static constexpr iostate badbit = /*implementation defined*/
static constexpr iostate failbit = /*implementation defined*/
static constexpr iostate eofbit = /*implementation defined*/

流状态标志的类型

ConstantExplanation
goodbitno error
badbit不可恢复的流错误
failbit输入/输出操作失败(格式或提取错误)
eofbit相关的输入序列已到达文件末尾

---

std :: ios_base :: fmtflags

typedef /*implementation defined*/ fmtflags;
static constexpr fmtflags dec = /*implementation defined*/
static constexpr fmtflags oct = /*implementation defined*/
static constexpr fmtflags hex = /*implementation defined*/
static constexpr fmtflags basefield = dec | oct | hex;
static constexpr fmtflags left = /*implementation defined*/
static constexpr fmtflags right = /*implementation defined*/
static constexpr fmtflags internal = /*implementation defined*/
static constexpr fmtflags adjustfield = left | right | internal;
static constexpr fmtflags scientific = /*implementation defined*/
static constexpr fmtflags fixed = /*implementation defined*/
static constexpr fmtflags floatfield = scientific | fixed;
static constexpr fmtflags boolalpha = /*implementation defined*/
static constexpr fmtflags showbase = /*implementation defined*/
static constexpr fmtflags showpoint = /*implementation defined*/
static constexpr fmtflags showpos = /*implementation defined*/
static constexpr fmtflags skipws = /*implementation defined*/
static constexpr fmtflags unitbuf = /*implementation defined*/
static constexpr fmtflags uppercase = /*implementation defined*/

指定可用的格式标志。它是一个BitmaskType。定义了以下常量:

ConstantExplanation
dec对整数I/O使用十进制基数: see std::dec
oct对整数I/O使用八进制基数: see std::oct
hex对整数I/O使用十六进制基数: see std::hex
basefielddec|oct|hex. 用于屏蔽操作
left左调整(向右侧添加填充字符):: see std::left
right右调整(向左侧添加填充字符): see std::right
internalinternal adjustment (在内部指定点上增加填充字符): see std::internal
adjustfieldleft|right|internal. 用于屏蔽操作
scientific用科学计数法写浮点值: see std::scientific
fixed用定点表示法写浮点值:see std::fixed
floatfieldscientific|fixed. 用于屏蔽操作
boolalpha以字母字符串(truefalse)读取/写入bool元素。: see std::boolalpha
showbase生成一个指示整数输出数字基数的前缀,需要货币I / O中的货币指示符: see std::showbase
showpoint无条件生成浮点数输出的小数点字符:see std::showpoint
showpos在非负数值前加一个加号(+): see std::showpos
skipws在某些输入操作之前跳过前导空格:see std::skipws
unitbuf在某些输出操作中, 将某些小写字母替换为大写字母: see std::unitbuf
uppercase在某些输出操作中, 将某些小写字母替换为大写字母:see std::uppercase

--

#include <iostream>
 
int main() 
{
    int num = 150;
 
    // using fmtflags as class member constants:
    std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
    std::cout.setf(std::ios_base::showbase);
    std::cout << num << '\n';
 
    // using fmtflags as inherited class member constants:
    std::cout.setf (std::ios::hex , std::ios::basefield);
    std::cout.setf (std::ios::showbase);
    std::cout << num << '\n';
 
    // using fmtflags as object member constants:
    std::cout.setf(std::cout.hex, std::cout.basefield);
    std::cout.setf(std::cout.showbase);
    std::cout << num << '\n';
 
    // using fmtflags as a type:
    std::ios_base::fmtflags ff;
    ff = std::cout.flags();
    ff &= ~std::cout.basefield;   // unset basefield bits
    ff |= std::cout.hex;          // set hex
    ff |= std::cout.showbase;     // set showbase
    std::cout.flags(ff);
    std::cout << num << '\n';
 
    // not using fmtflags, but using manipulators:
    std::cout << std::hex << std::showbase << num << '\n';
}

Member classes

failure

流异常的基类(公共成员类)

Init

初始化标准流对象(公共成员类)

 

std::ios_base::failure

  • std :: ios_base :: failure定义输入/输出库中的函数在失败时引发的异常对象。

  • std :: ios_base :: failure可以定义为std :: ios_base的成员类,也可以定义为具有相同功能的另一个类的同义词(typedef)

---

#include <iostream>
#include <fstream>
int main()
{
    std::ifstream f("doesn't exist");
    try {
        f.exceptions(f.failbit);
    } catch (const std::ios_base::failure& e)
    {
        std::cout << "Caught an ios_base::failure.\n"
                  << "Explanatory string: " << e.what() << '\n'
                  << "Error code: " << e.code() << '\n';
    }
}

std::ios_base::Init

  • 构造此成员类型的对象可确保标准流对象(cincoutcerrclogwcinwcoutwcerr and wclog)的构造并正确初始化。
  • 该类维护一个内部静态计数器,其中包含现有对象的数量。
     

成员常量

流具有成员常量,其中可能包含成员类型fmtflags、iostate、openmode和seekdir的值(有关详细信息,请参阅每种类型的描述)。

 

 

 

 

 

https://en.cppreference.com/w/cpp/io/ios_base/iostate

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值