类和对象

相对于c语言的结构体,在c++中更喜欢用这种类型,当然也兼容结构体

在类中可以定义成员变量成员函数,成员函数可以访问成员变量

class stack
//stack是类名
{
  //成员函数
    void Init()
    {
        a=nullptr;
        top=capacity=0;
    }
  //成员变量
  int* a;
  int top;
  int capacity;
};
int main()
{
    stack S2;
    return 0;
}

类的定义

class是定义类的关键字,{}里面是类的主体,和结构体一样{}后要加

class与struct的默认权限不一样

class默认限定符是私有的

strucr的默认限定符是公有的

访问限定符

public(公有)

protection(保护)

private(私有)

定义了新的作用域,类的所有成员都在域中

pubilc修饰的成员可以在类外面访问

protection和private修饰的成员只能在类里面访问不能直接在类的外面被访问

类中以上两个私有关键字不受限定符限制

class stack
{
 pubilc:
    void push(int x)
    {
    	if(capacity==top)
        {
            int newcapacity=capacity==
                0?4:capacity*2;
            a=(int*)realloc(a,sizeof(int)*newcapacity);
            capacity=newcapacity; 
        }
        a[top++]=x;
    }
	void  Init()
    {
        int*a=nullptr;
        top=capacity=0;
    }
private:
    //修饰从24行开始直到遇到下一个限定符结束
    //private修饰以后外部无法访问
    int* a;
    int top;
    int capacity;
};

int main()
{
    return 0;
}

类可以成员定义分离

如果成员函数在类里面定义,编译器可能会把它当做内联函数处理

当类在外定义成员时,需要使用::作用域操作符指明成员属于哪个类的域

//.h文件声明
class stack
{
    void Init();
    void push(int x);
    private:
        int* a;
    	int top;
    	int capacity;
};
//.cpp文件定义
//stack::说明它是成员函数,且可以在这个类中找其他成员变量
//不加的话会找不到成员,因为不在这个域中
void stack::Init()
{
    int*a=nullptr;
    top=capacity=0;
}
void stack::push(int x)
{
    if(capacity==top)
    {
        int newcapacity=capacity==
            0?4:capacity*2;
        a=(int*)realloc(a,sizeof(int)*newcapacity);
        capacity=newcapacity; 
    }
    a[top++]=x;
}

用_来区分成员变量,或是前置,或是后置,或是 _m,是一种书写风格

类的实例化

类的定义不需要分配内存空间,而去使用类创建一个对象,才会占用空间

成员函数是存储在公共代码区的,所以sizeof计算类时不会计算成员函数的大小

class date
{
    pubilc:
        void Init (int year,int month,int day)
        {
        
            _year=year;
            _month=month;
            _day=day;
        }
	private:
    //这里的变量都是声明,声明没有开空间,没有定义是没有空间的
    int _year;
    int _month;
    int _day;
};
int main()
{
    date._year=1;
    //这里是不可以的因为上面的类只是声明
    //开空间
    date d;
    d._year=1;
    //这里还是不行赋值,因为是私有的
}

#include<iostream>
using namespace std;
class a1
{	public:
 		void f1(){}
 	private:
 		int _a;
};
class a2
{
  public:
    void f2(){}
};
class a3
{};
int main()
{
    cout<<sizeof(a1)<<endl;
    cout<<sizeof(a2)<<end2;
    cout<<sizeof(a3)<<end3;
    return 0;
}
//结果 4,1,1

为什么一个没有成员变量名,一个没有成员,大小还能为1呢?

因为这两个类进行了占位,c++对没有成员变量的类分配1byte的空间,进行占位表示对象存在

为什么要内存对齐?

cpu访问内存时并不是从任意位置随意访问,只能是从内存地址开头位置去访问
在这里插入图片描述

对齐下的地址,每个值之间都会有没用的指针给隔开

不对齐的地址,每个值的地址都是相邻的

在不对齐的情况下,cpu从 _a开始向下访问,才能访问到 _b,期间读取 _a时要读前三个字节的数据,在读 _b的前一个字节,再进行拼接才能读出 _a的值,期间要涉及数据拼接多次读取,还可能读取到不需要的数据

