day44——面向对象特征

一、封装

1.1 面向对象的三大特质

封装、继承、多态,如果问有四大特征,可以外加一个抽象

封装:将实现同一事物的所有的属性(成员变量)和行为(成员函数)封装到一个整体,我们称之为类(class)。类对外部信息有一个屏障作用。

1.2 C++中的类(class)

C++中的类,是由C++中的结构体演化而来的,只需要将struct改成关键字class,就定义了一个类

C++中类和结构体的区别:默认的权限不同,结构体中默认权限为public,类中默认权限为private

默认的继承方式不同,结构体的默认继承方式为public,类的默认继承方式为private

1.3 定义格式

class 类名
{
    public:
        功能的成员属性、函数
    protected:
        受保护的成员属性、函数
    private:
        私有的成员属性、函数
};

1> 类中的成员属性和成员函数分为不同的权限

public:该权限下的成员,可以在类内、子类中、类外被访问

protected:该权限下的成员,可以在类内、子类中直接被访问,类外不允许被访问

private:该权限下的成员,只能在类内被访问,子类、类外不允许被访问

2> 如果没有指定权限,则默认为私有权限

3> 一个类中,访问权限可以出现多次,也可以出现在任意地方,一般情况下,我们将同一权限下的成员写到一个关键字下面

4> 一个访问权限的范围,是从当前关键字开始到下一个关键字或者整个类的定义结束为止

5> 一般情况下,成员属性定义成私有的,成员函数定义成公有的

6> 类的访问权限是针对于类体而言的,不是针对于类对象的

#include <iostream>
 
 
using namespace std;
 
 
//将实现人的所有属性和行为都封装到一个整体,
//后期如果需要一个人,只需要使用该类实例化对象后,通过对象为整个程序服务
class Person
{
    string skill = "C++";          //技能
 
 
public:
    string name = "zhangsan";        //姓名    功能的属性
 
 
protected:
    int pwd = 123456;           //银行卡密码
 
 
private:
    int money = 1000000;         //私房钱
 
 
public:
    void show()
    {
        cout<<"  name = "<<name<<endl;        //公共权限下的成员,类内可以直接访问
        cout<<"  pwd = "<<pwd<<endl;          //受保护权限下的成员,类内可以直接访问
        cout<<"  money = "<<money<<endl;      //私有成员,类内可以直接访问
        cout<<"  skill = "<<skill<<endl;      //默认为私有成员,类内可以直接访问
    }
 
 
};
 
 
/******************************************主程序***************************/
int main()
{
    Person p1;          //使用类定义变量的过程,称为实例化对象,p1就是Person类的一个对象
 
 
    //通过p1使用成员
    cout<<"name = "<<p1.name<<endl;          //公共权限下的成员,类外可以直接访问
    //cout<<"pwd = "<<p1.pwd<<endl;            //收保护成员,类外无法直接访问
    //cout<<"money = "<<p1.money<<endl;      //私有成员,类内可以直接访问,类外无法访问
    //cout<<"skill = "<<p1.skill<<endl;      //默认为私有成员,类内可以直接访问,类外无法访问
    p1.show();                                 //类中公共权限下的成员,类外可以直接访问
 
 
    return 0;
}

练习:

自定义一个矩形类,包含私有成员属性 高(height)和宽(width),

公共成员函数:初始化宽、高函数

设置宽度函数

设置高度函数

获取宽度函数

获取高度函数

求矩形的周长(Perimeter)函数

求矩形的面积(Area)函数

