C++学习笔记(超详细笔记记录ing)

C++学习笔记(11)

学习是一件任重而道远的事情,与其焦虑不如动手起来,借助平台记录自己学习笔记,希望和大家多多交流,今天又是努力成为程序媛的一天!

17.类和对象

17.3 C++对象模型和this指针

17.3.1 成员变量和成员函数分开存储

在C++中,类内成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上

#include<iostream>
using namespace std;

class Person {

	int A = 10;  //非静态成员变量 属于类的对象上

	static int B; //静态成员变量 不属于类的对象上

	static void C() {}; //静态成员函数  不属于类的对象上

	void D() {};//非静态成员函数  不属于类的对象上

};

int Person::B = 12;

void calculate() {

	Person p;
	cout << "size of p = " << sizeof(p) << endl;//空对象占用的字节大小为1  //size of p = 1
	//C++编译器会给每一个空对象分配一个字节空间 是为了区分空对象占内存的位置
	//每个空对象也应该有一个独一无二的内存地址

}

void A() {
	Person p;
	cout << "size of p = " << sizeof(p) << endl; //size of p = 4 

}
	

int main() {
	
	//calculate();
	A(); //只有一个int非静态成员变量时对象所占内存空间为4个字节大小
	//加上一个静态成员变量B对象依旧只有4个字节大小
	//再加上一个静态成员函数依旧4个字节大小
	//再加上一个非静态成员函数依旧4个字节大小
	system("pause");
	return 0;
}


17.3.2 this 指针概念

  • 每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型对象会共用一块代码

那么这一块代码如何区分哪个对象调用自己呢?
C++通过提供特殊的对象指针,this指针,解决上述问题,this指针指向被调用的成员函数所属对象。

this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可

this指针用途:

  • 当形参与成员变量同名时,可用this指针区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this
#include<iostream>
using namespace std;

class Person {
public:
	//1.解决名称冲突问题
	Person(int age) {
		this->age = age;//this指向被调用的成员函数所属对象
	}

	int age;//函数参数与类成员属性同名时,会有冲突,结果不对  要么名字修改不同 要么加this指向被调用的成员函数所属对象


	Person& PersonAddAge(Person& p) {//这里返回值加了引用 才是其本体返回 不加引用返回的则是副本 即以值传递的方式返回
		this->age += p.age;

		//this是指向p2的指针变量 *this即返回p2本体
		return *this;
	}
};


void test01() {
	Person p(18);
	cout << "age = " << p.age << endl;//结果为18
}

//返回对象本身用this
void test02() {

	Person p1(20);
	Person p2(10);

	//若返回的是对象,这样可以链式使用对象属性 
	//链式编程思想
	p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);//如果去掉引用以值传递的方式返回 因为栈区数据在函数调用完之后都会销毁 所以每次返回得到的都是一个新的不同的副本 自然不能用p2的属性 结果为30
	cout << "p2.age = " << p2.age << endl;//结果为70

}

int main() {
	test01();
	test02();

	system("pause");
	return 0;
}

17.3.3 空指针访问成员函数

C++中空指针也可以调用成员函数的,但是也要注意有没有用到this指针,如果用到this指针,需要加以判断保证代码的健壮性

#include<iostream>
using namespace std;

class Person {
public:
	Person(int a) :m_a(a) {
		cout << "析构函数的调用" << endl;
	}

	void show1() {
		cout << "This is show1()" << endl;
	}

	void show2() {

		//这里访问成员属性时默认使用的是this指针  在属性前面都默认加了this 等价于
		//cout << "This is show2()" << "m_a =" << this->m_a << endl;//this 指向被调用的成员函数所属对象 而这里并没有指向创建任何对象 是一个空的值 无法访问里面的成员 所以会出错
		//加判断,如果是指针指向为空就退出程序 不是空 就继续执行下面语句 防止程序崩溃
		if (this == NULL) {
			return;//退出函数
		}
		cout << "This is show2()" << "m_a =" << m_a << endl;
	}

	int m_a;
};

void test01() {
	Person p(18);
	p.show1();
	p.show2();
}