而在对齐情况下 从上向下访问到 _b只需要一次,从而提高了效率


this指针

隐藏的this指针,this指向当前调用这个函数的对象,在c++中是个关键字

只对非静态的成员函数有效

只能在成员函数内部使用

//编译器自动添加this
class Date
{
    pubulic:
    //this在实参和形参位置不能显示的写
    //但是在类里面可以显示使用
    void Init(/*Date* this*/,int year,int month,int day)
{
    /*this->*/_year=year;
    /*this->*/_month=month;
    /*this->*/_day=day;
}
    private:
    int _year;
    int _month;
    int _day;
};

//调用的地方
int main()
{
    
    Date d;
    d.Init(/*&d*/,2023,7,27);
    return 0;
}

通过this访问的对象,this是个成员函数形参,一般存储在栈帧中,所以对象不存储编译器一般会用寄存器自动传递

class p
{
  
    public:
    void print()
    {
        cout<<"print"<<emdl;
    }
    private:
    int _a;
};
int main()
{
    p* d=nullptr;
    d->print();
    //这段代码没有解引用,因为print函数存在在公共代码区,不需要在类中寻找
    (*d).print();
    //这段看上去解引用了,其实并没有,因为编译器不需要找print函数,所以和d->print()一样
    d->_a; 
    //当访问类的成员时就会崩溃,因为d是空指针
    return 0;
}

默认成员函数

当一个类为,并非什么都没有,编译器会自动生成六个默认成员函数

分别是负责初始化与清理的,构造函数析构函数

负责拷贝赋值的,拷贝构造函数赋值重载函数

负责取地址重载的,取地址重载函数

构造函数

构造函数是个特殊的成员函数,构造函数的函数名类名相同

构造函数的作用是初始化对象,而不是开辟空间

特征

在对象的生命周期内只调用一次

没有返回值

对象实例化时自动调用

构造函数可以进行重载

class Date
{
    public:
    	//无参构造
        Date()
        {
            _year=1;
            _month=1;
            _day=1;
        }
    	//带参数构造
    	Date(int year,int month,int day)
        {
            _year=year;
            _month=month;
            _day=day; 
		}
    	//全缺省版
    	Date(int year=1,int month=1,int day=1)
        {
            _year=year;
            _month=month;
            _day=day;
		}
    	//从语法上看这几个函数构成函数重载可以共存,但是调用会出现问题,因为编译器不知道要调用哪个
      void print()
        {
            cout << _year << endl;
            cout << _month << endl;
            cout << _day << endl;
        }
    private:
        int _year;
        int _month;
        int _day;
};
int main()
{
    //无参初始化
    //使用无参构造函数时,对象后不加括号,否则就是函数声明
    Date a;
    a.print();
    //带参初始化
    Date b(2023,7,27);
    b.print();
    return 0;
}
//执行结果 1,1,1

默认构造函数

一般情况下都需要手动写构造函数,决定初始化方式,手动编写后,编译器就不会自动生成

只有在成员变量全是自定义类型,才考虑不写构造函数

内置类型(语言提供的类型,只要是指针都是内置类型),对于内置类型成员编译器不会处理(并不绝对)

无参的构造函数,全缺省的构造函数,编译器生成的构造函数,统称默认构造函数,这三个只能有一个,否者会出现调用歧义

初始化列表

冒号开始接着以逗号分割数据的成员列表,每个成员变量后跟着一个放在括号里的初始值或是表达式

尽量使用初始化列表初始化,不论是否使用初始化列表,对于自定义变量一定会优先使用初始化列表进行初始化

每个成员变量只能初始化一次

引用成员变量

const修饰成员变量

自定义类型成员且无默认构造函数

这三种必须在初始化列表进行初始化

成员变量类中的声明顺序决定了其在初始化列表的初始化顺序

class D
{
    public:
    D(int &a)
        :_a(a)
        {}
    
    private:
    
