#3[补]:C++:数据保护;

     公用数据的保护:

    有些数据往往是共享的,此时误操作可能会改变数据的状况;可以使用const将有关的数据定为常量;

1. 常对象:

    定义 :
Time const t1(12,57,29);  ==  const Time t1(12,57,29);

    一般形式为:    类名 const 对象名(实参表列) 或 const 类名 对象名(实参表列)

注:
    1. 常对象中成员变量为常变量且必须有初值;
    
    2. 此时在所有的场合之下,所有的数据成员的值都不可以改变,
 
    3. 如果一个对象被定义为常对象,则不能调用该对象的非 const类型的成员函数(构造和析构除外)!!
例:
    const Time t1(10,58,30);
    t1.get_time();        //    错误,函数为非 const 类型的成员函数;

    这是为了防止这些函数修改常对象中的成员的值;

所以当需要引用常对象中的数据成员时,需要将成员函数声明为 const ,如:  void get_time() const;

    这表示常成员函数。  常成员函数可以访问常成员对象中的数据成员,但是不可以修改(只读);

有时为了编程需要,一定要修改常对象中的某个成员的值,此时可以做特殊处理:

    mutable int count;

    
即把 count 定义为可变的数据成员,此时可以用声明为 const 的成员函数来修改它;

2. 常对象成员:
 
    可以在声明时把成员声明为 const 类型,包括常数据成员 和 常成员函数;

    1. 常数据成员:
        
        其作用和一般常变量相似,用 const 来声明常数据成员;
注:
    只能通过构造函数的参数初始化表对常数据成员进行初始化!!!!

如:


class Time
{
    const int hour;
};

Time :: Time(int h)
{
    hour = h;            //    此时是非法的,因为常数据成员是不可以被赋值的!!
}                        

Time :: Time(int h) : hour(h){}    //    通过参数初始化表对常成员变量进行赋值;

    当一个类声明了一个数据成员为 const 时, 该类的所有成员中的该数据成员的值都不可变(可以不同)


    2. 常成员函数:


            对于一般的成员函数,可以引用本类中的非 const 成员和修改他们;
            但是对于 常成员函数,只能引用本类中的数据成员,但是不能修改他们;
例:
    void get_time() const;

    const 是函数类型的一部分,在声明和定义函数的时候都必须要有 const 关键字,调用时可没有;

注:
    常成员函数可以引用 const 数据成员(非const函数不可),也可以引用非 const 数据成员;
    
    const 数据成员可以被 const成员函数引用,亦可以被非 const 的成员函数引用;
    
常成员函数的应用:

 
    1. 如果在一个类中,有些数据成员的值需要改变,而另一些数据成员的值不允许变化:
    
        可以将一部分成员声明为 const ,以保证其值不会被改变。
        
        此时非 const 类型的函数可以引用这些数据成员的值,并修改非 const 数据成员的值;

    2. 如果要求所有的数据成员的值都不可改变:
    
        则可以将对象为 const ,然后再用 const 成员函数引用成员,起到双保险作用!
        
    3. 如果已经定义了一个常对象
    
        此时只能调用其中的 const 型的成员函数,而不能调用非const类型的成员函数(不论是否会修改值);
        
        如果需要访问对象中的数据成员,可将常对象中的所有成员函数都定义为 const 类型;
        
注:

1. 常对象只保证数据成员的值不被修改,但是如果成员函数未加 const声明,编译系统会当做非const处理;

2. 常成员函数不能够调用另一个非 const 函数!;


      指向对象的常指针

    将指向对象的指针变量声明为 const 即,指针始终保持初值,指向不改变;

如:
    Time t1(12,53,30),t2;    
    Time *const pt = &t1;        //    定义一个常指针,指向t1
    
    pt = &t2;        //    错误,常指针的指向不可改变;

定义指向对象的常指针的一般形式

    类名 * const 指针变量名 = 对象地址;

注:    对象的常指针的指向不可改变,但是可以改变原对象中的值!

    往往用常指针来作为函数的形参,此时函数在执行过程中,指针变量的值始终不变;
    此时如果认为改变该形参的值,则编译系统将会报错,避免错误的发生!


      指向常对象的指针变量:

指向常变量的指针变量:
    