void test02() {
	//空指针也可以访问成员函数,然而其不能使用this指针
	Person* p2 = NULL;
	p2->show1();
	p2->show2();

}

int main() {
	test01();
	test02();
	cout << "空指针调用成员函数" << endl;
	system("pause");
	return 0;
}

17.3.4 const修饰成员函数

常函数:

  • 成员函数后加const后我们称这个函数为常函数(本质是this指向的对象的值也不可修改)
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依旧可以修改

常对象:

  • 声明对象前加const就称该对象为常对象
  • 常对象只能调用常函数
#include<iostream>
using namespace std;

//常函数和常对象

class Person {
public:

	Person(int a,int b) :m_a(a) ,m_b(b){
		
	}
	
	//成员函数后加const后我们称这个函数为常函数
	//this本质是指针常量!即this指针的指向是不可以修改的
	//const Person * const this 限定this指向和this指向的值都不可修改  第一个const相当于常函数后面的const
	//成员函数后加const 修饰的是this指向 除了this指向不变,让指针指向的值也不可修改
	void show()  const{
		if (this == NULL) {
			return;//退出函数
		}

		this->m_b = 22;
		//this->m_a = 100;//常函数不允许修改指针指向的值 报错
		//this = NULL; //报错 this指针已经指向了调用此函数的p,无法再指向空 指向不可修改

		cout << "This is show2()" << "m_a =" << m_a << endl;
		cout << "This is show2()" << "m_b =" << m_b << endl;
		//等价于cout << "This is show2()" << "m_a =" << this->m_a << endl;
	}

	//对于普通成员函数来说,对象的成员属性值是可以修改的 即this指向的对象的值可以更改,等价于Person * const this
	void t() {
		m_a = 200;
		cout << "t m_a = " << m_a << endl;
		cout << "t m_b = " << m_b << endl;
	}

	int m_a;
	mutable int m_b;//特殊变量 即使在常函数中 也可以修改这个值 加关键字mutable
};

void test01() {
	Person p(12,13);
	
	p.show();
	p.t();
}

void test02() {
	const Person p2(15,16);//常对象
	//p2.m_a = 1;//常对象的普通属性也无法修改
	p2.m_b = 2;//在常对象下也可修改特殊值m_b

	//常对象只能调用常函数
	p2.show();
	//p2.t();//常对象本身不允许修改属性 但是调用普通函数里可以修改属性值 这样就与自身设定矛盾
}


int main() {
	test01();
	test02();
	cout << "const 修饰成员函数" << endl;
	system("pause");
	return 0;
}

结果为:
在这里插入图片描述

17.4 友元

在程序中,有些私有属性,也想让类外的特殊函数或类进行访问,就需要用到友元的技术。
友元就是声明一些特殊的函数或者类作为另一个类的好朋友,来访问到这类里的私有成员。
友元的关键字为friend,友元的三种实现:

  • 全局函数做友元
  • 类做友元
  • 成员函数做友元

1.全局函数做友元

#include<iostream>
using namespace std;
#include<string>

class Building {
	//goodFriend全局函数是Building好朋友 可以访问Building中私有成员
	friend void goodFriend(Building &p);//全局函数做友元
public:
	//构造函数
	Building() {
		m_SittingRoom = "客厅";
		m_BedRoom = "卧室";
	}

public:
	string m_SittingRoom;

private:
	string m_BedRoom;
};

//全局函数做友元
void goodFriend(Building &p) {
	
	cout << "全局函数 m_SittingRoom " << p.m_SittingRoom << endl;
	cout << "全局函数 m_BedRoom " << p.m_BedRoom << endl;
}

void test() {
	Building B;
	goodFriend(B);

}

int main() {
	test();

	system("pause");
	return 0;
}

在这里插入图片描述
2.类做友元

#include<iostream>
using namespace std;
#include<string>

//class Building;//如果先调用Building类但是未出现需要声明才不会报错  不过Building的属性和函数要在其他类使用前写 否则没有对象属性和行为 或者把其他类函数写在调用类外成员属性函数之下
class Building {