    int _a;
}
class Date
{
    public:
    Date(int year,int month,int day,int &n)
    {
       //初始化列表是成员定义的地方
        :_year(year)
        ,_month(month)
        ,_n(0)
       	,_end(n)
        ,_D(1)
        //,_day(day)
        //对于day在初始列表,也是定义了的但是因为没有编写,内置类型编译器不做处理,所以给了随机值
       //无论是有没有显示定义,初始化列表都会去定义,自定义类型或调用默认构造,内置类型给随机值,部分编译器会给零,显示定义的构造函数的自定义类型,初始化列表不作处理
        //也可以混合使用
        {
            //赋值
            _day=day;
        }
	}
    private:
    //成员声明
    int _year=1;
    //c++11支持给缺省值,这个缺省值是给初始化列表的
    //如果初始化列表没有显示定义,就使用这个缺省值
    //若是初始化列表定义了,缺省值无效(缺省值主要是备用)
    int _month;
    int _day;
    //const必须在定义时初始化
    const int _n;
    //引用必须在定义时初始化
    int &_end;
    //自定义类型没有构造需要在定义时初始化
    D _D;
};
calss a
{
    public:
    A(int i)
        :_n(i)
        {}
    A(const a&i)
        :_n(i._n)
        {}
    private:
    int _n;
};
int main()
{
    //初始化
    a A(1);
    //单参数构造函数隐式类型转换
    //2会调用a构造函数生成一个临时对象,再用这个临时对象拷贝构造A1
    //编译器优化后,直接将2构造
    a A1=2;
    return 0;
}

析构函数

析构函数负责对象在销毁时完成对象的资源清理工作

析构函数是在类名前加上 ‘~’

无参无返回值,不能重载

一个类只能有一个析构函数,没有手动编写,编译器会自动生成默认析构函数(对于内置类型不做处理)

对象生命周期结束时,编译器自动调用析构函数

定义的先析构,类似栈帧的后进先出

  class Date
 {
	~Date()
        {
            cout << _year << endl;
        }
        void print()
        {
            cout << _year << endl;
            cout << _month << endl;
            cout << _day << endl;
        }
    
    private:
        int _year;
        int _month;
        int _day;
};
int main()
{
   
    Date a(2000);
   // a.print();
    Date b(2023);
   // b.print();
    return 0;
}
//执行结果2023,2000

类中无资源申请可以不去编写析构函数,但是一旦有资源申请就需要去编写,防止资源泄露


拷贝构造

拷贝构造函数是构造函数的重载

拷贝构造只有一个形参,是对类类型对象的引用,在不涉及改变源数据的情况下,经常加const来修饰

class Date
{
    public:
        Date(int year = 1900, int month = 1, int day = 1)
        {
            _year = year;
            _month = month;
            _day = day;
        }
    	//错误
        //Date(const Date d)   
		//正确
        Date(const Date& d)   
        {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
    private:
     int _year;
     int _month;
     int _day;
};
int main()
{
     Date d;
     Date D(d);
     return 0;
}

默认拷贝构造是按对象内存储字节序完成拷贝的,这种拷贝又叫浅拷贝

无穷递归

如果传值方式并非引用传参,在调用函数之前会调用拷贝构造函数,而调用拷贝函数又需要传参,又会调用拷贝函数循环往复,就成了死循环

所以要一定使用引用传参


class Stack
{
    public:
        Stack(size_t capacity=0)
            {
                _a = (int*)malloc(sizeof(int) * capacity);
                if (_a == NULL)
                {
                    perror("malloc fail");
                    return;
                }
                _top = 0;
                _capacity = capacity;
            }
        void Push(int val)
            {

                if (_top == _capacity)
                {
                    _a = (int*)realloc(_a, sizeof(int) * (_capacity + 4));
                    if (_a == NULL)
                    {
                        perror("realloc fail");
                        return;
                    }
                }
                _a[_top] = val;
                _top++;
            }
        ~Stack()
        {
            free(_a);
            _top = _capacity = 0;
        }
private:
    int* _a;
    int _top;
    int _capacity;
};
int main()
{
    Stack S;
    Stack s1(s);
    return 0;
}

在这里插入图片描述

像栈之类的类在使用浅拷贝时会有多次析构的问题,会造成程序崩溃

自定义类型传值传参必须调用拷贝构造

自定义类型需要自定义构造拷贝函数

赋值两个已经存在的对象进行拷贝拷贝构造,是一个存在的对象,去创建另一个新对象

拷贝优化

拷贝对象优化

一个表达式,连续的构造(包括拷贝构造)可能会被合并

A f2()
{
    A aa;
    return aa;
    //优化直接构造
    return A(1);
}
int main()
{
    //拷贝
    A ret1=f2();
    //这是一个表达式,当aa返回临时对象之前编译器将它直接拷贝给了ret1
    A ret2;
    //赋值
    ret2=f2();
    //此时便不会优化了
    //优化条件需要二者都是构造,得是一个表达式
    return 0;
}
//看似两次拷贝构造,但是被编译器给优化了

赋值运算符重载

自定义类型不允许使用运算符直接进行比较

关键字operator后接需要重载的运算符符号

如bool operator<(参数)

不能创建新的操作符

重载操作符必须有一个类类型参数

运算符重载必须有一个参数是自定义类型

内置类型运算符,的含义不能改变,如‘+’运算符不能改成其他意思

不能改变操作符的操作个数

如,+ 有着两个操作数,但是因为有着隐藏的this指针存在,所以只需要重载函数只需要一个参数

