c++类与对象

 类和对象概念:

类和对象是 C++的重要特性:

类(class)是一种构造类型,对象(object)类定义出来的变量,类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫类的实例化。每个对象都是类的一个具体实例(Instance),拥有类的成员变量和成员函数。

结构体和类的区别:

在C语言中的结构体:

  1. struct 只能包含变量
  2. struct 不能包含函数
  3. 因为C语言没有面向对象,所以struct没有(继承和多态)
  4. 访问权限只能是public

C++的结构体:

为了兼容C,C++也有struct,但C++中的结构体可以继承,可以多态,可以拥有函数

类:

class比较全能:

  1. 可以拥有变量,函数
  2. 可以继承
  3. 可以发生多态

c++中类和结构体的区别:

  1. struct 的成员默认为 public,class 的成员默认为 private
  2. struct不可以用于定义模板参数,class 可以用于定义模板参数

  3. struct 继承默认是 public 继承 ,class 继承默认是 private 继承

类的创建:

格式:

class 类名

{

    权限:成员变量;成员函数;...

};

class person
{
public://权限
	int a;//成员变量
	void show()
	{
		cout << a << endl;//成员函数
	}
protected:
	double b;
private:
	char c;
};

对象的创建:

  •  class   类名   标识符
  • 类名   标识符(建议使用)
class person
{
public:
	int a;
	void show()
	{
		cout << a << endl;
	}
protected:
	double b;
private:
	char c;
};
int main() {
	class person p1;//方式一
	person p2;      //方式二
	return 0;
}

类的成员:

  • 成员变量
  • 成员函数
  1. 成员函数在类内声明和定义的话默认为内联函数
  2. 成员函数在类内声明如果在类外定义的话,不为内联函数,需要在定义处添加inline

当类中的成员函数较少时,一般使用类内定义

当类中的成员函数较多时,为了不影响类中结构的观察,一般会使用类内声明,类外实现

类外定义格式:

(inline)返回类型   类名::  函数名(形参,...)

  1. 不为内联函数的话,不加inline
  2. 类名:: 的作用是 限定为 该类中的函数
class person
{
public:
	int a;
	int text1()//类内声明和定义
	{
		return a;
	}
	int text2();//类内声明
};
inline int person::text2()//类外定义
{
	return a + 1;
}

类中的权限和封装: 

class默认权限:private(私有权限)

  • public  :    共有权限,类内外都可以访问

  • protected:保护权限 ,仅类内可以访问
  • private:     私有权限,仅类内可以访问

protected和private的区别:在继承时会仔细分析。

class person
{
public:
	int a;
	int text1() //类内可以访问全部成员
	{
		return a;
	}
protected:
	double b;
	double text2()
	{
		return b;
	}
private:
	char c;
	char text3()
	{
		return c;
	}
};
int main() {
	person p2;
	p2.a = 10;//公有类型 类外可以访问
	p2.b = 10;//(报错)保护类型 类外不可以访问
	p2.c= 10; //(报错)私有类型  类外不可以访问
	return 0;
}

封装: 

封装,是指尽量隐藏类的内部实现,只向用户提供有用的成员函数。

为了保护类内的成员变量,防止被随意修改,一般会把成员变量设置为private类型,然后定义几个接口来访问私有数据,以达到修改私有属性。常见的接口为get() set()

  1. 在实战项目中尽可能的使用封装
  2. 成员变量一般为私有权限
  3. 成员函数的话,一般为公共权限(接口)
  4. 平时练习和话可以不用封装(节约时间)
class person
{
public:
	int a;
	void show()
	{
		cout << a << endl;
	}
};

int main() {
	person p;
	p.a = 10;//可直接修改,不安全
	return 0;
}
class person
{
public:
	void show()
	{
		cout << a << endl;
	}
	//获取a的值
	int get_a()
	{
		return a;
	}
	//设置a的值
	void set_a(int p)
	{
		a = p;
	}
private:
	int a;
};

int main() {
	person p;
	p.a = 10;//错误,私有成员不可直接访问
	p.set_a(20);//设置a的值 (更安全)
	p.get_a();//得到a的值
	return 0;
}

