类与对象总结
一、知识点
1、类的定义
1)、类是对具有相同属性和行为的一组对象的抽象与统一描述。是用户自定义的数据类型;
类的定义包括行为和属性两个部分;
属性以数据表示,行为通过函数实现。
2)、类的定义格式
class 类名
{
public:
公有数据成员和成员函数;
protected:
保护数据成员和成员函数;
private:
私有数据成员和成员函数;
}; (”;“不可省略)
3)、类定义举例
classStudent //定义学生类Student
{
public: //声明类成员
void Getinfo(string pname, string pid
,char Sex, int a,double s);
void modify(float s);
void display();
private:
string name;
stringid;
char sex;
intage;
double score;
}; //类定义以分号结束
4)、注:
类的成员可以是其他类的对象,但不能以类自身的对象作为本类的成员,而类自身的指针和引用可以作为类的成员。
类定义必须以分号“;”结束。
类与结构体的区别:
没有明确指定类成员的访问权限时,C++结构体的成员是公有的,而类的成员是私有的。
在类的定义中不能对数据成员进行初始化。
类的任何成员都必须指定访问属性,一般将数据成员定义为私有成员或保护成员,将成员函数定义为公有成员。
类中的数据成员可以是C++语法规定的任意数据类型。
类的成员可以是其他类的对象,称为类的组合。但不能以类自身的对象作为本类的成员。
类定义必须以分号“;”结束
class与struct的不同:
① class中,成员缺省情况是private。
② struct中,成员缺省情况是public。
2、访问控制
类的访问属性:
1)、Public:公有成员,是类与外部的接口
2)、Protected:保护成员,控制仅允许本类成员函数及派生类成员函数进行访问
3)、Private:私有成员,仅允许本类成员函数访问
3、成员函数
1)、类的成员函数是实现类的行为属性的成员。
一般将成员函数声明为函数原型,在类外具体实现成员函数。
2)、定义:
返回值类型 类名::成员函数名(参数表)
{
函数体
}
3)、
Set成员函数:修改成员值;
Void setx(int a)
{x=a;}
get成员函数:返回成员值。
Void getx()
{return x;}
4、对象
1)、对象是类的实例或实体。
类与对象的关系,如同C++基本数据类型和该类型的变量之间的关系。
2)、定义格式:
类名 对象名1,对象名2,…,对象名n;
注:必须在定义了类后才可以定义类的对象。
5、类成员的访问
1)、圆点访问形式:对象名.公有成员
2)、指针访问形式: 对象指针变量名->公有成员
定义一个指针变量,用它去访问成员
例:
#include<iostream>
using namespace std;
class CTest
{
private:
int x;
int y;
public:
CTest(int value_x,int value_y);
x = value_x ;
y = value_y ;
}
~CTest(){}
void getValue()
{
cout << "x::"<< x << endl;
cout << "y::"<< y << endl;
}
};
void getClassValue(CTest*ctest)
{
int* flag = (int*)(ctest);
cout << "getClassValue:: "<< *flag << endl;
cout << "getClassValue:: "<< *(++flag) << endl;
int main()
{
CTest* test = new CTest(1,2);
test->getValue();
getClassValue(test);
delete test;
return 0;
}
6、内联函数
内联函数作用 :
减少频繁调用小子程序的运行的时间开销,适用于短代码
内联函数机制 :
编译器在编译时,将内联函数的调用以相应代码代替
内联函数声明
inline 函数原型
注:内联函数仅在函数原型作一次声明。
适用于只有1 ~ 5行的小函数
不能含有复杂结构控制语句 ,不能递归调用
7、函数重载
函数名相同,但参数不相同(类型不同,或者个数不同)的一组函数。
编译器根据不同参数的类型和个数产生调用匹配
函数重载用于处理不同数据类型的类似任务
8、构造函数
1)、基本定义:
构造函数是用于创建对象的特殊成员函数
当创建对象时,系统自动调用构造函数
构造函数的作用是: 为对象分配空间;对数据成员赋初值;请求其他资源
用户未定义的构造函数时,系统提供缺省版本的构造函数
构造函数名与类名相同:类名
构造函数可以重载
构造函数可以有任意类型的参数,但没有返回类型
2)、如果类中没有定义构造函数,系统将自动生成一个默认形式的构造函数,用于创建对象。
形式:类名::类名(){} ;(默认构造函数是一个空函数)
3)、定义与使用
#include<iostream>
usingnamespace std;
classDate {
public:
Date(); // 无参构造函数
Date(int y,int m,int d);
void showDate();
private:
int year, month, day;
};
Date::Date() // 构造函数的实现
{
year=0;
month=0;
day=0;
}
Date::Date(inty,int m,int d)
{
year=y;
month=m;
day=d;
}
inlinevoid Date::showDate()
{
cout<<year<<"."<<month<<"."<<day<<endl;
}
int main()
{
Date a_date,b_date(2014,3,25);
a_date.showDate();
b_date.showDate();
return 0;
}
(a_date调用无参构造函数,b_date调用有参构造函数。)
4)、利用构造函数创建对象:
l 利用构造函数直接创建对象.其一般形式为:
类名 对象名[(实参表)];
这里的“类名”与构造函数名相同,“实参表”是为构造函数提供的实际参数。
l 利用构造函数创建对象时,通过指针和new来实现。其一般语法形式为:
类名 *指针变量 =new 类名[(实参表)];
例如:
Date *date1=new Date(1998,4,28);
就创建了对象(*date1)。
5)、构造函数初始化成员
l 使用构造函数的函数体进行初始化
class Date
{
intd, m, y;
public:
Date(intdd, int mm, int yy)
{
d=dd;
m=mm;
y=yy;
}
Date(intdd, int mm)
{
d=dd;
m=mm;
}
}
l 使用构造函数的初始化列表进行初始化
格式:
funname(参数列表):初始化列表
{ 函数体,可以是空函数体 }
初始化列表的形式:
成员名1(形参名1),成员名2(形参名2),成员名n(形参名n)
class Date
{
intd, m, y;
public:
Date(intdd, int mm, int yy):d(dd),m(mm),y(yy)
{ 函数体可以为空 }
l 以下情况必须用初始化表:
数据成员为常量
数据成员为引用类型
数据成员为没有无参构造函数类的对象
#include<iostream>
usingnamespace std;
classA{
public:
A(int i):x(i),rx(x),pi(3.14)
{}
void display()
{cout<<"x="<<x<<"rx="<<rx<<"pi="<<pi<<endl;}
private:
int x,℞
const float pi;
};
intmain(){
A aa(10);
aa.display();
return 0;
}
(rx为引用,pi为常量)
#include<iostream>
usingnamespace std ;
classA
{public :
A ( int x ) : a ( x ) { }
int a ;
} ;
classB
{public :
B( int x, int y ) : aa( x ), b( y ) { }
void out()
{ cout << "aa = "<< aa.a << endl << "b = " << b << endl; }
private :
int b ;
A aa ;
} ;
intmain ()
{ B objB ( 3, 5 ) ;
objB . out ( ) ;
}
(aa为A类的对象)
6)、带默认值的构造函数
#include<iostream>
usingnamespace std;
classBox
{
public:
Box(int h=10,int w=10 , int l=10);
int volume();
private:
int height,width, length;
};
Box::Box(inth, int w,int l):height(h),width(w),length(l)
{}
intBox::volume(){
return width*length*height;
}
intmain()
{
Box box1;
cout<<"The volume is"<<box1.volume();
Box box2(12,30,25);
cout<<"The volume is"<<box2.volume();
Box box3(30,25);
cout<<"The volume is"<<box3.volume();
return 0;
}
7)、构造函数的重载
classBox{
public:
Box();
Box(int ,int , int);
int volume();
private:
int height,width, length;
};
8)、类成员的初始化的顺序:
按照数据成员在类中的声明顺序进行初始化,与初始化成员列表中出现的顺序无关
9、析构函数
1)、基本定义:
析构函数是用于取消对象的成员函数
当一个对象作用域结束时,系统自动调用析构函数
析构函数的作用是进行对象消亡时的清理工作
没有用户定义析构函数时,系统提供缺省版本的析构函数
析构函数名为: 类名
析构函数没有参数,也没有返回类型
2)、定义格式:
类名::~类名()
{
函数语句
}
若没有显式定义析构函数,则系统自动生成一个默认形式的析构函数。
系统自动生成的默认构造函数形式如下:
类名::~类名(){}
#include<iostream>
#include<string>
usingnamespace std;
classStudent{
public:
Student(int n, string a_name, char s) {
num=n;
name=a_name;
sex=s; cout<<"Constructorcalled."<<endl;
}
~Student()
{ cout<<"Destructorcalled."<<endl; }
void display()
{cout<<name<<endl;cout<<num<<endl;cout<<sex<<endl; }
private:
int num; string name; char sex;
};
intmain()
{
Studentstud1(10001,"Wang_li",'f');
stud1.display();
Studentstud2(10002,"Zhao_Wu",'s');
stud2.display();
return 0;
}
3)、特点
① 析构函数与构造函数名字相同,但它前面必须加一个波浪号(~);
② 析构函数没有参数,也没有返回值,而且不能重载。因此在一个类中只能有一个析构函数;
③ 当撤消对象时,编译系统会自动地调用析构函数。
4)、
一般情况下,可以不定义析构函数
但如果类的数据成员中包含指针变量是从堆上进行存储空间分配的话,需要在析构函数中进行存储空间的回收
10、this指针:
1)、用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间。为区分不同的实例对象的数据成员,C++为此专门设立了一个名为this的指针,用来指向不同的对象。 一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。
2)、需要显式引用this指针的三种情况
l 在类的非静态成员函数中返回类对象本身或对象的引用的时候,直接使用 return*this,返回本对象的地址时,return this。
l 当参数与成员变量名相同时,如this->x= x,不能写成x = x。
l 避免对同一对象进行赋值操作,判断两个对象是否相同时,使用this指针。
3)、
#include<iostream>
#include<string>
usingnamespace std;
classPerson{
public:
Person(string n, int a) {
name = n; //这里的 name 等价于this->name
age = a; //这里的 age 等价于this->age
}
int get_age(void) const{ return age; }
Person& add_age(int i) {age += i; return *this; }
private:
string name;
int age;
};
intmain()
{
Person Li("Li", 20);
cout<<"Li age = "<<Li.get_age()<<endl;
cout<<"Li add age ="<< Li.add_age(1).get_age()<<endl;
//增加1岁的同时,可以对新的年龄直接输出;
return 0;
}
(this指针返回类对象所引用的addage函数,完成年龄的增加)
4)、参数与变量名相同时
#include<iostream>
usingnamespace std;
classPoint
{
public:
int x;
Point ():x(0){}
Point (int a){ x=a; }
void print(){ cout<<"x ="<<x<<endl; }
void set_x(int x){ this ->x = x; }
};
intmain(){
Point pt(5);
pt.set_x(10);
pt.print();
return 0;
}
用this ->x = x,不能直接用x=x。
5)、用this指针判断对象是否相同,要避免对同一对象进行赋值操作。
11、复制析构函数
1)、基本概念及基本工作:
复制构造函数用一个已有同类对象创建新对象进行数据初始化
C++为类提供默认版本的复制构造函数
程序员可以定义用户版本的复制构造函数
语法形式
类名 :: 类名(const 类名 & 引用名 , …);
voidmain(){
Point a(5,10),b(a);
}
例:#include <iostream>
usingnamespace std;
classBox{
public:
Box(int =10, int =10, int =10);
Box(const Box & b)
{height=2*b.height; width=2*b.width;length=2*b.length;}
int volume();
private:
int length, height, width;
};
Box::Box(inth, int w, int l):length(l),width(w),height(h){ }
intBox::volume (){ returnwidth*height*length;}
intmain(){
Box box1(1,2,3),box2(box1),box3=box2;
cout<<"Box1's volume is"<<box1.volume()<<endl;
cout<<"Box2's volume is"<<box2.volume()<<endl;
cout<<"Box3's volume is"<<box3.volume()<<endl;
return 0;
}
把box1复制给box2,又把box2复制给box3
2)、特点复制构造函数名与类名相同,并且也没有返回值类型。
l 复制构造函数可写在类中,也可以写在类外。
l 复制构造函数要求有一个类类型的引用参数。
l 如果没有显式定义复制构造函数,系统自动生成一个默认形式的复制构造函数
3)、复制构造函数调用
l 声明语句中用类的一个已知对象初始化该类的另一个对象时。
l 当对象作为一个函数实参传递给函数的形参时,需要将实参对象去初始化形参对象时,需要调用复制构造函数。
l 当对象是函数的返回值时,由于需要生成一个临时对象作为函数返回结果,系统需要将临时对象的值初始化另一个对象,需要调用复制构造函数。
4)、浅复制与深复制
浅复制:
●在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,使两个对象同时指向了同一资源的复制方式称为浅复制(即:对于复杂类型的数据成员只复制了存储地址而没有复制存储内容)。
●默认复制构造函数所进行的是简单数据复制,即浅复制。
浅复制不能复制复杂数据类型成员,如:
#include<iostream>
#include<string.h>
usingnamespace std;
classPerson
{
public:
Person(char* name1,int a,double s);
voiddisplay(){cout<<name<<"\t"<<age<<"\t"<<salary<<endl;}
~Person(){delete name;}
private:
char*name;
int age;
double salary;
};
Person::Person(char*name1,int a,double s)
{
name=new char[strlen(name1)+1];
strcpy(name,name1);
age=a;
salary=s;
}
intmain()
{
Person*P1=new Person("WangWei",8,3880); //调用构造函数创建对象P1
P1->display();
Person P2(*P1); //调用复制构造函数,用P1的数据初始化对象P2
delete P1;
P2.display();
return 0;
}
上述程序,未自定义构造函数,系统调用默认复制构造函数,进行浅复制,姓名不能正确复制。
深复制:
●通过一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源的复制方式称为深复制。
●自定义复制构造函数所进行的复制是深复制。
深复制构造函数必须显示定义。
定义:类名::类名([const]类名 &对象名);
成员变量的处理:对复杂类型的成员变量,使用new操作符进行空间的申请,然后进行相关的复制操作。
12、类的其他成员
类定义中除了一般指定访问权限的成员,还可以定义各种特殊用途的成员。
1)、常成员
l 常数据成员
常数据成员是指数据成员在实例化被初始化后,其值不能改变。
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数。
使用const说明的数据成员称为常数据成员。
如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员
#include<iostream>
using namespacestd;
class Mclass
{ public :
int k;
const int M; //说明常数据成员
Mclass() : M(5) { } //用初始式对常数据成员赋值
void testFun()
{ //M++; //错误,不能在成员函数中修改常数据成员
k++; //可以修改一般数据成员
}
} ;
int main()
{ Mclass t1, t2;
t1.k=100;
//t1.M=123; //错误,不能在类外修改常数据成员
cout<<"t1.k="<<t1.k<<'\t'<<"t1.M="<<t1.M<<endl;
t2.k=200; t2.testFun();
cout<<"&t1.M="<<&t1.M<<endl;
cout<<"t2.k="<<t2.k<<'\t'<<"t2.M="<<t2.M<<endl;
cout<<"&t2.M="<<&t2.M<<endl;
}
2)、常对象
如果在说明对象时用const修饰,则被说明的对象为常对象。
常对象的说明形式:
类名 const 对象名[(参数表)];
或者
const 类名 对象名[(参数表)];
在定义常对象时必须进行初始化,而且不能被更新。
说明:
C++不允许直接或间接更改常对象的数据成员。
C++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限)。
3)、常成员函数
在类中使用关键字const说明的函数为常成员函数,常成员函数的说明格式如下:
类型说明符 函数名(参数表) const;
const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)
13、静态成员
1)、类成员冠以static声明时,称为静态成员。
静态数据成员为同类对象共享。
静态成员函数与静态数据成员协同操作。
2)、静态成员不属于某一个单独的对象,而是为类的所有对象所共有
静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员: 保证在不依赖于某个对象的情况下,访问静态数据成员
3)、静态数据成员在定义或说明时前面加关键字static,如:
classA
{
int n;
static int s;
};
对于静态数据成员,每个类只拥有一个副本。(在静态存储区分配一个存储空间,对所有对象都是可见的)
公有访问权限的静态成员,可以通过下面的形式进行访问
类名::静态成员的名字
对象名.静态成员名字
对象指针->静态成员的名字
在静态成员函数内部,直接访问。
4)、静态成员函数
l 除静态数据成员以外,一个类还可以有静态成员函数。
静态函数仅可以访问静态成员, 或是静态成员函数或是静态数据成员。
静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
静态成员函数没有this指针,只能对静态数据操作
注:
静态成员函数在类外定义时不用static前缀。
静态成员函数主要用来访问同一类中的静态数据成员。 私有静态成员函数不能在类外部或用对象访问。
可以在建立对象之前处理静态数据成员。
编译系统将静态成员函数限定为内部连接(在其他文件中不可见)。
静态成员函数中是没有this指针的。
静态成员函数不访问类中的非静态数据成员。如有需要,只能通过对象名(或指向对象的指针)访问该对象的非静态成员。
l 定义静态成员函数的格式:
static 返回类型 静态成员函数名(参数表);
与静态数据成员类似,调用公有静态成员函数的一般格式有如下几种:
类名::静态成员函数名(实参表)
对象. 静态成员函数名(实参表)
对象指针->静态成员函数名(实参表)
l #include<iostream>
using namespacestd;
class small_cat{
public:
small_cat(doublew){weight=w;total_weight+=w;total_number++;}
static void display(small_cat &w)
{cout<<"The small_cat weights"<<w.weight<<"kg\n";}
static void total_disp()
{cout<<total_number<<"small_cat total weight ";
cout<<total_weight<<"kg "<<endl;}
private:
double weight;
static double total_weight; static double total_number;
};
doublesmall_cat::total_weight=0;double small_cat::total_number=0;
it main()
{ small_cat w1(0.9),w2(0.8),w3(0.7);
small_cat::display(w1);small_cat::display(w2);
small_cat::display(w3);small_cat::total_disp();
return 0;}
静态成员函数要调用非静态成员,必须建立一个临时对象,通过对象名调用
14、友元函数
1)、基本定义
如果在本类(类A)以外的其他地方定义了一个函数(函数B),这个函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。
在类体中用friend对其(函数B)进行声明,此函数就称为本类(类A的友元函数。
友元函数(函数B)可以访问这个类(类A)中的私有成员 。
注:
友元函数可以访问其他类,但会迫坏系统的封装性,因此一般不使用。
使用不同类友元函数时,定义类有一定的顺序,有时需要对要引用的类提前声明。
15、类的包含(类的组合)
1)、基本概念
类的包含是程序设计中一种软件重用技术。即定义一个新的类时,通过编译器把另一个类“抄”进来。
当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。
构造函数 ( 形参表 ) : 对象成员1(形参表 ) , … , 对象成员n (形参表 ) ;
2)、对象成员的初始化
出现成员对象时,该类的构造函数要包含对象成员的初始化。如果构造函数的成员初始化列表没有对成员对象初始化时,则使用成员对象的无参(缺省)构造函数。
建立一个类的对象时,要先执行成员对象自己的构造函数,再执行当前类的构造函数。
例:
#include<iostream>
usingnamespace std;
classA
{public:
A(int x):a(x){ }
int a ;
};
classB
{public:
B( int x, int y ) : aa(x) { b = y ; }
void out() { cout<<"aa ="<<aa.a<<endl<<"b = "<<b<<endl ; }
private:
int b ;
A aa ;
} ;
intmain()
{ BobjB( 3, 5 ) ;
objB.out() ;
}
aa是A类的对象,调用构造函数是,先调用A的构造函数,对aa初始化,要注意a是共有数据成员。
16、对象数组
1)、
所谓对象数组是指每一数组元素都是对象的数组。
定义一个一维对象数组的格式:
类名 数组名[下标表达式];
2)、对象数组的初始化
l 当对象数组所属的类中包含带参的构造函数,可用初始化列表完成对象数组的初始化。
l 当对象数组所属的类中包含无参的构造函数,也可以先定义,再给每个数组元素赋值
int main(){
Pointp1[4];
p1[0]=Point(1,1);
}
l 当对象数组所属的类中包含单个参数的构造函数,可简写。
二、题型总结
1、输入矩形的长和宽,输出面积和周长
将长、宽变量和设置长,宽,求面积,以及求周长的三个函数“封装”在一起,就能形成一个“矩形类”。
长、宽变量成为该“矩形类”的“成员变量”,三个函数成为该类的“成员函数”
#include<iostream>
usingnamespace std;
classCRectangle
{
public:
int w,h;
int Area() {
return w * h;
}
int Perimeter() {
return 2 * ( w + h);
}
void Init( int w_,int h_ ) {
w = w_; h = h_;
}
};
intmain( )
{
intw,h;
CRectangle r;
cin>> w >> h;
r.Init( w,h);
cout<< r.Area() << endl << r. Perimeter();
return 0;
}
2、创建一个Student类,该类中具有学生姓名,学号,性别,年龄,三科成绩、平均成绩等数据成员。在该类中定义成员函数实现相关信息的输入、输出。
#include<cstring>
#include<iostream>
usingnamespace std;
classStudent
{
public:
Student(int n, char * a_name, char s)
{
num=n; name=new char[strlen(a_name)+1];
strcpy(name,a_name); sex=s;
cout<<"Constructorcalled."<<endl;
}
~Student(){
cout<<"Destructorcalled."<<endl;
delete[] name;
}
void display()
{
cout<<name<<endl;cout<<num<<endl;cout<<sex<<endl;
}
private:
int num; char*name; char sex;
};
intmain()
{
Studentstud1(10001,"Wang_li",'f');
stud1.display();
Studentstud2(10002,"Zhao_Wu",'s');
stud2.display();
return 0;
}
3、某商店经销一种货物,货物成箱进,成箱卖出,购进和卖出都是以重量为单位(每箱的重量不同),商店需要记录下存货的总重量。
(定义一个货物类,表示一箱货物,类中包含
私有成员 weight
一个静态数据成员total_weight;
定义in函数,表示进货,进货时total_weight的值增加
定义out函数,表示出货,出货时total_weight的值减少)
#include<iostream>
usingnamespace std;
classGoods{
int weight;
public:
static int total_weight;
Goods(int x):weight(x){}
void in() {total_weight=total_weight+weight; }
void out(){total_weight=total_weight-weight; }
void display_store(){cout<<total_weight<<endl;}
};
intGoods::total_weight=0;
voiddisplay_store(){ cout<<Goods::total_weight<<endl;}
intmain(){
Goods g1(10),g2(20);
g1.in(); g2.in();
g1.display_store(); g2.display_store(); display_store();
g1.out(); g1.display_store(); display_store();
return 0;
}
三、心得体会
这一章学习了类的定义及使用,了解了类的成员、对象、成员函数等概念。总的来说,概念比较多,也都是新知识,比较繁琐,我不能很好地记住这些概念,在对这些的应用上也很生疏,甚至说不怎么会。但总算大体的有些了解,知道为什么要用,在对概念的理解及应用上需要多下功夫。老师一直再强调应用,而不是对概念的记忆什么的,也的确,我们学来就是为了实践,为了解决问题。通过这一章的学习,知道了怎么去定义一个类,在对学生管理系统的调试中了解到完成解决一个问题的大致思路还有对一个系统程序的调试。要通过一个系统解决一个问题,首先要了解系统所要实现的功能,怎么实现这些功能。要用到哪些数据,怎么定义,怎么去操作。确定问题的大体方向,然后不断分解、细化成所能用程序解决的问题。然后才能开始写程序。大概是数据类然后操作类。写完一个类要先调通在进行下一个类,否则问题越积越多最后就解决不了了。增加一个新的功能就在主函数中调试一遍,循序渐进。和程序一样,学习写它也是一个循序渐进的过程,需要不断的累计。目前能力太低,什么问题也解决不好,所以需要花更多的时间,去写,去调,才能一点点的熟练起来。多练习,多思考,多动手,多花时间。