  • ::
  • sizeof
  • ?:
  • .*
  • .

这几个是不能重载的

class Date
{
    public:
    Date(int year=1,int month=1,int day=1)
    {
        _year=year;
        _month=month;
        _day=day;
	}
    
   	private:
    int _year;
    int _month; 
    int _day;
}
//比较函数
//bool Compare(const Date&c1,const Date&c2)
//运算符重载
//将运算符重定义
bool operator<(const Date&c1,const Date&c2)
{
    if(c1._year<c2._year)
    {
        return  true;
    }
    else if(c1.year==c2.year&&c1.month<c2.month)
    {
        return true;
    }
    else if(c1.year==c2.year&&c1.month==c2.month&&c1.day<.c2.day)
    {
        true;
	}
    else
        return false;
}
int main()
{
    Date d1(2023,1,1);
    Date d2(2023,2,2);
    //不加括号的话会使cout<<d1先结合
    cout<<(d1<d2)<<endl;
   	return 0;
}
class Date
{
    public:
    Date(int year=1,int month=1,int day=1)
    {
        _year=year;
        _month=month;
        _day=day;
	}
    //其中this参数指向d1
    bool operator<(const Date&c2)
    {
            if(_year<c2._year)
            {
                return  true;
            }
            else if(_year==c2._year&&_month<c2._month)
            {
                return true;
            }
            else if(_year==c2._year&&_month==c2._month&&_day<c2._day)
            {
                true;
            }
            else
                return false;
    }
    