	friend class GoodFriend;//类做友元!
public:
	Building();//该函数在内外写

public:
	string m_SittingRoom;

private:
	string m_BedRoom;
};


//类外写成员函数  加个作用域
Building::Building() {
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}

//类做友元
//一个类去访问另一个类的私有属性
class GoodFriend {
public:
	
	
	GoodFriend(){
		p = new Building;//new 数据类型  返回的是指针 在堆区创建 定义*b的时候并没有分配内存
		//只有执行new后才会分配内存 传指针参数传过去的就是4个字节 如果用对象,参数传递占用的资源就太了
		}
	void visit() {
		cout << "正在访问m_SittingRoom =" << p->m_SittingRoom << endl;
		cout << "正在访问m_BedRoom =" << p->m_BedRoom << endl;
	}
		
private:
	
	Building* p;//创建类指针 
	
};



void test() {
	GoodFriend g;
	g.visit();
}

int main() {
	test();

	system("pause");
	return 0;
}

在这里插入图片描述
3.成员函数做友元

#include<iostream>
using namespace std;
#include<string>

class Building;//如果先调用Building类但是未出现需要声明 不过Building的属性和函数要在其他类使用前写 否则没有对象属性和行为 或者把其他类函数写在调用类外成员属性函数之下  如这里下面的写法


//成员函数做友元
//一个类去访问另一个类的私有属性
class GoodFriend {
public:

	GoodFriend();
	
	void visit();//让visit函数可以访问Building的私有属性
	void visit1();//visit1函数不可以访问Building的私有属性

private:

	Building* p;//创建类指针 

};

class Building {
	friend void GoodFriend::visit();//让成员函数做友元

public:
	Building();//该函数在内外写

public:
	string m_SittingRoom;

private:
	string m_BedRoom;
};


//类外写成员函数  加个作用域
Building::Building() {
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}

GoodFriend::GoodFriend() {
	p = new Building;//new 数据类型  返回的是指针 在堆区创建 定义*b的时候并没有分配内存

}

void GoodFriend::visit() {
	
	cout << "正在访问m_SittingRoom =" << p->m_SittingRoom << endl;
	cout << "正在访问m_BedRoom =" << p->m_BedRoom << endl;
	
}

void GoodFriend::visit1() {

	cout << "正在访问m_SittingRoom =" << p->m_SittingRoom << endl;
	//cout << "正在访问m_BedRoom =" << p->m_BedRoom << endl;//不是友元 无法访问私有属性

}

void test() {
	GoodFriend g;
	g.visit();
	g.visit1();
}

int main() {
	test();

	system("pause");
	return 0;
}

在这里插入图片描述

17.5 运算符重载

 概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

17.5.1 加号运算符重载

作用:实现两个自定义数据类型相加的运算
在这里插入图片描述

#include<iostream>
using namespace std;
#include<string>


//实现两个自定义数据类型相加的运算

class Person {

public:
	
	成员函数重载+号运算
	//Person operator +(Person & p) {
	//	Person Temp;
	//	Temp.m_a = this->m_a + p.m_a;
	//	Temp.m_b = this->m_b + p.m_b;
	//	return Temp;

	//}
public:
	int m_a;
	int m_b;
};

//2.全局函数重载+号运算符
Person operator+(Person & p1, Person & p2) {
	Person temp;
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}


//运算符函数重载
Person operator+(Person& p1, int &num) {//引用要初始化
	Person temp;
	temp.m_a = p1.m_a + num;
	temp.m_b = p1.m_b + num;
	return temp;
}

void T() {

	Person p1;
	p1.m_a = 10;
	p1.m_b = 10;
	Person p2;
	p2.m_a = 20;
	p2.m_b = 20;


	//成员函数重载本质调用
	//Person p3 = p1.operator+(p2);
	全局函数重载本质调用
	//Person p3 = operator+(p1, p2);都可运行成功
	Person p3 = p1 + p2;

	//运算符重载 也可以发生函数重载
	int a = 100;
	Person p4 = p1 + a;

	cout << "p3.m_a = " << p3.m_a << endl;
	cout << "p3.m_b = " << p3.m_b << endl;
}