#include <iostream>
 
 
using namespace std;
class rectangle
{
public:
    void init(int w, int h);       //初始化一个矩形
    bool set_width(int w);       //设置宽度
    bool set_height(int h);      //设置高度
    int get_width();          //获取宽度
    int get_height();          //获取高度
    int perimeter();           //获取周长
    int area();                 //获取面积
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
bool rectangle::set_width(int w)
{
    if(w<=0)
    {
        cout<<"提供的宽度不合法"<<endl;
        return 0;
    }
    width=w;
    return 1;
}
 
 
bool rectangle::set_height(int h)
{
    if(h<=0)
    {
        cout<<"提供的高度不合法"<<endl;
        return 0;
    }
    height=h;
    return 1;
}
 
 
int rectangle::get_width()
{
    return width;
}
 
 
int rectangle::get_height()
{
    return height;
}
 
 
int rectangle::perimeter()
{
    return 2*(height+width);
}
 
 
int rectangle::area()
{
    return height*width;
}
 
 
void rectangle::init(int w, int h)
{
    if(w<=0 || h<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    width = w;
    height = h;
}
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<r1.perimeter()<<endl;
    cout<<r1.area()<<endl;
 
 
 
 
    return 0;
}

练习:

在上面练习的基础上,写一个函数,可以比较两个矩形框是否相等

相等条件:宽==宽 高==高

#include <iostream>
 
 
using namespace std;
class rectangle
{
public:
    void init(int w, int h);       //初始化一个矩形
    bool set_width(int w);       //设置宽度
    bool set_height(int h);      //设置高度
    int get_width();          //获取宽度
    int get_height();          //获取高度
    int perimeter();           //获取周长
    int area();                 //获取面积
    bool judge_rect(rectangle &r);        //定义判断两个矩形框是否相对
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
bool rectangle::set_width(int w)
{
    if(w<=0)
    {
        cout<<"提供的宽度不合法"<<endl;
        return 0;
    }
    width=w;
    return 1;
}
 
 
bool rectangle::set_height(int h)
{
    if(h<=0)
    {
        cout<<"提供的高度不合法"<<endl;
        return 0;
    }
    height=h;
    return 1;
}
 
 
int rectangle::get_width()
{
    return width;
}
 
 
int rectangle::get_height()
{
    return height;
}
 
 
int rectangle::perimeter()
{
    return 2*(height+width);
}
 
 
int rectangle::area()
{
    return height*width;
}
 
 
//判断两个矩形框是否相等,成员函数版
bool rectangle::judge_rect(rectangle &r)
{
    if(r.width==width && r.height==height)
    {
        return true;
    }
 
 
    return false;
}
 
 
void rectangle::init(int w, int h)
{
    if(w<=0 || h<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    width = w;
    height = h;
}
 
 
//定义全局函数版本
bool judge_rect(rectangle &r1, rectangle &r2)
{
    //判断两个矩形是否相等
    if(r1.get_width()==r2.get_width() && r1.get_height()==r2.get_height())
    {
        return true;
    }
 
 
    return false;      //不相等
}
 
 
 
 
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<r1.perimeter()<<endl;
    cout<<r1.area()<<endl;
 
 
    //定义第二个矩形
    rectangle r2;
    r2.init(3,6);
 
 
    //if(judge_rect(r1, r2))
    if(r1.judge_rect(r2))            //r2.judge_rect(r1)
    {
        cout<<"两个矩形框相等"<<endl;
    }else
    {
        cout<<"两个矩形框不相等"<<endl;
    }
 
 
 
 
    return 0;
}

1.4 分文件编译

1> 头文件

#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <iostream>
 
 
using namespace std;
 
 
 
 
//头文件中主要放:类的声明、全局函数的声明、全局变量的定义、类型重命名、宏定义
class rectangle
{
public:
    void init(int w, int h);       //初始化一个矩形
    bool set_width(int w);       //设置宽度
    bool set_height(int h);      //设置高度
    int get_width();          //获取宽度
    int get_height();          //获取高度
    int perimeter();           //获取周长
    int area();                 //获取面积
    bool judge_rect(rectangle &r);        //定义判断两个矩形框是否相对
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
 
 
 
 
bool judge_rect(rectangle &r1, rectangle &r2);        //全局函数的声明
 
 
#endif // RECTANGLE_H

2>源文件

#include"rectangle.h"
 
 
bool rectangle::set_width(int w)
{
    if(w<=0)
    {
        cout<<"提供的宽度不合法"<<endl;
        return 0;
    }
    width=w;
    return 1;
}
 
 
bool rectangle::set_height(int h)
{
    if(h<=0)
    {
        cout<<"提供的高度不合法"<<endl;
        return 0;
    }
    height=h;
    return 1;
}
 
 
int rectangle::get_width()
{
    return width;
}
 
 
int rectangle::get_height()
{
    return height;
}
 
 
int rectangle::perimeter()
{
    return 2*(height+width);
}
 
 
int rectangle::area()
{
    return height*width;
}
 
 
//判断两个矩形框是否相等,成员函数版
bool rectangle::judge_rect(rectangle &r)
{
    if(r.width==width && r.height==height)
    {
        return true;
    }
 
 
    return false;
}
 
 
void rectangle::init(int w, int h)
{
    if(w<=0 || h<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    width = w;
    height = h;
}
 
 
//定义全局函数版本
bool judge_rect(rectangle &r1, rectangle &r2)
{
    //判断两个矩形是否相等
    if(r1.get_width()==r2.get_width() && r1.get_height()==r2.get_height())
    {
        return true;
    }
 
 
    return false;      //不相等
}

3> 主程序

#include"rectangle.h"
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<r1.perimeter()<<endl;
    cout<<r1.area()<<endl;
 
 
    //定义第二个矩形
    rectangle r2;
    r2.init(3,6);
 
 
    //if(judge_rect(r1, r2))
    if(r1.judge_rect(r2))            //r2.judge_rect(r1)
    {
        cout<<"两个矩形框相等"<<endl;
    }else
    {
        cout<<"两个矩形框不相等"<<endl;
    }
 
 
 
 
    return 0;
}

1.5 this指针

1> this的内含:是类的非静态成员函数所拥有的一个隐藏的形参指针,指代该对象本身起始地址,哪个对象使用我,我就表示哪个对象

2> this指针的格式:类名 * const this;

3> 对于this指针而言,如果没有显性使用该指针,仅仅只是使用成员,那也是默认使用了this指针

3> this指针的使用场景

场景1:当成员函数的形参名和成员变量同名时,可以使用this指针进行区分

场景2:在拷贝复制函数中,需要返回自身引用时,也必须使用this指针(后面讲)

#include <iostream>
 
 
using namespace std;
class rectangle
{
public:
    void init(int width, int height);       //初始化一个矩形
 