   	private:
    int _year;
    int _month; 
    int _day;
}
int main()
{
    Date d1(2023,1,1);
    Date d2(2023,2,2);
   	cout<<d1.operator(d2)<<endl;
   	return 0;
}
   //赋值运算符重载
    Date& operator=(const Date& d)
    {
        if (this != &d)
        {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
    
        return *this;
    }

注意赋值运算符重载

返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值

检测是否自己给自己赋值

返回this指针要符合连续赋值的含义

赋值运算符只能重载成类的成员,不能重载为全局函数

class Date
{
    public:
        //获取某年某月的天数
        int GetMonthDay(int year, int month)
        {
            static int a[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31};
            if (month == 2 && year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
            {
                return 29;
            }
            return a[month];
        }
    //默认构造
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    //拷贝构造
    Date(const Date& d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    //赋值运算符重载
    Date& operator=(const Date& d)
    {
        if (this != &d)
        {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
    
        return *this;
    }
    //析构函数
    ~Date()
    {
        _year = 0;
        _month = 0;
        _day = 0;
    }
    //日期+=天数
    Date& operator+=(int day)
    {
        _day += day;
        while (_day > this->GetMonthDay(_year, _month))
        {
            _day -= GetMonthDay(_year, _month);
            _month++;
            if (_month == 13)
            {
                _year++;
                _month = 1;
            }
        }
        return *this;
    }
    //日期+天数
    Date operator+(int day)
    {
        Date tmp(*this);
        tmp+= day;
        return tmp;
    }
    void print()
    {
        cout << _year <<"年" << _month << "月" << _day << "日"<<endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1(2023,7,31);
    Date d2=d1;
    //d1给d2是拷贝构造
    Date d3;
    d3=d1;
    //d1给d3是赋值重载
    return 0;
}

拷贝构造是使用同类对象初始化创建对象

赋值重载主要是把一个对象赋值给另一个对象

对于自定义类型,默认赋值重载,是以字节拷贝的方式赋值的,需要同样小心,多次析构的问题

前置++和后置++

    //前置++
    Date& operator++()
    {
        *this += 1;
        return *this;
    }
    //后置++
    Date operator++(int)
    {
        Date tmp(*this);
        *this +=1;
        return tmp;
    }

默认前置++不需要参数,而后置++需要一个int类型来进行占位,以便区分二者

前置–和后置–同理

const 成员函数

使用const修饰的成员函数,叫const成员函数,实际上修饰的是this指针,表示不能对类的任何成员进行修改

class Date
{
	public:
     void print()const;
    //等同
   	 void print(const Date*this);
    const int func();//修饰返回值无法修改返回值
    //效果等同于int func();返回一个拷贝值,这个值具有常性无法修改
    private:
      	int _year;
    	int _month;
    	int _day;
}

由于隐藏的this指针无法显示定义存在实参和形参所以只能将const放在表达式后方来修饰this

const对象无法调用普通成员函数,这是权限的放大

void Display()const==void Display(const Date*this)
void print()const;

void print();

//这两个函数可以同时存在,参数不同可以重载

缺省参数可以调用函数

class SeqList
{
  pubilc:
    int ope
  private:
    int* _a=(int*)malloc(sizeof(int)*10);
    size _top=0;
    size _capacity=0;
};

不能无脑加const

只读内部不需要修改的成员都可以加const

const对象可以调用非const成员函数吗?不能这是权限的放大

非const对象可以调用const成员函数吗?可以这是权限的缩小

const成员函数内可以调用其他非const成员函数吗?不可以这是权限的放大

非const成员函数内可以调用其它const成员函数吗?可以这是权限的缩小

取地址和const运算符重载

取地址运算符是默认成员函数,编译器自动生成

除非在特殊情况下不想被取出地址,需要自己编写,其他情况无需编写

class Date
{
    public:
    Date* operator&()
	{
 		return this 
    }
    const Date* operator&()const
    {
     	return this ;
    }
  	private:
        int _yaer;
        int _month;
        int _day;
};

隐式类型转换

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值 的构造函数,还具有类型转换的作用

c++98支持单参数隐式类型转换

c++11支持多参数隐式类型转换

#include<iostream>
class A
{
    public:
        //explicit A(int i)
    	//修饰构造函数,禁止类型转换
        A(int i)
            :_a(i)
            {}
        A(const A&a)
            :_a(a._a)
            {}
  	private:
    	int _a;
};
class B
{
    public:
    	B(int b1,int b2)
            :_b(b1)
            ,_bb(b2)
            {}
  	private:
    	int _b;
    	int _bb;
};
int main()
{
    A a1=1;
    //单参数构造函数的隐式类型转换
    //1调用一个构造函数生成一个临时对象,再用临时对象调用拷贝构造到a1
    //这个过程编译器会优化成用1直接构造
    A1&a = 1;
    //这是错误的因为类型转换都会生成临时变量,它具有常性,这是权限的放大
    //const A1&a=1;权限的平移
    
    //c++11 支持多参数隐式转换
    B b1(1,2);
    B b2={3,4};
	return 0;
}

关键字explicit修饰构造函数,禁止类型转换

友元

友元破坏了类的封装性,不适合多用

可以直接访问私有的成员,它是定义在类外部的普通函数,不属于类,但是需要在类的内部声明,声明要加friend关键字

友元函数

友元函数可以访问类的私有和保护成员,但它本身不是类的成员函数

友元函数不能用const来修饰

友元函数可以在类的任何地方声明,不受访问限定符的限制

一个函数可以是多个类的友元函数

友元函数的调用与普通函数调用相同

class Date
{
    public:
    //友元声明,声明只要放在类中,在哪都一样
  	friend ostream& operator<<(ostream& _cout, const Date& d);
    friend istream& operator>>(istream& _cin, Date& d);
        
    private:
        int _year;
        int _month;
        int _day;
//流插入流提取,不能定义成成员函数,因为有隐藏指针this,会导致符号指向错误
ostream& operator<<(ostream& _cout, const Date& d)
{
     _cout << d._year<< d._month<< d._day;
     return _cout; 
}
istream& operator>>(istream& _cin, Date& d)
{
     _cin >> d._year;
     _cin >> d._month;
     _cin >> d._day;
     return _cin;
}
int main()
{
    return 0;
}

友元类

友元关系是单向

如,B类可以访问A类的成员,但是A类不能访问B类成员

友元关系不能传递

如,C是B的友元, B是A的友元,不能说明C是A的友元

友元关系不能继承

class A
{
    friend class B;
    //声明B类为A的友元类,在B类中就可以访问A类中的私有成员变量
public:
    A(int a = 1, int b = 2, int c = 3)
        : _a(a)
        , _b(b)
        , _c(c)
    {}
private:
    int _a;
    int _b;
    int _c;
};
class B
{
public:
    B(int aa=0,int bb=0,int cc=0)
        : _aa(aa)
        , _bb(bb)
        , _cc(cc)
    {}
    void print()
    {
        cout << t._a << ' ' << t._b << ' ' << t._c << endl;
    }
private:
    int _aa;
    int _bb;
    int _cc;
    A t;
};
int main()
{
    B bb;
    bb.print();
	return 0;
}

内部类

一个类定义在另一个类的内部,这就叫内部类

内部类受外部类类域和访问限定符的限制

内部类是外部类的友元

内部类可以访问外部类,而外部类不能访问内部类

//这两个类各自独立
class A
{
public:
    class B
    {
    public:
        void func()
        {
            A aa;
            _b = aa._a;
        }
    private:
        int _b;
    };
private:
    int _a = 1;
};

匿名对象

//有名对象,生命周期在当前局部域
A aa(1);
//匿名对象,生命周期在这一行
A(7)

静态成员

int n=0,m=0;
class A
{
 	public:
   		A()
        {
          	++n;
            ++m;
		}
    	A(const A& t)
        {
            ++n;
            ++m;
        }
    	~A()
        {
            --m;
        }
    //静态成员函数无this指针
    static void print()
    {
        cout<<n<<' '<<m<<endl;
    }
    private:
    //放入类中
    //加上static使变量成为全局的属于所有对象
    //但是缺省值是在初始化列表使用的,而这种静态变量无法在初始化列表初始化
    //static	int n=0;
    //static	int m=0;
    //声明
    static	int n;
    static	int m;
};
//定义
int A::n=0;
int A::m=0;
int main()
{
    A a1;
    A a2;
    //如果类成员变量n,m是公共的,以下一切建立在公有的基础上
    //有这几种访问方式
    A::n;
    //通过A访问类域中的n
    a1.n; 
    A* ptr=nullptr;
    ptr->n;
    //ptr->n
    //上面两种方式是通过它们访问类域,从而找到n,m
    //而n,m是存在在静态区的
    //不用创建对象直接使用静态成员函数
    A::print();
    
}

全局变量会破坏封装,把它们放入类中,受到类的限制,但是这样会导致每个对象都有n,m

在n,m前加上static修饰成静态成员变量

静态成员函数没有this指针,所以不能用const来修饰

静态成员函数不能访问非静态变量,因为没有this指针

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值