1、C+中的类和对象中的类和对象 2FAQ1n如何理解类和对象?在面向对象程序设计中,类表示对现实世界中一类具在面向对象程序设计中,类表示对现实世界中一类具有共同特征的事物的抽象。有共同特征的事物的抽象。类类的定义是由两部分组成的,分别是声明部分和实现的定义是由两部分组成的,分别是声明部分和实现部分。声明部分用来声明该类的成员,包括数据成员部分。声明部分用来声明该类的成员,包括数据成员及成员函数及成员函数(数据成员即是属性,成员函数即是方法数据成员即是属性,成员函数即是方法),实现部分是成员函数的具体实现。实现部分是成员函数的具体实现。3class 类名public:公有数据成员或成员函数声明;p
2、rivate:私有数据成员或成员函数声明;protected:受保护数据成员或成员函数声明;4#include“iostream.h”class Stuprivate:char name20;int age;char sex10;public:void stuinfo()cout”name:”nameendl;cout”age:”ageendl;cout”sex:”sexendl;5#include“iostream.h”class Stuprivate:char name20;int age;char sex10;public:void stuinfo();void Stu:stuinfo(
3、)cout”name:”nameendl;cout”age:”ageendl;cout”sex:”sexendl;6n对象的定义方式:先定义类再定义对象定义类的同时定义对象#include“iostream.h”class Stuprivate:char name20;int age;char sex10;public:void stuinfo();Stu s1,s2;/对象对象#include“iostream.h”class Stuprivate:char name20;int age;char sex10;public:void stuinfo();s1,s2;7FAQ2n如何理解对象的
4、初始化?构造函数用来对类对象进行初始化,它完成对内存空构造函数用来对类对象进行初始化,它完成对内存空间的申请、赋初值等工作。间的申请、赋初值等工作。析构函数主要是用来做清理工作的。8class Stuprivate:char name20;int age;char sex10;public:Stu(charc120,char c210,int n);/构造函数void stuinfo();9class Stuprivate:char name20;int age;char sex10;public:Stu(charc120,char c210,int n);/构造函数void stuinfo(
5、);Stu();/析构函数;10#include#includeclass Stuprivate:char name20;int age;char sex10;public:Stu(char c120,char c210,int n);/构造函数void stuinfo();Stu();/析构函数;Stu:Stu(char c120,char c210,int n)/构造函数定义cout“constructor called!”endl;strcpy(name,c1);strcpy(sex,c2);age=n;11Stu:Stu()/析构函数定义cout“disconstructor call
6、ed!”endl;void Stu:stuinfo()cout”name:”nameendl;cout”age:”ageendl;cout”sex:”sexendl;void main()Stu s1(“Mary”,”w”,23),s2(“Jack”,”m”,25);s1.stuinfo();s2.stuinfo();12FAQ3n如何理解对象的生存周期?对象的生存周期是从对象创建到释放的一段时间。对对象的生存周期是从对象创建到释放的一段时间。对象可以按生存周期的不同分为象可以按生存周期的不同分为4种,即局部对象,全种,即局部对象,全局对象,静态对象和动态对象。局对象,静态对象和动态对象。局局
7、部对象的生存周期较短;静态对象的生存周期较长;部对象的生存周期较短;静态对象的生存周期较长;全局对象的生存周期最长;而动态对象的生存周期取全局对象的生存周期最长;而动态对象的生存周期取决于决于new运算符和运算符和delete运算符的之间的间隔。运算符的之间的间隔。13#include#includeclass Testchar*mp;public:Test(char*lp)/类Test的构造函数mp=NULL;coutTest:Test()endl;int len=strlen(lp)+1;/获得lp指向内容的长度mp=new charlen;/动态分配len大小的内存空间memset(mp
8、,0,len);/内存设置strncpy(mp,lp,len);/将len长的lp内容赋给mpTest()coutTest:Test()endl;if(NULL!=mp)delete mp;/如果mp的内容不为NULL,释放14operator char*()/重载char*类型return mp;/返回mp;int main()Test t=Test();char*p=t;coutcall fun beforeendl;coutlenstrlen(p)endl;coutendendl;return 0;15FAQ4n如何向函数传递对象?值传递值传递地地址传递址传递16#includeclas
9、s Testpublic:Test(int a)/构造函数 num=a;void setnum(int a)num=a;int getnum()return num;private:int num;void add(Test t)/类对象作为函数参数 t.setnum(t.getnum()+t.getnum();coutnnum value add.;coutt.getnum()endl;int main()Test tt(100);/调用构造函数 add(tt);/调用函数add(),参数按值传递 coutobject tt changed is main.;couttt.getnum()e
10、ndl;return 0;17#includeclass Testpublic:Test(int a)/构造函数num=a;void setnum(int a)num=a;int getnum()return num;private:int num;void add(Test*t)/类对象作为函数参数t-setnum(t-getnum()+t-getnum();coutnnum value add.;coutgetnum()endl;int main()Test tt(100);/调用构造函数add(&tt);/调用函数add(),参数按值传递coutobject tt changed is
11、main.;couttt.getnum()endl;return 0;18#includeclass Testpublic:Test(int a)/构造函数num=a;void setnum(int a)num=a;int getnum()return num;private:int num;void add(Test&t)/类对象作为函数参数t.setnum(t.getnum()+t.getnum();coutnnum value add.;coutt.getnum()endl;int main()Test tt(100);/调用构造函数add(tt);/调用函数add(),参数按值传递co
12、utobject tt changed is main.;couttt.getnum()endl;return 0;19FAQ5n编写C+类时需要注意哪些问题?使用关键字使用关键字class来定义来定义C+类时,类时,class必须是小写,必须是小写,其后面紧跟着类的名称。类以左大括号开始,右大括其后面紧跟着类的名称。类以左大括号开始,右大括号结束,大括号中的内容都属于该类的成员。号结束,大括号中的内容都属于该类的成员。一般情况下,在类体内先说明公有成员,然后说明私一般情况下,在类体内先说明公有成员,然后说明私有成员。在说明成员时,一般按照成员的类型由小到有成员。在说明成员时,一般按照成员的类
13、型由小到大的顺序说明。大的顺序说明。类中的数据成员的类型可以是任意的,包含整型、浮类中的数据成员的类型可以是任意的,包含整型、浮点型、字符型、数组、指针和引用等,也可以是另一点型、字符型、数组、指针和引用等,也可以是另一个类的对象、自身类的指针或引用,但是自身类的对个类的对象、自身类的指针或引用,但是自身类的对象是不可以的。象是不可以的。在类体中不允许对所定义的数据成员进行初始化。在类体中不允许对所定义的数据成员进行初始化。可以将类定义的说明部分或者整个定义部分可以将类定义的说明部分或者整个定义部分(包含实现包含实现部分部分)放到一个头文件中。放到一个头文件中。20声明类的静态变量时必须在类内
14、部和类外部的全局内存区中两次声明,但访问的方式与类中的普通成员相同。静态变量和函数可以在声明实例之前就被访问。默认的情况下,类中的成员都被认为是私有的,并且只能被类中的其他成员函数访问。通常情况下如果没有自定义构造函数,系统会自动定义默认且仅有的构造函数和析构函数。而且当使用自定义构造函数时,要求构造函数必须声明为公有。在C+中,存在3种类型的类,分别为类,结构和联合,三者使用不同的关键字来声明,分别为class,struct和union。在类的成员函数中调用非成员函数,在非成员函数前必须加上“:”。21类类结构结构联合联合声明和定义时使用的关键字声明和定义时使用的关键字 class stru
15、ctunion默认成员访问权限默认成员访问权限私有公有公有使用限制使用限制无无同时只能使用一个成员22FAQ6n如何理解构造函数?构造函数的主要功能是给对象分配空间,因为对象在构造函数的主要功能是给对象分配空间,因为对象在定义时都会默认调用构造函数,以此进行内存空间的定义时都会默认调用构造函数,以此进行内存空间的分配以及变量的初始化操作。分配以及变量的初始化操作。23#includeclass Timepublic:Time()/构造函数Time()hour=0;minute=0;sec=0;void set_Time();void show_Time();private:int hour;i
16、nt minute;int sec;int main()Time t1;t1.set_Time();t1.show_Time();Time t2;t2.show_Time();return 0;void Time:set_Time()cinhour;cinminute;cinsec;void Time:show_Time()couthour:minute:secendl;24n如果自己没有定义构造函数,系统会自动创建默认的无参数,空构造函数。如果自定义了一个构造函数,系统则不会自动创建默认构造函数。并且当声明类的实例时,需要使用自定义的构造函数。n构造函数必须是公有的。n构造函数的名称必须与类
17、名相同。n构造函数没有返回值。n构造函数是成员函数,函数体可写在类体内,也可定义在类体外。n构造函数是一个特殊的函数,该函数的名称与类名相同,不指定类型说明,有隐含的返回值,该值由系统内部使用。n程序中不能直接调用构造函数,在创建对象时系统自动调用构造函数。n构造函数可以无参数,可以有一个参数,也可以有多个参数。n构造函数可以重载,即可以定义多个参数个数不同的构造函数。25FAQ7n默认构造函数是什么,它有什么特点?如果程序中没有提供任何构造函数,则如果程序中没有提供任何构造函数,则C+提供一个默提供一个默认的构造函数,该默认构造函数是无参构造函数,它仅认的构造函数,该默认构造函数是无参构造函
18、数,它仅负责创建对象,不做任何初始化的工作。负责创建对象,不做任何初始化的工作。默认构造函数的特点如下:默认构造函数的特点如下:n在创建对象时编译器自动创建并调用。在创建对象时编译器自动创建并调用。n无参数,函数体为空。无参数,函数体为空。n仅当没有自定义构造函数时编译器才会自动创建。仅当没有自定义构造函数时编译器才会自动创建。26#include#includeclass Stupublic:Stu():val(6)Stu(int val):val(6)int val;void main()Stu s;couts.val;Stu arr4;coutarr2;vector vec(5);cou
19、tvec3.valendl;Stu*ptr=new Student4;coutptr1.val;Stu ss=Student();coutss.val;27FAQ8n何时调用拷贝构造函数?拷贝构造函数是由编译器调用,用来完成一系列基于拷贝构造函数是由编译器调用,用来完成一系列基于同一类的其他对象的构件及初始化,拷贝构造函数的同一类的其他对象的构件及初始化,拷贝构造函数的一般形式如下:一般形式如下:类名类名(类名类名&变量名变量名)函数体函数体;28n对象以值传递的方式传入函数体,即函数的返回值是对象,调用函数进行形参和实参结合时。例如:class Test;copyfun(Test p)/函数
20、的形参是类的对象int main()Test t;copyfun(t);/当调用函数,函数的实参传给形参,调用拷贝构造函数/省略29n对象以值传递的方式从函数返回,即函数的返回值是对象,函数返回值时。例如:class Test;Test copyfun()/函数的返回值是类的对象Test t(100);return t;/函数返回的是对象int main()Test t1;t1=copyfun();/返回函数值时,调用拷贝构造函数/省略30n对象需要通过其他对象进行初始化,即当使用类的一个对象去初始化该类的另一个对象时。例如:class Test;int main()Test t1;Test
21、t2(t1);/使用t1初始化t2/省略31#include#include/自定义类Personclass Personpublic:/公有声明部分Person(char*pn);/构造函数声明Person(Person&p);/拷贝构造函数声明Person();/析构函数声明private:/私有声明部分char*pname;/定义字符指针pname;/构造函数实现部分Person:Person(char*pn)coutPerson is called:pnendl;/输出pn里存储的字符串pname=new charstrlen(pn)+1;if(pname!=0)strcpy(pnam
22、e,pn);/将pn的值赋给pname32/拷贝构造函数实现部分Person:Person(Person&p)coutcope p.pname to new memoryn;pname=new charstrlen(p.pname)+1;/同构造函数,分配空间if(pname!=0)/判断是否分配成功strcpy(pname,p.pname);/复制字符串/析构函数实现部分Person:Person()coutPerson is called:pnameendl;/输出要析构的Person对象的值pname0=0;/将字符串赋空值delete pname;/释放pname所在的内存空间void
23、 main()Person p1();/用构造函数定义Person对象p1,为其字符串赋值Person p2(p1);/用拷贝构造函数定义Person对象p2,其字符串与p1相同33FAQ9n深拷贝与浅拷贝的区别是什么?浅拷贝就是对默认拷贝构造函数所实现的数据成员逐浅拷贝就是对默认拷贝构造函数所实现的数据成员逐一赋值,如果类中包含指针类型数据,将会产生错误。一赋值,如果类中包含指针类型数据,将会产生错误。为了解决该问题,需要显式定义拷贝构造函数,使其为了解决该问题,需要显式定义拷贝构造函数,使其不但可以复制数据成员,而且可以为对象分配内存空不但可以复制数据成员,而且可以为对象分配内存空间,这就
24、是深拷贝。间,这就是深拷贝。class A;A a1;A a2=a1;/调用拷贝赋值函调用拷贝赋值函数数A a3(a1);/调用拷贝构造函调用拷贝构造函数数class Apublic:/省略省略int cint;char*cp;/指指针变量针变量cp;34A:A(const A&a)cint=a.cint;int len=strlen(a.cp);cp=new charlen;memcopy(cp,a.cp,len);/省略A A:operator=(A&b)if(a.cp!=NULL)delete a.cp;cint=a.cint;int len=strlen(a.cp);cp=new ch
25、arlen;memcopy(cp,a.cp,len);/省略35深拷贝和浅拷贝的区别n当拷贝对象状态中包含其他对象的引用时,如果需要复制的是引用对象指向的内容,而不是引用(内存地址),则是深拷贝,否则是浅拷贝。n浅拷贝就是成员数据之间的赋值,当值拷贝时,两个对象就有共同的资源。而深拷贝是先将资源复制一份,使对象拥有不同的资源,但资源内容是相同的。n深拷贝在处理引用时,如果改变新对象内容将不会影响到原对象内容。n浅拷贝资源后释放资源时可能会产生资源归属不清楚的情况,从而导致程序运行出错。36FAQ10n如何理解析构函数?析构函数,其作用与构造函数刚好相反,是用来清理析构函数,其作用与构造函数刚好
26、相反,是用来清理内存中无用的资源。只有当一个对象的生命周期结束内存中无用的资源。只有当一个对象的生命周期结束时才调用析构函数。时才调用析构函数。37n没有使用析构函数的程序的代码如下:class Baudpublic:Baud(long speed);private:int m_aSpeed;char*m_pszSpeed;Baud:Baud(int speed)m_aSpeed=new char10;if(m_pSpeed!=NULL)sprint(m_pszSpeed,“%ld”,speed);38n构造函数和析构函数的区别:每个类可以有多个构造函数,但却只能有一个析构函数。可以自定义带参
27、数的构造函数,但是却不允许为析构函数传递参数。n 析构函数的特点如下。析构函数是成员函数,函数体可以写在类的内部,也可以写在类的外部。析构函数是一个特殊函数,其名称与类名相同,并在前面加“”字符,用来与构造函数加以区别。析构函数不可以指定返回值类型,也没有参数。一个类中只允许定义一个析构函数。析构函数可以手动调用,也可以被系统调用。39#includeclass Destoryint x,y,z;public:Destory()x=y=z=0;Destory()/析构函数coutdestructor.n;Destory(int i,int j,int k)x=i;y=j;z=k;Destory operator=(Destory op2);void show();40Destory Destory:operator=(Destory op2)x=op2.x;y=op2.y;x=op2.z;return*this;void Destory:show()coutx,;couty,;coutzn;int main()/主函数Destory a(1,2,3),c;coutbefore c=a;n;c=a;coutafter c=a;n;c.show();return 0;41Thank you!