对象访问成员的方式:

  • 普通对象用   .    访问类中的成员和函数
  • 指针的话用   ->  访问类中的成员和函数
	person p2;
	p2.a = 10;
	person *p = new person;//开辟内存
	p->a = 10;
	delete p;//释放内存

构造函数:

构造函数:是一种特殊的成员函数

作用:初始化对象的数据成员

构造函数的特点:

  1. 函数名和类名相同
  2. 没有返回值
  3. 创建对象时自动调用(实例化)
  4. 不能被显示调用
  5. 可以发生重载

格式:  类名(形参){   操作;}  

class person
{
public:
	person()//构造函数没有返回值,函数名与类名相同
	{
		cout << "构造函数" << endl;
	}
	person(int a,double b)//构造函数可以发生重载(作用为初始化数据)
	{
		_a = a;
	    _b = b;
		cout << "构造函数2" << endl;
	}
	int _a;
	double _b;
};
int main() {
	person p;//实例化时自动调用构造函数
	person p1(1, 2.0);//实例化时自动调用构造函数
	return 0;
}

对象初始化列表: 

例如:构造函数为:person(int a,int b){}

普通对象:

  1. 隐式:person  p(10,20);
  2. 显示:person  p=person(10,20);
  3. person  p{10,20};  //c++11新加
  4. person  p={10,20};//c++11新加

指针对象:

  1. person  *p= new person(10,20);
  2. person  *p =new person{10,20};//c++11新加
class person
{
public:
	person(int a, int b)
	{
		cout << "构造函数调用" << endl;
	}
	int _a;
	double _b;
};

int main() {
	person p(10, 20);
	person p1=person(10, 20);
	person p2{ 10, 20 };
	person p3 = { 10, 20 };
	person * pp1 = new person(10, 20);
	person * pp2 = new person{ 10,20 };
    delect(pp1);
    delect(pp2);
	return 0;
}

构造函数的易错点:

构造函数易错点_旷工锁的博客-CSDN博客

默认构造函数: 没有显式提供 初始化 式时调用的构造函数

  1. 只有默认构造函数”被需要“的时候编译器才会生成默认构造函数 
  2. 默认构造函数没有形参,不对数据做任何处理。
  3. 一旦定义了构造函数,那么不会生成默认构造函数。 

此块内容来自:深度探索C++对象模型(侯捷)(推荐大家使用这本书) 

默认构造函数生成的情况:

1.当一个类内含另一个类对象时且该类对象有默认构造

class person
{
public:
	person()//默认构造
	{
	}
	int _a;
	double _b;
};
class son
{
public:
	person p;
	int s;
};

int main() 
{
	son k();//这是son会生成默认构造函数
	return 0;
}

 2.拥有默认构造的基类的派生类

class person
{
public:
	person()
	{
	}
	int _a;
	double _b;
};
class son :public person//son 继承于person
{
public:
	person p;
	int s;
};

int main() 
{
	son k;//这是son会生成默认构造函数
	return 0;
}

3.带有虚函数的类

  1. class 声明(或继承)一个虚函数
  2. class 派生自一个继承串链,其中有一个或多个虚基类

4.在虚拟继承下的类

构造函数的初始化: 

 初始化方法一:

class person
{
public:
	person(int a,double b)
	{
		_a = a;
		_b = b;
	}
	int _a;
	double _b;
};

初始化方法二:

格式  :类名 (类型 标识符,...) : 成员变量(标识符),成员变量(标识符)...{ }

这种方法更加的简便

	person(int a,double b):_a(a),_b(b)
	{

	}
	int _a;
	double _b;

 类成员初始化的顺序:

类初始化的顺序为 成员变量声明的顺序,先初始化成员再初始化函数

 展示一个案例:(易发生的错误)

class person
{
public:
	person(int a):_a(_b),_b(a),_c(_b)
	{

	}
	int _a;
	int _b;
	int _c;
};

int main() 
{
	person p(4);
	cout << p._a << endl;//结果为-858993460
	cout << p._b << endl;//结果为4
	cout << p._c << endl;//结果为4
	return 0;
}

 

 析构函数:

析构函数的作用:销毁对象清理内存

析构函数的特点:

  1. 析构函数没有返回值
  2. 析构函数不能显示调用
  3. 析构名  ~类名
  4. 析构函数没有参数
  5. 不能被重载(只有一个析构函数)