int main() {
	T();

	system("pause");
	return 0;
}

在这里插入图片描述
注意:

  • 对于内置的int…等数据类型的表达式的运算符运算是不能修改的
  • 不要滥用运算符重载,比如+号运算,里面放-号等杂乱运算,行为迷惑

17.5.2 左移运算符重载

作用:可以输出自定义数据类型

#include<iostream>
using namespace std;
#include<string>

class Person {
	friend ostream& operator<<(ostream& cout, Person& p);
public:
	Person(int a, int b) :m_a(a), m_b(b) {

	}
	利用成员函数重载 左移运算符 1号
	//void operator <<(ostream &cout) {//cout是标准的输出流类对象 而且全局只能有一个 用引用的方式传过来 不能创建一个新的 由于不能简化为p << cout形式 所以要采用全局函数重载
	//	cout << this->m_a << endl;
	//}

	成员函数重载 左移运算符 2号
	//void operator <<(Person& p) {
	//	cout << "m_a = " << p.m_a << " m_b = " << p.m_b;
	//}

private:
	int m_a;
	int m_b;
};

ostream& operator<<(ostream& out, Person& p) {//cout是标准的输出流类对象 而且全局只能有一个 用引用的方式传过来 不能创建一个新的 返回也要引用的方式 这样没有复制返回值 而是返回对象的引用即对象本身
	out << "m_a = " << p.m_a << " m_b = " << p.m_b;
	return out;// cout << p是一个函数的调用,返回值是void,需要返回cout类型才能加endl; 这样cout<<每次返回就是输出流cout 了 就可以使用其特点输出了 形成链式编程思想。
}

void test01() {
	Person p(5, 10);
	cout << p << endl;//想输出p就返回p的所有属性
	//p << cout;//如果是成员函数重载 调用的时候简化成该种形式 并不是我们想调用的cout << p形式
	//p << (p);//成员函数重载又或许是这种形式 但显然不是想要的形式  == p.operator<<(p);

	
	
}

int main() {

	test01();

	system("pause");
	return 0;
}

在这里插入图片描述
备用参考链接:左移运算符函数重载
补充:我这里用的是速览定义也可,得到cout是ostream输出流自定义类的对象

17.5.3 递增运算符重载

作用:通过重载递增运算符,实现自己的整型数据
补充:运算符的优先级顺序
在这里插入图片描述

#include<iostream>
using namespace std;

class MyIntger {
	friend ostream& operator<<(ostream& out, MyIntger myint);

public:
	MyIntger() {
		m_a = 0;
	}

	//重载前置++运算符 
	MyIntger& operator++() {//先运算++,再<< ; ++如果返回的是void就不满足<<里的参数设置了 所以需要返回MyIntger类型 
		                    //并且要加&引用返回本体 因为如果原本++(++i) 返回值是2 本身返回i也是2 如果不是引用返回而是值传递++(++MyIntger)结果为2 但是MyIntger值为1 因为操作的不是本体
		//先加1
		m_a++;
		//后返回自增值
		return *this;
	}

	//重载后置++运算符
	const MyIntger operator++(int) { //int 纯属让编译器区分 是后置 无参的是前置
		                       //不返回引用是因为不能返回函数局部变量 否则再次访问就是非法操作
		//先给出目前的值
		MyIntger temp = *this;

		//自增
		m_a++;

		//返回当前值
		return temp;
	}

private:
	int m_a;
};

ostream& operator<<(ostream& out, MyIntger myint) {
	cout << myint.m_a << endl;

	return out;
}

void test() {

	MyIntger myint;
	cout << myint << endl;//0
	cout << ++myint << endl;//先提示没有可以这样运算的左运算符  所以要先函数重载左运算符  //1
	cout << ++myint << endl;//2
	cout << myint << endl;//2
	cout << myint++ << endl;//2
	cout << myint << endl;//3
	cout << ++(++myint) << endl;//5
	cout << myint << endl;//5
	//cout << (myint++)++ << endl;//不加const返回5  其实只增加了1,因为第二次自增作用在一个临时对象上 所以返回临时对象5 两次不是同一个作用对象 无论多少次后置递增(递减)都只相当于运算一次
	//cout << (myint++)++ << endl;//加const报错
}