例:    const char *ptr;    //    指向常变量的指针变量;
注:    *const ptr;            //    常指针!

    原式表示指针指向的是一个常变量,不能通过指针来改变它的值;
    
定义的一般形式为:
    
    const 类型名 * 指针变量名;

说明:
    1. 如果一个变量已经被声明为常变量:
        
        只能用指向常变量的指针指向它,不能用非 const 类型的指针指向;
如:
    const char c[] = "Boy";
    const char *ptr;
    ptr = c;        //    注意,此处为数组名,已经是首地址!
    
    char *p2 = c;    //    非法,因为数组 c 为常变量!!


    2. 指向常变量的指针除了可以指向常变量,还可以指向未被声明的 const 的变量(非 const):
    
        此时不能通过指针来改变他们的值!
如:
    char c1 = 'a';
    const char *p;
    p = &c1;        //    定义一个 const 指针指向一个非 const 类型的变量;
    
    *p = 'b';        //    错误,试图用 const 指针改变一个变量;
    c1 = 'b';         //    正确,原变量为 非 const 类型;
    

    3. 如果函数的形参是指向非 const 类型的指针:
    
        实参只能使用指向非 const 类型的指针,而不能使用 const 类型的指针;
        
        这样在执行程序的过程中可以改变形参指针所指向的变量的值!

    4. 如果函数的形参是指向 const 类型的指针:
        
        在函数的执行过程中,不可以改变指针变量所指向的变量的值,
        
        因此允许实参是指向 const 或 非 const 类型的指针;

如:
    const char str[] = "Boy";
    void fun(char *ptr);     //    函数声明为行参是 非 const 类型的指针;
    fun(str);                 //    非法,实参是 const 类型;

即对于指向常变量的指针变量:

    指向常变量的指针变量可以指向 const 和 非 const 类型的变量;
    
    但是指向非 const 类型变量的指针变量只能指向 非 const 型变量;



指向常对象的指针变量:同理

     1. 如果一个对象已经被声明为常对象:
         
         只能用指向常对象的指针来指向它,而不能用一般的(非 const)指针变量来指向它;

     2. 如果已经定义了一个指向常对象的指针变量:
    
         并使它指向一个非 const 类型的对象,则其指向的对象的值不可以通过指针改变(原变量值可改变)
例:
    Time t1(12,24,43);
    const Time *p = &t1;
    
    t1.hour = 19;    //    正确;
    p->hour = 19;    //    错误,该指针为一个指向常变量的指针;
    
注:
    Time *const p;    //    指向对象的常指针变量,只能指向一个固定的对象,不能改变指向的对象;
    const Time *p;    //    指向常对象的指针变量,可以指向 非 const 此时不能改变值;
    
    
     3. 指向常对象的指针最常用于函数的形参,目的在于保护形参指针所指向的对象(不会改变指向);

例:

int main()
{
	void fun(const Time *p);	//	形参是指向常对象的指针变量; 
	Time t1(12,24,12);			
	
	fun(&t1);		//	实参是对象t1(非 const)的地址,合法; 
	return 0;
}	

void fun(const Time *p)
{
	p->hour = 18;		//	错误,试图用指向常变量的指针改变值; 
	cout << p->hour <<endl;
} 

           对象的常引用:

        对于一个变量的引用,其实就是一个别名!
    
        如果形参为变量的别名,实参为变量名,则在调用函数时,虚实结合于同一个区域,
        此时可以通过引用名直接操作;

class Time
{
	public:
		Time(int h,int m,int s) : hour(h),minute(m),sec(s) {}
		int hour;
		int minute;
		int sec;
};

void fun(Time &t)
{
	t.hour = 18;
}
	
int main()
{
	Time t1(10,22,34);		//	此时hour 为 10; 
	fun(t1);		//	修改利用引用 把hour修改为 18; 
	cout << t1.hour << endl;
	return 0;
}

            对象的动态建立和释放:

     有时人们希望在需要用到对象时才建立对象,在不需要对象时就撤销它,释放内存;(如链表)    
    
     对象也可以使用 new 和 delete 动态建立和撤销一个对象;
    
例:
    new Box;
    
    此时建立了一个内存空间来存储一个 Box 型变量,并调用其构造函数
    
    但此时用户不能够访问这个对象,因为对象既没有变量名也没有获得地址 ----无名对象
    