class person
{
public:
	person()
	{
		cout << "构造函数" << endl;
	}
	~person()//析构函数,没有返回值,没有参数,没有重载,不能显示调用,
	{
		cout << "析构函数" << endl;
	}
};

int main() 
{
	person p;
	return 0;
}

 析构函数的调用:

  1. 当对象为普通对象时,存放在栈区 ,析构函数会自动调用
  2. 当对象为指针时,new的时候会调用构造函数,存放在堆区,要 delete后才会调用析构函数 
class person
{
public:
	person()
	{
		cout << "构造函数" << endl;
	}
	~person()
	{
		cout << "析构函数" << endl;
	}
};

int main() 
{
	person p; //调用了 构造和析构
	return 0;
}

 

class person
{
public:
	person()
	{
		cout << "构造函数" << endl;
	}
	~person()//析构函数,没有返回值,没有参数,没有重载,不能显示调用,
	{
		cout << "析构函数" << endl;
	}
};

int main() 
{
	person *p;//不会调用构造和析构
    cout<<"----------"<<endl;
	person *p1 = new person;//调用构造函数
	delete p1;//调用析构函数
	return 0;
}

拷贝构造函数:

拷贝构造函数的作用:已有的对象初始化一个新的对象

  1. 函数名与类名相同
  2. 拥有参数 参数为  (类名 & 对象名)   (一定要用引用,引用不会产生新内存)

拷贝构造函数调用的时机:

  1. 用对象初始化新对象时
  2. 当函数的形参是对象时(值传递时)
  3. 返回值是对象时 ,会生成一个临时对象,用完后立即释放
  4. 需要产生一个临时类对象时 

 下面给出例题:

 

 深拷贝和浅拷贝:

浅拷贝:可以说是简单的值拷贝(普通对象)

class person
{
public:
	person(){}//默认构造
	person(const person&p)//浅拷贝构造函数
	{
		_age = p._age;
		_height = p._height;
	}
	int _age;
	double _height;
};

int main()
{
	person p;
	person p1(p);//浅使用拷贝函数
	return 0;
}

 深拷贝:在堆区开辟空间,进行拷贝操作,为了防止重复释放同一块内存

class person {
public:
	//初始化
	person(int a, string n)
	{
		cout << "有参构造函数的调用" << endl;
		age = a;
		name = new string(n);
	}
	~person()//析构函数
	{
		//释放内存
		if (name != NULL)
		{
			delete name;
			name = NULL;
		}
		cout << "析构函数的调用" << endl;
	}
	//自定义拷贝构造
	person(const person &p)
	{
		age = p.age;
		//在堆区申请一块内存  指向不一样的内存
		name = new string(*p.name);
	}

	int age;
	string *name;
};

int main()
{
	person p1(15, "name");
	//深拷贝
	person p2 = p1;
	return 0;
}

这里拓展以下知识:

  • 浅层复制 :只复制指向对象的指针,而不复制引用对象本身
  • 深层复制 :复制引用对象本身

类中构造和拷贝和析构的生成情况:

正常情况下:创建一个类时编译器会自动生成3个函数

1.默认构造函数

2.析构函数

3.拷贝构造函数(浅拷贝)

当用户定义有参构造函数,则c++不会提供默认构造函数 但还会提供拷贝构造函数(值拷贝)

当定义拷贝构造时,c++不会提供其他构造函数

class person
{
public:
	person(const person &p)//拷贝构造函数
	{
		_name = p._name;
		_age = p._age;
		_height = p._height;
	}
	string _name;
	int _age;
	int _height;
};
int main()
{
	person p;//报错,没有默认构造函数
	return 0;
}

类对象作为类成员:(对象成员)

第一种格式:成员在类声明之后

class person{};
class son{
    person p;
};

 第二种格式:成员在类声明之前,需要使用前向引用声明,使编译器提前知道该类名。

class person;//前向引用声明

class son{

    person p;

}

class person{}

注意:在提供一个完整的类定义之前,不能定义该类对象,也不能在内联成员函数中使用该类的对象 

class person;
class son
{
public:
	person p;//报错son::p使用未定义的 class“person”	

};
class person
{
public:

};
int main()
{
	son s1;
	return 0;
}