int main() {
	test();


	system("pause");
	return 0;
}

注意:
参考链接:C++之运算符重载(前置++和后置++)

  • const MyIntger operator++(int)后置++运算符的返回类型为什么要是const对象呢?
    • 有两个原因:

      • 1.如果不是const对象,myint(++)++这样的表达式就可以通过编译。但是,其效果却违反了我们的直觉 。myint其实只增加了1,因为第二次自增作用在一个临时对象上。
      • 2.对于内置类型,(i++)++这样的表达式是不能通过编译的。自定义类型的操作符重载,应该与内置类型保持行为一致 。myint++的返回类型如果改成非const对象,肯定能通过编译,但是我们最好不要这样做
  • 前置++的返回类型是MyIntger&,后置++的返回类型const MyIntger。这意味着,前置++返回的是左值,后置++返回的是右值。
    • 对于什么是左值,右值:
      • ++i是直接给i变量加1,然后返回i本身,因为i是变量,所以可以被赋值,因此是左值表达式
      • i++是先产生一个临时变量,记录i的值,在i的值被使用后,再后给i加1,接着返回临时变量,然后临时变量不存在了,所以,不能再被赋值,因此是右值表达式
  • 前置++的效率更高,应优先使用前置++,尤其是对于用户自定义类型的自增操作。理由是:后置++会生成临时对象。temp是一个临时对象,会造成一次构造函数和一次析构函数的额外开销。虽然,编译器在某些情况下可以优化掉这些开销,但是,我们最好不要依赖编译器的行为。

同理:写出前置–和后置–函数重载

#include<iostream>
using namespace std;

class MyIntger {
	
	friend ostream& operator<<(ostream& cout,const MyIntger& myint);
public:
	MyIntger() {
		num = 0;
	}

	//前置--
	MyIntger& operator--() {
		//先运算
		this->num--;
		//后返回值本身
		return *this;
	}

	//后置--
	const MyIntger operator--(int) {//加const表示返回值的内容不可改动 即不能作为左值  int 为占位参数
		//先临时定义现在的值
		MyIntger temp = *this;
		//递减操作
		num--;
		//返回递减之前的值
		return temp;
	}

private:
	int num;
};

ostream& operator<<(ostream& cout,const MyIntger& myint) {//全局函数 左移运算符函数重载
	cout << myint.num << endl;
	return cout;
}

void test() {
	MyIntger myint;

	cout << myint << endl;//0
	cout << --myint << endl;//-1
	cout << myint << endl;//-1
	cout << --(--myint) << endl;//-3
	cout << myint-- << endl;//起初这行报错 把<< 后面的参数加上const就行  //-3
	cout << myint << endl;//-4

}


int main() {
	test();

	system("pause");
	return 0;
}


这里在后置–的时候出现一个问题,:
在这里插入图片描述
当然我这里是–,不过搜素一番发现后置++也会这样,原因:后置++返回值类型不是引用,是一个临时值,在返回之后就会消亡,但是非const引用(参考链接:C++禁止引用非const的临时变量)需要对象一直存在,临时值则不行,也就无法调用这个函数;当然也可以把引用和const都去掉,值传递也可,而临时变量是可以作为常量引用的,因为临时变量本身是可以修改的。

17.5.5 赋值运算符重载

在这里插入图片描述如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题。
如果在堆区创建了变量,会出现堆区空间重复释放的问题,需要深拷贝解决,往期笔记:深拷贝和浅拷贝

#include<iostream>
using namespace std;

class Person {
public:
	Person(int a) {
		num = new int(a);//析构函数 堆区创建变量
	}

	~Person() {
		//判断 并删除堆区创造变量
		if (num != NULL) {
			delete num;
		}
	}
	//深拷贝 赋值运算符 
	Person& operator=(Person& p) {

		//编译器默认浅拷贝操作:
		// num = p.num;
		
		//先释放干净堆区数据 
		if (num != NULL) {
			delete num;
		}

		//进行深拷贝
		num = new int(*p.num);

		//返回自身
		return *this;
	}
//private:
	int *num;//创建类指针
};