所以需要定义一个指针变量:

    Box *pt;
    pt = new Box;    或  Box *pt = new Box(12,25,18);
    
    此后在程序中便可以通过 pt 指针来访问该对象;
    
    在不需要使用由new 产生的对象的时候,可以用delete 运算符予以释放;
注:
    delete pt;
    
    这就撤销了 pt 指向的对象,但是要注意指针变量的当前指向,以免删错了对象;
    
    执行delete 后,自动执行析构函数,以完成善后工作!

      对象的赋值和复制:
1. 对象的赋值:

    如果对于一个类,定义了两个或者多个对象,可以用 = 互相赋值!
注:
    这里的赋值指的是数据成员的赋值,是通过 = 运算符的重载实现的,将一个对象的成员值一一复制;
    
一般形式 : 对象名 1 = 对象名 2; (两个对象属于同一个类);

如:

class Box
{
	public:
		Box(int l = 10,int w = 10,int h = 10);
		int volume();
		
	private:	
		int length;
		int width;
		int height;
		
}; 

Box :: Box(int l,int w,int h)
{
	length = l;
	width = w;
	height = h;	
}

int Box :: volume()
{
	return (length * width * height);
}

int main()
{
	Box box1(15,20,30);
	
	cout << "The volume of the box is :" << box1.volume() << endl;
	Box box2 = box1;
		
	cout << "The volume of the box is :" << box2.volume() << endl;
	
	return 0;
}
说明:
    1. 对象的赋值只对其中的数据成员赋值,而不对成员函数赋值;
    
    2. 类的数据成员中不能够包括动态分配的数据,否则在赋值时可能会出现严重错误!
    


2. 对象的复制:


    用一个 “已有的 ” 对象快速的复制出多个相同的对象;
如:
    Box box2(box1);
    
    作用为 用一个已有的对象 box1 克隆出另一个对象 box2;
    
一般形式为:     类名 对象名1( 对象名2 );


     与前面定义对象的不同点在于: 括号中不再是参数,而是一个对象;
    
    在建立一个新的对象的时候,调用一个特殊的构造函数复制构造函数;
    
Box :: Box(const Box &b)
{
    height = b.height;
    ...
    ...
}

    由于在括号中为一个对象,此时在定义一个新的对象的时候就调用复制构造函数;
注:
    用户可以自己定义一个复制构造函数,否则系统将自动生成一个复制构造函数,仅仅复制数据;
    
C++ 还提供一种用赋值号代替:

    Box box1 = box2;    一般形式 : 类名    对象名 1 = 对象名 2;
    
其作用都是调用复制构造函数;


注:    
    对象的赋值和对象的复制是两个不同的概念
    
      对象的赋值时建立在两个对象都已经存在的基础之上,是 = 运算符的重构;
      
      而对象的复制是一个对象从无到有的过程,需要调用复制构造函数;
        


            静态成员:

    有时人们希望有某个数据为所有对象所共有(如: 平均分,n个总和等),这样可以实现数据公有;
例:
    n 个学校除了教学楼,实验室等,公有一个运动场;

1. 静态数据成员:

    静态数据成员是一种特殊的数据成员,以关键字static 开头;
例:

class Box
{
    public:
        int volume();
        
    private:
        static int height;
        int ...;
        ...
};

    此时 height 在各个对象中的值都是一样的,所有的对象都可以引用它;
    
说明:
    
    1. 静态成员变量的值在所有对象中都是一样的,所以对象都可以引用他;
    
    2. 静态的数据成员在内存中只占一个存储空间(与函数类似)

    3. 如果改变静态数据成员的值,则在所有对象中的值都将改变;
    
    4. 静态成员变量是在所有对象之外单独开辟空间,只要在类中定义了,即使不定义对象,也分配空间;
    
    5. 如果在一个函数中定义了静态变量,在函数结束时,不随对象的撤销而释放!!
    
        静态数据成员是在程序编译时被分配空间的,到程序结束时才释放空间;
        
    6. 静态数据成员可以初始化,但是必须在类体外进行初始化!!!
例:
     int Box :: height = 10;    //    表示对静态数据成员初始化;
    
一般形式 : 数据类型 类名 :: 静态数据成员名  = 初值; (不必再初始化语句中加入static)