类对象作为类成员的特点:

  1. 按照初始化顺序调用构造函数
  2. 如果对象成员有构造函数,那么如果类没有构造函数,会生成默认构造函数
  3. 初始对象成员时,需要按照对象成员的构造函数来实现
#include<iostream>
#include<string>
using namespace std;
class person
{
public:
	//构造函数
	person();
	person(string na, int a, int h) :name(na), age(a), height(h)
	{ 
		cout << "person的构造函数" << endl; 
	}
	~person()
	{ 
		cout << "person的析构" << endl; 
	}
	string name;
	int age;
	int height;
};
class son
{
public:

	son(string s, string s1, int a, int h) :Name(s), P(s1, a, h)
	{ 
		cout << "son的构造" << endl; 
	}
	~son()
	{
		cout << "son的析构" << endl; 
	}
	string Name;
	person P;
};

void text()
{
	son S1("A", "B", 12, 160);//初始化
	cout << "父亲的名字"<<S1.Name << endl;
	cout << "儿子的名字" << S1.P.name << endl;
	cout << "儿子的年龄" << S1.P.age<< endl;
	cout << "儿子的身高" << S1.P.height << endl;
}
int main()
{
	text();
	return 0;
}

 this指针:

  1.  this时c++的一个关键词,是一个const指针,可以用this指向对象中的成员
  2. this指针是隐含每一个非静态成员函数的指针
  3. this不需要定义,直接使用

this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。 

使用场景:

  1. 当形参和实参命名相同时,可以使用this指针区分
  2. 当非静态成员函数返回对象本身是 可以用 *this 
  3. 判断是否为空指针

区分形参和成员变量:

class person
{
public:
	person(string name, int age)
	{
		//使用this指针区分形参和成员变量
		this->name = name;
		this->age = age;
		//不使用也可以 但代码可读性差
		//name = name;
		//age = age;
	}

	string name;
	int age;

};

返回本身: 

class person
{
public:

	person get_this()
	{
		//返回本身
		return *this;
	}

};

 判断是否为空指针:

class person
{
public:

	void show_age()
	{
		//可以做一个判断,防止出现错误
		if (this == NULL)
		{
			return;
		}
		cout << "age=:" << age << endl;
		//等价与cout<<"age=:" << this->age << endl;
		//因为this为空指针,所以报错
	}
	int age;
};
int main()
{
	//此时指针为空指针
	person *p = NULL;
}

易错点:成员函数删除this指针

小结参考自:在类的成员函数中调用delete this - 向日葵的祈愿 - 博客园 (cnblogs.com)

this指针是可以被delete的:原理为this是一个指针,使用delete会调用析构函数,然后再释放内存。

  1. delete this 不能放在析构函数中,会造成死循环,会反复调用析构函数
  2. delete this放在非析构函数中(创建普通对象时),delete this 之后 不能访问类中的成员(因为使用类成员,靠的是this指针)
  3. delete this放在非析构函数中(创建指针对象时),delete this 之后 不能访问类中的成员

注意:delete 只会释放内存,并不会把指针赋予NULL

以下测试在vs2015中,不同的编译器可能会有差异 

//析构函数中调用delete this
class person
{
public:
	person(){}
	~person() {
		cout << "delete this" << endl;//结果持续输出这条语句
		delete this;
		
	}
	int a = 0;
};
int main()
{

	person p;
	return  0;
}

//delete this 放在普通成员中,创建普通对象
class person
{
public:
	person(){}
	~person() {

	}
	void show()
	{
		cout << a << endl;
		delete this;//在这里delete this 之后不能访问类的成员函数和变量
		this->a = 10;//这条语句错误
        a=10;//错误 //本本质上也是调用this指针访问
        text();//错误
		cout << a << endl;
	}
	void text()
	{
		cout << "show" << endl;
	}
	int a = 1;
};
int main()
{
	person p;//创建普通对象
	p.show();
    p.a=10;//错误,无法访问
	return  0;
}

//delete this 放在普通成员中,创建指针对象
class person {
public:
	person() {
		member = 1;
	}
	~person() {
		member = 0;
	}
	void test() {
		delete this;
	}
	void show()
	{
		cout << "show" << endl;
	}
private:
	int member;

};