void test() {
	Person p1(18);//函数执行完就释放了
	cout << *p1.num << endl;//18

	Person p2(20);

	Person p3(16);

	cout << *p2.num << endl;//20

	p1 = p2;//一旦进入赋值操作 p1就把地址数值等复制一本给p2 这样两个就指向同一个地址 析构两次同地址发生了错误

	cout << *p2.num << endl;//20

	p1 = p2 = p3;//p3赋给p2 返回p2 再把p2赋给p1

	cout << "p1.num = " << *p1.num << "  p2.num = " << *p2.num << "  p3.num = " << *p3.num << endl;//p1.num = 16  p2.num = 16  p3.num = 16


}

int main() {
	test();

	//int a1 = 10;
	//int a2 = 12;
	//int a3 = 15;

	//a1 = a2 = a3;
	//cout << a1 << " " << a2 << "  " << a3 << endl;//15  15  15即内置=运算是允许连续赋值的



	system("pause");
	return 0;
}

17.5.6 关系运算符重载

作用:重载关系运算符,可以让两个自定义类型对象进行对比操作 == 和 !=

#include<iostream>
using namespace std;
#include<string>

//关系运算符重载 ==    !=
class Person {
public:
	Person(string name,int age) {
		m_name = name;
		m_age = age;
	}

	bool operator==(Person& p) {//注意返回类型是bool
		if (this->m_name == p.m_name && this->m_age == p.m_age) {
			return true;
		}

		return false;
	}

	bool operator!=(Person& p) {
		if (this->m_name == p.m_name && this->m_age == p.m_age) {
			return true;
		}

		return false;
	}

	string m_name;
	int m_age;
};

void test() {
	Person p1("Tom", 18);

	Person p2("Su", 20);
	//Person p3("a", 22);
	cout << "姓名:" << p1.m_name << "  年龄:" << p1.m_age << endl;
	cout << "姓名:" << p2.m_name << "   年龄:" << p2.m_age << endl;

	if (p1 == p2 ) {//不具有链式 原内置也没有链式
		cout << "p1 == p2" << endl;
	}
	else {
		cout << "p1 != p2" << endl;
	}

}

int main() {
	test();


	system("pause");
	return 0;
}

在这里插入图片描述

17.5.7 函数调用运算符重载

  • 函数调用运算符()也可以重载
  • 由于重载后使用方式很像函数调用 又称伪函数
  • 仿函数没有固定写法,很灵活
#include<iostream>
using namespace std;
#include<string>

//函数调用重载

//打印函数调用
class MyPrintf {
public:
	
	void operator()(string s) {//这个小括号表示对其重载 后面括号表示传入的参数
		cout << s << endl;
	}

};


void test01() {
	MyPrintf myprintf;
	myprintf("hello");//由于调用此重载类成员函数很像函数调用 所以叫伪函数  ()重载函数调用即为伪函数调用

}

//函数灵活 
//加法类
class Add {
public:
	int operator()(int a,int b){

		return a + b;
	}

	
};

void test02() {
	Add ex;
	int re = ex(12, 15);
	cout << re << endl;

	//匿名函数对象
	//不创建对象输出
	cout << Add()(20, 30) << endl;//前面Add()就是创建一个匿名对象 然后利用函数重载小括号  //匿名对象特点:当前行执行完立即释放  数据类型+()就是匿名对象 这里又有调用所以是匿名函数对象
}

//根据自己需要写仿函数 很灵活

int main() {
	test01();
	test02();

	system("pause");
	return 0;
}

在这里插入图片描述

解惑链接:
1.&取地址符与* 解引用操作符
2.值传递,指针传递,引用传递
3.值传递,指针传递,引用传递区别

第十一篇笔记到此结束,C++基础学习会持续更新在C++学习笔记合集中,当作学习笔记复习,如果能帮助其他小伙伴就更好了。
笔记是看黑马程序C++时做的记录,笔记中如果有错误和改进的地方,欢迎大家评论交流,up up up!!!
学习原视频来自:黑马程序员C++从0到1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值