注:
    不能够用参数初始化表对静态数据成员变量初始化:
    
        Box(int h,int w,int len) : height(h){}    //    错误!
    
    7. 静态数据成员既可以通过对象名引用(a.height = 10) ,也可以用类名引用 (Box :: height = 10);

例:

class Box
{
	public:
		Box(int l,int w);
		int volume();
		
		static int height;
		int length;
		int width;
};

Box :: Box(int l,int w)
{
	length = l;
	width = w;
}	

int Box :: volume()
{
	return (length * width * height);
}

int Box :: height = 10;

int main()
{
	Box a(10,20),b(20,20);
	
	cout << a.height << endl;
	cout << b.height << endl;
	
	cout << Box :: height << endl;
	
	cout << "The volume of the box is :" << a.volume() << endl; 
	
	return 0;
}
注: 1. 即使在没有定义对象的情况下,也是可以通过类名引用公用的静态变量!!
    
         因为静态数据成员不是属于某个对象,而是属于类的!!



 
2. 静态成员函数:

    成员函数也可以定义为静态的,在声明前加上 static 即可;
如:

    static int volume();    
    
    和静态成员相同,静态成员函数也是类的一部分,可以用类名或对象名调用:
    
如:
    Box :: volume();    ||    a.voulume();

    与静态成员不同,静态成员函数的作用是为了能够处理静态数据成员;

    当调用一个对象的成员函数(非静态函数)时,系统会把该对象的起始地址赋值给this指针。
    但是静态成员函数并不属于某一对象,它与任何对象都无关,所以没有this指针!!
    
所以,静态与非静态函数的区别在于静态成员函数没有this指针!
    
     静态成员函数不能够访问非静态变量!!
    
     然而静态成员函数可以直接引用本类中的静态数据成员,因为他们同属于类的,可以直接引用!

    所以一般静态成员函数是用来访问静态数据成员,而不访问非静态成员;

例:
    一个静态成员函数中有:
        
        cout << height << endl;        //    height 为 static 正确;
 
        cout << width << endl;         //    width 是非静态成员变量,错误!


注:
     并不是静态成员函数一定不能访问非静态成员,只是不能默认访问!
     但是还是可以用加对象名和成员运算符进行访问!!
    
例:

Student :: Student()
{
	cout << "Please Input the data : (number,age,score)" << endl;
	cin >> num >> age >> score;
	cout << "Data is loaded successfully!" << endl;
}

float Student :: Average()		//	定义静态成员变量,只在声明时有 static 、 
{
	return (sum/count);
}

void Student :: Total()
{
	sum += score;
	count++;
}

int Student :: count = 0;
float Student :: sum = 0.0;

int main()
{
	class Student stu[3] = 
	{
		Student(1001,18,96.5),
		Student(1002,19,94),
		Student(1003,18,92)
	};
	cout << "Please Input the number of the Student :" << endl;
	int n;
	cin >> n;
	for(int i = 0;	i < n;	i++)
	{
		stu[i].Total();
	}

	cout << "The average of the score is :" << stu[0].Average() << endl;
	cout << "The average of the score is :" << stu[1].Average() << endl;
	cout << "The average of the score is :" << stu[2].Average() << endl;
	cout << "The average of the score is :" << Student :: Average() << endl;
	
	return 0;
}

            友元 :

    在一个类中有 public 和 private 之分,在类外可以访问公用成员,而只有本类的函数可以访问私有;
    
    对于友元 friend 可以访问声明与其有好友关系的类中的数据成员;
    
      1. 友元函数:

    如果在类外定义了一个函数(不属于本类成员函数可以是别的类成员或非成员函数):
    
        在本类进行声明时,此函数就成为本类中的友元函数;
        
        一个类的友元函数可以访问这个类的私有成员;
        
1. 把普通函数声明为友元函数:
 
class Time
{
	public:
		Time(int ,int ,int );
		friend void Display(Time &);	//	定义为友元函数; 
		
	private:
		int hour;
		int minute;
		int sec;
	
}; 

Time :: Time(int h,int m,int s)
{
	hour = h;
	minute = m;
	sec = s;
}

void Display(Time &t)
{
	cout << t.hour << ":" << t.minute << ':' << t.sec << endl;	//	输出一个 Time 型的数据; 
}