int main() {
	person *p = new person();//创建指针对象
	p->test();
	p->show();//运行报错
	delete p;
	return 0;
}

静态成员变量:

静态成员变量:在成员变量之前加上  static

  1. 所有对象共用同一份数据
  2. 在编译阶段分配内存
  3. 类内声明,类外初始化

注意:静态成员函数已经在类外初始化,无法用构造函数初始化

初始化格式:(不管什么权限都能初始化)

类内声明: static  数据类型   标识符;

类外实现: 数据类型   类名::标识符=初始化数据;

class person
{
public:

	//静态成员变量
	static int age;
};
//类外初始化
int person::age = 0;

 静态成员变量访问方式:

  1. 通过对象访问
  2. 通过类名访问
class person
{
public:
	person(){}

	string _name;
	static int _age;//类内声明
};
int person:: _age=10;//类外初始化
int main()
{
	person p;
	p._age = 20;//通过对象访问
	person::_age = 30;//通过类名访问
	return 0;
}

注意:static 成员变量的内存,而是在(类外)初始化时分配。反过来说,没有在类外初始化的 static 成员变量不能使用 

class person
{
public:
	person(){}

	string _name;
	static int _age;//类内声明
};
int person:: _age=10;//初始化时分配内存
int main()
{
	person p;
	return 0;
}

static 成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问 

class p
{
public:
	static int a;
};
int p::a = 10;
int main()
{
	p::a = 20;//不用生成对象也可以访问
}

静态成员函数:

静态成员函数:在成员函数之前加上  static

  1. 所有对象共用一个函数
  2. 静态成员函数只能访问静态成员变量

class person
{
public:
	person(){}
	person(string name):_name(name){}
	static void show()
	{
		cout << _name << endl;//报错,无法访问非静态成员变量
		cout << _age << endl; // 可以访问
	}
	string _name;
	static int _age;
};

 总结:静态成员和非静态成员的区别:

非静态成员:静态成员:
只有本对象能使用所有对象共用一个成员
类内声明用构造函数初始化类内声明,类外初始化
构造函数初始化后,分配内存类外初始化时分配内存
创建对象才能访问不用创建对象也能访问(受权限限制)
可以使用this指针不能有this指针(公有的)

const在类中的使用:

  1. const修饰的成员变量
  2. const修饰的成员函数
  3. const修饰的类
  4. const修饰的引用

const修饰的成员变量:

  1. 仅有const修饰的成员数据,类内声明,只能通过初始化来赋值(构造函数)
  2. static const修饰的成员数据,(整型和枚举类型)可以在类内初始化,其他的按照const初始化

注意:常成员数据的值不能修改

 1.常成员初始化:

class person
{
public:
	person(int b) :a(b){}//常成员的初始化
	~person(){}

	const int a;
};
class person
{
public:
	person(){}
	~person(){}

	const int a=20;//常成员的初始化
};

错误的初始化:

class person
{
public:
    person(int b)
    {
        a = b;//因为a为常量不能被赋值
    }
    ~person(){}

    const int a;
};

 静态常成员数据(整形和枚举类型可以在类内初始化):

整形数据和枚举类型,在类内初始化

class person
{
public:
	static const int a=10;//可在类内初始化
	static const enum S1 { A, B = 8, C, D, E };//可在类内初始化
};

其他类型则不能在类内初始化,只能在类外初始化

class person
{
public:
	static const float a;
	static const double b;
	static const string c;
};
//非整形和枚举类型只能在类外初始化
const float person::a = 10.0;
const double person::b = 12.00;
const string person::c = "pppppp";

2.常成员函数:

  1. 常成员函数,是用const修饰的成员函数(定义时也要加const)
  2. 常成员函数,修改不了成员数据
  3. 常成员函数可以区分重载

 常成员函数的定义:

class person
{
public:
	void show()
	{
		cout << "show" << endl;
	}
	void show()const //const符号加到()后面 ,常成员函数可以区分重载
	{
		cout << "const show" << endl;
	}
};

常成员函数不能修改成员数据:

class person
{
public:
	void show()
	{
		a = 20;//可以,普通成员函数可以修改成员变量
		cout << "show" << endl;
	}
	void show()const
	{
		a = 20;//报错,常成员函数无法修改成员变量
		cout << "const show" << endl;
	}
	int a=10;
};