    void show()
    {
        cout<<"width = "<<width<<"  height = "<<height<<endl;
    }
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
 
 
void rectangle::init(int width, int height)
{
    if(width<=0 || height<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    this->width = width;             //可以通过this指针改变this所指向内存中的值
    this->height = height;
 
 
    cout<<"this = "<<this<<endl;
 
 
    //this = NULL;          //不能更改指针的指向
 
 
}
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<"&r1 = "<<&r1<<endl;         //r1的地址
    r1.show();
 
    //在实例化一个对象
    rectangle r2;
    r2.init(2,2);
    cout<<"&r2 = "<<&r2<<endl;         //r2的地址
 
    return 0;
}

1.6 类的大小

1> 一个空的类的大小为1字节,用于占位使用,如果后期有成员变量的加入,则会将这一字节的空间分配出去

2> 类中的成员函数不占类的空间大小,但是成员属性会占用类的大小

3> 成员属性分配空间的大小遵循字节对齐原则

4> 如果类中有虚函数(后期讲),那么类中就会多一个虚指针的大小

5> 如果该类是虚继承(后期讲)自父类,那么该类中也会增加一个虚指针的大小

#include <iostream>
 
 
using namespace std;
 
 
class Temp
{
public:
    int num;      //整型成员变量
 
 
    void show()
    {
        cout<<"num = "<<num<<endl;
    }
 
 
    //类中有虚函数时,就会多分配一个虚指针的空间
    virtual void display()
    {
        cout<<"我是虚函数"<<endl;
    }
 
 
    virtual void display(int )
    {
        cout<<"我是虚函数"<<endl;
    }
 
 
};
 
 
int main()
{
    cout<<"sizeof(Temp) = "<<sizeof(Temp)<<endl;
 
    return 0;
}

二、类中特殊的成员函数(非常重要)

2.1 类中提供的特殊成员函数

1> 特殊的原因:如果用户不显性定义这些函数,系统也会自动提供这些函数,如果用户显性定义了这些函数,那么系统就不提供了。

无论这些特殊的成员函数,是系统提供的还是用户字节定义的,都无需用户手动调用,特殊的时机,系统会自动调用

2> 构造函数、析构函数、拷贝构造函数、拷贝复制函数、移动构造函数、移动复值函数、取地址运算符重载

2.2 构造函数

1> 功能:

使用类去实例化对象时,为对象进行资源的申请以及初始化使用的

2> 定义格式

1、构造函数没有返回值
2、函数名与类同名
3、访问权限,一般为public
4、 类名(形参列表){函数体内容}

3> 调用时机:

当使用类实例化对象时,系统自动调用,无需手动调用

1、栈区空间:使用类实例化对象时,系统自动调用

类名 变量名(实参); //此时就调用的构造函数

2、堆区空间:只有在使用new申请空间时,自动调用构造函数

类名 *指针名; //此时仅仅只是定义一个指针变量,并没有为对象分配空间

指针名 = new 类名(实参); //此时调用的构造函数

#include <iostream>
 
 
using namespace std;
 
 
class Stu
{
public:
    Stu()
    {
        cout<<"Stu的构造函数"<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    return 0;
}

4> 构造函数分为有参构造和无参构造函数,有参构造函数可以为成员属性进行初始化,这些构造函数之间构成重载关系

5> 一个类中可以有多个构造函数,每个对象仅仅只会调用一个构造函数

6> 如果类中没有定义构造函数,那么,系统会自动提供一个无参构造函数,用于对对象空间的申请,如果程序员自己定义了构造函数,系统就不再提供那个无参构造了,如果还想使用无参构造,需要自己定义一个无参构造

#include <iostream>
 
 
using namespace std;
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
 
 
public:
    //无参构造
    Stu()
    {
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a)
    {
        this->name = n;
        this->age = a;
        cout<<"Stu::有参构造"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
 
    //申请一个对象,调用有参构造
    Stu s2("zhangsan", 18);          //此时调用了有参构造
    s2.show();
    cout<<"**************************************"<<endl;
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    return 0;
}

7> 构造函数初始化对象可以使用初始化列表完成

使用方式:类名(形参1,形参2,。。。形参n):成员1(形参1),成员2(形参2),。。。成员n(形参n)

{函数体内容}

说明:在构造函数的小括号后,由冒号引出初始化列表,括号外时成员变量,括号内是形参

#include <iostream>
 
 
using namespace std;
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
 
 
public:
    //无参构造
    Stu()
    {
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a)
    {
        this->name = n;         //对成员的赋值操作
        this->age = a;
        cout<<"Stu::有参构造1"<<endl;
    }
 
 
    //定义有参构造:使用初始化列表完成对成员的初始化工作
    Stu(string n, int a, double s):name(n),age(a),score(s)
    {
        cout<<"Stu::有参构造2"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
 
    //申请一个对象,调用有参构造
    Stu s2("zhangsan", 18);          //此时调用了有参构造
    s2.show();
    cout<<"**************************************"<<endl;
 
 
 
 
    //申请一个对象,调用有参构造
    Stu s3("lisi", 20, 99.8);
    s3.show();
    cout<<"**************************************"<<endl;
 
 
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    return 0;
}

8> 必须使用初始化列表的情况

1、当构造函数的形参名和成员变量名同名时,可以使用初始化列表来解决

2、当类中有const修饰的成员变量时,对该变量也必须进行初始化,使用初始化列表解决

3、当类中有引用成员时,对该成员的操作也必须使用初始化列表完成

4、当类中有其他类的成员子对象时,对该成员的操作也必须使用初始化列表完成,如果没有使用初始化列表调用有参构造,则系统会自动调用成员子对象的无参构造

#include <iostream>
 
 
using namespace std;
 
 
class Toy
{
public:
    Toy() {cout<<"Toy::无参构造"<<endl;}
    Toy(string n):name(n) {cout<<"Toy::有参构造"<<endl;}
 
 
private:
    string name;
 
 
};
 
 
 
 
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
    const int value;        //类中有const类型的成员
    int &key;             //类中有引用成员
    Toy t;               //类中有其他类的成员子对象
 
 
public:
    //无参构造
    Stu():value(1314), key(*(new int(520))), t("hello kity")
    {
 
 
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a, int &k):value(1314), key(k)
    {
        this->name = n;         //对成员的赋值操作
        this->age = a;
        cout<<"Stu::有参构造1"<<endl;
    }
 
 
    //定义有参构造:使用初始化列表完成对成员的初始化工作
    Stu(string name, int age, double score, int &k):name(name),age(age),score(score),value(1314),key(k)
    {
        cout<<"Stu::有参构造2"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
};
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
    return 0;
}

2.3 析构函数

1> 功能:在对象消亡时,用于给对象回收空间使用的

2> 定义格式

1、没有返回值
2、函数名:类名前加个波浪线  ~类名
3、权限:一般为public
4、没有参数,所以,一个类中只有一个析构函数,不能进行重载
5、格式:   ~类名()

3> 调用时机:当对象的生命周期结束后,用于回收内存空间

栈区:当栈空间释放后,系统会自动调用该类的析构函数

堆区:当使用delete关键字释放对象空间时,系统自动调用

4> 如果没有手动定义析构函数,系统会提供一个析构函数,用于回收类对象的空间,如果手动定义了析构函数,那么,系统就不再提供默认的析构函数了。

#include <iostream>
 
 
using namespace std;
 
 
class Toy
{
public:
    Toy() {cout<<"Toy::无参构造"<<endl;}
    Toy(string n):name(n) {cout<<"Toy::有参构造"<<endl;}
 
 
private:
    string name;
 
 
};
 
 
 
 
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
    const int value;        //类中有const类型的成员
    int &key;             //类中有引用成员
    Toy t;               //类中有其他类的成员子对象
    int *ptr;         //指针成员
 
 
public:
    //无参构造
    Stu():value(1314), key(*(new int(520))), t("hello kity"), ptr(new int(666))
    {
 
 
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a, int &k):value(1314), key(k)
    {
        this->name = n;         //对成员的赋值操作
        this->age = a;
        cout<<"Stu::有参构造1"<<endl;
    }
 
 
    //定义有参构造:使用初始化列表完成对成员的初始化工作
    Stu(string name, int age, double score, int &k):name(name),age(age),score(score),value(1314),key(k)
    {
        cout<<"Stu::有参构造2"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
 
 
    //定义析构函数
    ~Stu()
    {
        delete ptr;          //释放指针的空间
        cout<<"STU::析构函数"<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
 
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    //释放ptr的空间
    delete ptr;       //此时会调用析构函数
 
 
    return 0;
}

作业

仿照string类,实现myString

#include <iostream>
#include <cstring>

class myString
{
private:
    char *str;          //记录c风格的字符串
    int size;            //记录字符串的实际长度

public:
    //无参构造
    myString():size(10)
    {
        str = new char[size];         //构造出一个长度为10的字符串
        str[0] = '\0';                // 初始化为空字符串
    }

    //有参构造
    myString(const char *s)
    {
        size = strlen(s);             // 计算传入字符串的长度
        str = new char[size + 1];     // 分配足够的内存空间,加1是为了存储结束符'\0'
        strcpy(str, s);               // 复制传入的字符串到新分配的内存空间
    }

    //判空函数
    bool empty() const
    {
        return str[0] == '\0';
    }

    //size函数
    int length() const
    {
        return size;
    }

    //c_str函数
    const char* c_str() const
    {
        return str;
    }

    //at函数
    char at(int index) const
    {
        if (index >= 0 && index < size)
        {
            return str[index];
        }
        else
        {
            throw std::out_of_range("Index out of range");
        }
    }

    //二倍扩容
    void doubleCapacity()
    {
        int newSize = size * 2;
        char *newStr = new char[newSize + 1]; // 分配新的内存空间,加1是为了存储结束符'\0'
        strcpy(newStr, str);                  // 复制原字符串到新内存空间
        delete[] str;                          // 释放原内存空间
        str = newStr;                          // 更新指针指向新的内存空间
        size = newSize;                        // 更新字符串长度
    }
};

int main()
{
    myString s1;
    myString s2("Hello, world!");

    std::cout << "s1是" << (s1.empty() ? "空" : "非空") << std::endl;
    std::cout << "s2是" << (s2.empty() ? "空" : "非空") << std::endl;

    std::cout << "s1的长度:" << s1.length() << std::endl;
    std::cout << "s2的长度:" << s2.length() << std::endl;

    std::cout << "s2的内容:" << s2.c_str() << std::endl;

    std::cout << s2.at(7) << std::endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值