int main()
{
	Time t1(12,35,40);
	Display(t1);		//	因为是友元函数,所以可以使用 t1 里的数据成员; 
		
	return 0;
}
2. 友元成员函数:

    friend函数不仅可以是一般函数, 还可以是另一个类中的成员函数:

   

class Date;		//	对 Date 类型的提前引用声明; 

class Time
{
	public:
		Time(int ,int ,int );
		void Display(Date &);
		
	private:
		int hour;
		int minute;
		int sec;
						
}; 

class Date
{
	public:
		Date(int ,int ,int );
		friend void Time :: Display(Date &);
	
	private:
		int month;
		int day;
		int year;	
};

Time :: Time(int h,int m,int s) : hour(h),minute(m),sec(s) {}

void Time :: Display(Date &d)
{
	cout << d.year << '/' << d.month << '/' << d.day << endl;
	cout << this->hour << ":" << this->minute << ":" << this->sec << endl;
}

Date :: Date(int y,int m,int d) : month(m),day(d),year(y) {}

int main()
{
	Time t1(12,30,15);
	Date d1(2018,1,12);
	
	t1.Display(d1);
	return 0;
}
说明:
  在本例中定义了两个类 Data 和 Time。第三行是对Data类的提前声明,因为在Time需要提前引用Data的内容;
    
  而对 Data 的定义在 Time 之后,并且在 Data 的定义中又引用了 Time 所以也不能仅把定义调换位置;
    
提前引用:
    
    即在正式声明一个类以前,先声明一个类名,表示此类将在稍后声明;

注:    但是不能在提前声明之后,定义一个对象;(必须在正式声明之后才可以定义对象);

 
3. 一个函数可以被多个类声明为“朋友”,这样可以引用多个类中的私有数据;



            友元类:

        不仅可以将一个函数声明为一个类的朋友,也可以将一个类( 类B )声明为另一个类的朋友( 类A )。
        
        这时 B就是 A 的友元类,友元类B 的所有函数都是类 A 的友元函数,可以访问 A 的所有成员;
        
定义方法:
    在类 A 的定义体中用以下语句声明:
    
    friend B;
    
一般形式 :    friend 类名;

例: 可以把 Time类,声明为 Data 类的友元类,这样Time的所有函数都可以访问Data
        
说明:
    
    1. 友元的关系是单向的而不是双向的! 如果仅仅声明了 B为A 的友元类,A 中的函数不可以访问B ;
    
    2. 友元的关系不能传递, B 是 A 的友元 ,C是 B的友元,不能表示 C 是 A 的友元;
    
        应当在 A 中 再次声明 C是A 的友元;
        
    3. 一般情况下, 一般不声明友元类而是声明友元函数,这样安全一些;


      类模板:

        C++ 中允许使用函数模板,对于功能相同而数据类型不同的一些函数,不必一一去定义;
        
        可以定义一个可对任何数据类型进行操作的函数模板,在调用时系统会根据实参的类型,
        
        取代模板的类型参数,得到具体的参数;
        
对于类的声明,有时也仅仅是数据类型的不同,此时可以使用类模板:

如:

class Compare_int
{
    public:
        Compare(int a,int b)
        {
            x = a; y = b;
        }
        int max()
        {
            return ( (x > y) ? x : y );
        }
        int min()
        {
            return ( (x < y) ? x : y );
        }
        
    private:
        int x,y;
        
};

其作用是对两个整数进行比较,结果可以用 max 和 min 函数来表述。

对于浮点型作比较,则需要用另外一个类声明:

class Compare_float
{
    public:
        Compare(float a,float b)
        {
            x = a; y = b;
        }
        int max()
        {
            return ( (x > y) ? x : y );
        }
        int min()
        {
            return ( (x < y) ? x : y );
        }
        
    private:
        float x,y;
        
};

    此时可以声明一个 通用的类模板, 他可以有一个或者多个虚拟的类型参数;

如:

template <typename numtype>

class Compare
{
    public:
        Compare(numtype a,numtype b)
        {
            x = a; y = b;
        }
        numtype max()
        {
            return ( x > y ) ? x : y;
        }
        numtype min()
        {
            return ( x < y ) ? x : y;
        }
        