3.常对象:

  1. 定义时用const修饰
  2. 常对象初始化后,不能更新数据
  3. 常对象只能调用常成员函数,不能调用其他成员函数

 常对象的定义:

using namespace std;
class person
{
public:
	person(int a1,string b1):a(a1),b(b1){}
	int a;
	string b;
};

int main() {
	const person p1(10,"pppppp");//定义时用const修饰
	p1.a = 20;//报错,常对象无法修改成员变量
	return 0;
}

常对象只能调用常成员函数:

class person
{
public:
	person(int a1,string b1):a(a1),b(b1){}
	int a;
	string b;
	void show()
	{
		cout << "show" << endl;
	}
	void show()const
	{
		cout << "const show" << endl;
	}
};

int main() {
	const person p1(10,"pppppp");//定义时用const修饰
	p1.show();//常成员调用常成员函数
	return 0;
}

 常引用:

常引用的作用是防止实参传到形参是数据被修改

class person
{
public:
	//默认构造函数
	person();
	//拷贝构造函数
	person(const person &b)
	{
		//加了const可以防止 b中的数据被修改
		this->b = b.b;
		a = new int(*b.a);
	}

	int *a;
	int b;
};

mutable,可以让常成员函数和常对象修改成员数据 

class person
{
public:
	person(int a1):a(a1){}
	void show()const
	{
		a = 20; //可以,mutable使 a可以在常成员函数中修改
	}
	mutable int a;
};

int main() {
	const person p1(10);
	p1.a = 30;//常对象中也能修改
	return 0;
}

拓展:普通对象调用常成员函数

  1. 在类中,常函数没有重载时,会调用常函数
  2. 在类中,如果有重载时,会优先调用非常函数
class person
{
public:
	void show()const
	{
		cout << "const show" << endl;
	}

};

int main() {
	person p1;
	p1.show();//调用show函数,调用的是const类型的
	return 0;
}

class person
{
public:
	void show()
	{
		cout << "show" << endl;
	}
	void show()const
	{
		cout << "const show" << endl;
	}

};

int main() {
	person p1;
	p1.show();//调用show函数,优先调用非const类型的
	return 0;
}

 

易错点 :

调用:常函数在调用时,不能使用const修饰

class person
{
public:
	void show()
	{
		cout << "show" << endl;
	}
	void show()const
	{
		cout << "const show" << endl;
	}

};

int main() {
	person p1;
	p1.show()const;//错误,不能这么使用
	p1.const show()//错误,不能这么使用
	return 0;
}

类中的内存结构:

  1. 空类所占的内存为1,用来区分对象
  2. 函数不存储在类中
  3. 静态成员不存储在类中
  4. 非静态成员数据存储在类中(常量和变量)
  5. 指针  4个字节(32位),8个字节(64位)

注意:在类中也按照字节对齐的方式来计算内存,内存不受数据权限的印象(仅在单个类中,非继承)

空类的内存:

class person
{

};
int main()
{
	person p;
	cout << sizeof(p) << endl;
	return 0;
}

 只有函数的类:(函数不存放在类中)

class person
{
public:
	person(){}
	~person(){}
	void show()
	{
		cout << "show" << endl;
	}
};
int main()
{
	person p;
	cout << sizeof(p) << endl;
	return 0;
}

静态成员变量不存储在类中:

class person
{
public:
	static int a;
	static const int b = 20;
};
int person::a = 10;
int main()
{
	person p;
	cout << sizeof(p) << endl;
	return 0;
}

 

 非静态成员数据:(存储在类中)

class person
{
public:
	char c;
	int a;
	const int b = 20;
};
int main()
{
	person p;
	cout << sizeof(p) << endl;
	return 0;
}

 

混合计算也是按照上面的计算方法:

class person
{
public:
	person(){}
	void show() { cout << "show" << endl; }
	void show() const{ cout << "show" << endl; }
	char c;
	int a;
	const int b = 20;
	static int b1;
	static const int b2 = 20;
	int *p;//指针占4个字节(32位),(64位)8个字节
};
int person::b1 = 20;
int main()
{
	person p;
	cout << sizeof(p) << endl;
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值