        private:
            numtype x,y;
    
};

说明:
    类模板 和之前的声明有所不同:
    
    1. 声明类模板时要增加一行; template< typename XXX >;
    
    2. 原有的类型名 int 换成虚拟类型参数名 typenum。在建立对象的时候,如果指定float 型,则
    
        系统会用 float 取代所有的 typenum;
        

      类模板的使用:

先回顾一下利用类来定义对象的方法:
    
    Compare_int cmpl(4,7);    //    Compare_int 为一个类名;
    
类模板定义一个对象的方法与之类似,但是不能直接写为:

    Compare cmpl(4,7);         //    错误!;
    
必须用实际的类型名来指代虚拟的类型:

    Compare <int> cmpl(4,7);
    
    即在模板名后的尖括号中指定实际的类型名;
    
    在进行编译时,编译系统就用 int取代模板中的类型参数 typenum;        

例:

    声明一个类模板,实现不同数据的比较,求最大最小值;

template <typename numtype>

class Compare
{
	public:
		Compare(numtype a,numtype b)
		{
			x = a;
			y = b;
		}
	
		numtype max()
		{
			return ( (x > y) ? x : y );
		}
		
		numtype min()
		{
			return ( (x < y) ? x : y );
		} 
	
	private:
		numtype x,y;		
		
};

int main()
{
	Compare <int> cmpi(3,7); 
	cout << "The max of the int is :" << cmpi.max() << endl;
	cout << "The min of the int is :" << cmpi.min() << endl;
	
	Compare <float> cmpf(45.2,45.22);
	cout << "The max of the float is :" << cmpf.max() << endl;
	cout << "The min of the float is :" << cmpf.min() << endl;
	
	Compare <char> cmpc('a','A');
	cout << "The max of the char is :" << cmpc.max() << endl;
	cout << "The min of the char is :" << cmpc.min() << endl;
	
	return 0;
}


说明:
    
    上面的成员函数是在类内定义的,如果改在类模板外定义,则不能用一般的定义成员函数的形式
    
    numtype Compare :: max(){ ... }     //    错误;
    
而应当写成类模板的形式:

    template <class numtype>
    
    numtype Compare <numtype> :: max()
    {
        return ( x > y ) ? x : y;
    }
    
所以定义一个类模板的一般形式为:

    1. 定义一个类:
    
        template <class XXX>
        
        class Compare
        {
            ...;
        };

        
    2. 用类模板定义一个对象:
    
        类模板名 <实际数据名> 对象名(实参表列);

    3. 类模板外定义成员函数:
    
         函数类型 类模板名 <虚拟类型参数> :: 成员函数名(函数形参表列) {...}
        
说明:


    1. 类模板的类型参数可以有一个或者多个,每个类型前都必须加 class :
    
        template<class T1, class T2>
        class someclass
        {...}
        
        在定义对象时分别代入实际的类型名
        
        someclass <int ,double> obj;
        
    2. 使用类模板时要注意其作用域,只能在有效区域内定义对象;
    
    3. 模板可以有层次,一个类模板可以作为基类,派生出派生模板类;

例:

#include<iostream> 
#include<string>
#include<iomanip>

using namespace std;

template <typename numtype>

class Compare
{
	public:
		Compare(numtype a,numtype b) : x(a),y(b) {}

		numtype max();	
		numtype min();
	
	private:
		numtype x,y;		
		
};


template <typename numtype>

numtype Compare <numtype> :: max()
{
	return (( x > y ) ? x : y);
}

template <typename numtype>

numtype Compare <numtype> :: min()
{
	return (( x < y ) ? x : y);
}

int main()
{

	Compare <int> cmpi(3,7); 
	cout << "The max of the int is :" << cmpi.max() << endl;
	cout << "The min of the int is :" << cmpi.min() << endl;
	
	Compare <float> cmpf(45.2,45.22);
	cout << "The max of the float is :" << cmpf.max() << endl;
	cout << "The min of the float is :" << cmpf.min() << endl;
	
	Compare <char> cmpc('a','A');
	cout << "The max of the char is :" << cmpc.max() << endl;
	cout << "The min of the char is :" << cmpc.min() << endl;

	
	return 0;
}

注: 每一个模板都要在声明一次!




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值