还剩45页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
计算机二级考试复习资料全C++
一、概述C++-发展历史年,博士开始着手创立一种模拟语言,可以具有面向对象的程1980Bjarne Stroustrup序设计特色在当时,面向对象编程还是一种比较新的理念,博士并不是从头开Stroustrup始设计新语言,而是在语言的基础上进行创立这就是语言C C++年,开始在外面慢慢流行通过数年的发展,已经有了多种版本为次,1985C++C++和的联合委员会于年着手为制定原则年月,该委员会出版了ANSI ISO1989C++19942第一份非正式草案,年正式推出了的国际原则1998C++二和C C++是的超集,也可以说是的子集,由于先出现按常理说,编译器C++C C C++C C++可以编译任何程序,不过和还是有某些小差异C C C++例如增长了不具有的关键字这些关键字能作为函数和变量的标识符在程序C++C C中使用,尽管包括了所有的但显然没有任何编译器能编译这样的程序C++C,C++C程序员可以省略函数原型,而不可以,一种不带参数的函数原型必须把C C++C void写出来而可以使用空参数列表C++中和是对内存分派的运算符,取代了中的和C++new deleteC malloc free原则中的字符串类取代了原则函数库头文献中的字符数组处理函数C++C C中用来做控制态输入输出的类库替代了原则中的函数库C++iostream Cstdio中的异常处理机制取代了原则中的和函数C++try/catch/throw CsetjmpO longjmpO
二、关键字和变量相对与增长了某些关键字,如下C++Ctypename booldynamic_cast mutablenamespacestatic_cast usingcatch explicitnewvirtual operatorfalse privatetemplatevolatile constprotected thiswchar_tconst_cast publicthrow friendtruereinterpret_cast trybitorxor_e and_eq complor_eqnot_eq bitand在中还增长了型变量和型变量C++bool wchar_t布尔型变量是有两种逻辑状态的变量,它包括两个值真和假假如在体现式中使用了布尔型变量,那么将根据变量值的真假而赋予整型值或要把一种整型变量转换成10布尔型变量,假如整型值为则其布尔型值为假;反之假如整型值为非则其布尔型值为0,0,真布儿型变量在运行时一般用做标志,例如进行逻辑测试以变化程序流程#include iostream.hint mainboolflag;二flag true;ifflag cout return0;面的函数就是构造函数容许同名函数,也就容许在一种类中有多种构造函数Box C++假如一种都没有,编译器将为该类产生一种默认的构造函数,这个构造函数也许会完毕某些工作,也也许什么都不做绝对不能指定构造函数的类型,虽然是型都不可以实际上构造函数默认为void void型o当一种类的对象进入作用域时,系统会为其数据组员分派足够的内存,不过系统不一定将其初始化和内部数据类型对象同样,外部对象的数据组员总是初始化为局部对0象不会被初始化构造函数就是被用来进行初始化工作的当自动类型的类对象离开其作用域时,所站用的内存将释放回系统看上面的例子,构造函数函数接受三个整型擦黑素,并把他们赋值给立方体对Box象的数据组员假如构造函数没有参数,那么申明对象时也不需要括号.使用默认参数的构造函数1当在申明类对象时,假如没有指定参数,则使用默认参数来初始化对象#include iostream.hclass Boxprivate:int height,width,depth;public:Boxint ht=2,int wd=3,int dp=4height=ht;二width wd;depth=dp;〜Box;int volumereturn height*width*depth;;int main〃初始化Box thisbox3,4,5;使用默认参数Box defaulbox;//cout coutreturn0;.默认构造函数2没有参数或者参数都是默认值的构造函数称为默认构造函数假如你不提供构造函数,编译器会自动产生一种公共的默认构造函数,这个构造函数什么都不做假如至少提供一种构造函数,则编译器就不会产生默认构造函数,重载构造函数3一种类中可以有多种构造函数这些构造函数必须具有不一样的参数表在一种类中需要接受不一样初始化值时,就需要编写多种构造函数,但有时候只需要一种不带初始值的空的对象Box#include iostream.hclass Box{private:int height,width,depth;public:Box{//nothing}Boxint ht=2,int wd=3,int dp=4height=ht;二width wd;depth=dp;〜Box;int volumereturn height*width*depth;;int main〃初始化Box thisbox3,4,5;Box otherbox;otherbox=thisbox;cout return0;这两个构造函数一种没有初始化值,一种有当没有初始化值时,程序使用默认值,即2,3,4o不过这样的程序是不好的它容许使用初始化过的和没有初始化过的对象,但它Box没有考虑当给赋值失败后,该返回什么很好的措施是,没有thisbox otherboxvolume参数表的构造函数也把默认值赋值给对象class Boxint height,width,depth;public:Boxheight=O;width=O;depth=O;Boxint ht,int wd,int dpheight=ht;width=wd;depth=dp;int volumereturnheight*width*depth;;这还不是最佳的措施,更好的措施是使用默认参数,主线不需要不带参数的构造函数class Box{int height,width,depth;public:Boxint ht=O,int wd=0,int dp=Oheight=ht;width=wd;depth=dp;int volumereturnheight*width*depth;
三、析构函数当一种类的对象离开作用域时,析构函数将被调用(系统自动调用)析构函数的名字和类名同样,不过要在前面加上对一种类来说,只能容许一种析构函数,析构函数不〜能有参数,并且也没有返回值析构函数的作用是完毕一种清理工作,如释放从堆中分派的内存我们也可以只给出析构函数的形式,而不给出起详细函数体,其效果是同样的,如上面的例子但在有些状况下,析构函数又是必需的如在类中从堆中分派了内存,则必须在析构函数中释放二级辅导笔记类的转换C++的内部数据类型遵照隐式类型转换规则假设某个体现市中使用了一种短整型变量,C++而编译器根据上下文认为这儿需要是的长整型,则编译器就会根据类型转换规则自动把它转换成长整型,这种隐式转换出目前赋值、参数传递、返回值、初始化和体现式中我们也可认为类提供对应的转换规则对一种类建立隐式转换规则需要构造一种转换函数,该函数作为类的组员,可以把该类的对象和其他数据类型的对象进行互相转换申明了转换函数,就告诉了编译器,当根据句法鉴定需要类型转换时,就调用函数有两种转换函数一种是转换构造函数;另一种是组员转换函数需要采用哪种转换函数取决于转换的方向
一、转换构造函数当一种构造函数仅有一种参数,且该参数是不一样于该类的一种数据类型,这样的构造函数就叫转换构造函数转换构造函数把别的数据类型的对象转换为该类的一种对象和其他构造函数同样,假如申明类的对象的初始化表同转换构造函数的参数表相匹配,该函数就会被调用当在需要使用该类的地方使用了别的数据类型,廉价器就会调用转换构造函数进行转换#include iostream.h#include time.h#include stdio.hclass Date int mo,da,yr;public:Datetime_t;void displayO;;void Date::display charyear
[5];ifyr10sprintfy ear,0%d,y r;elsesprintfyear,%d,yr;cout}Date::Datetime_t nowtm*tim=localtimenow;da=tim-tm_rnday;mo=tim-tm_mon+1;yr=tim-tm_year;ifyr=100yr-=100;int maintime_t now=time0;Date dtnow;dt.displayO;return0;本程序先调用函数来获取目前时间,并把它赋给」对象;然后程序通过调time time用类的转换构造函数来创立一种对象,该对象由」对象转换而来」对Date Date time time象先传递给函数,然后返回一种指向构造文献中申明的指针,然后localtimc tmtime.h构造函数把构造中的口月年的数值拷贝给对象的数据组员,这就完毕了从对象Datetime_t到对象的转换Date
二、组员转换函数组员转换函数把该类的对象转换为其他数据类型的对象在组员转换函数的申明中要用到关键字这样申明一种组员转换函数operatoroperator aaa;在这个例子中,就是要转换成的数据类型的阐明符这里的类型阐明符可以是任aaa何合法的类型,包括其他的类如下来定义组员转换函数;C++Classname::operator aaa类名标识符是申明了该函数的类的类型阐明符上面定义的类并不能把该类的Date对象转换回」型变量,但可以把它转换成一种长整型值,计算从月日到目前的天time11数#include iostream.h class Dateint mo,da,yr;public:〃申明Dateint m,int d,int y{mo=m;da=d;yr=y;}operator int;;〃定义Date:operator int static int dys[]={31,28,31,30,31,30,31,31,30,31,30,31;二int daysyr-;days*=365;days+=yr-/4;forint i=0;i days+=dys[i];days+=da;return days;int main Date now12,24,;int since=now;cout return0;类的转换上面两个例子都是类对象和内部数据对象之间的互相转换也可以定义转换函数C++来实现两个类对象之间的互相转换#include iostream.hclass CustomDatepublic:int da,yr;CustomDateint d=0,int y=0{da=d;yr=y;}void displayO{cout};class Dateint mo,da,yr;public:Dateint m=O,int d=O,int y=O{mo=m;da=d;yr=y;}〃转换构造函数Dateconst CustomDate;〃组员转换函数;operator CustomDate;void displaycout}static int dys[]={31,28,31,30,31,30,31,31,30,31,30,31;Date::Dateconst CustomDatejdyr=jd・yr;da=jd.da;formo=0;moll;mo++ifdadys[mo]da-=dys[mo];else break;mo++;Date:operator CustomDate CustomDate cd0,yr;forint i=0;i cd.da+=da;return cd;int mainDate dt12,24,3;CustomDate cd;=出;〃调用组员转换函数cd cd.displayO;调用转换构造函数dt=cd;//dt.displayO;return0;这个例子中有两个类和型日期包括年份和天数CustomDate Date,CustomDate这个例子没有考虑闰年状况不过在实际构造一种类时,应当考虑到所有问题的也许性在里中具有两种转换函数,这样,当需要从型变为型十,可以Date Date CustomDate调用组员转换函数;反之可以调用转换构造函数不能既在类中定义组员转换函数,又在类里定义转换构造函数那Date CustomDate样编译器在进行转换时就不懂得该调用哪一种函数,从而出错.
四、转换函数的调用里调用转换函数有三种形式第一种是隐式转换,例如编译器需要一种对象,C++Date而程序提供的是对象,编译器会自动调用合适的转换函数此外两种都是需CustomDate要在程序代码中明确给出的显式转换强制类型转换是一种,尚有一种是显式调用转C++换构造函数和组员转换函数下面的程序给出了三中转换形式#include iostream.hclass CustomDatepublic:int da,yr;CustomDateint d=0,int y=0{da=d;yr=y;}void displayOcout};class Dateint mo,da,yr;public:Dateint m,int d,int ymo=m;da=d;yr=y;operator CustomDate;;Date:operator CustomDatestatic int dys[]={31,28,31,30,31,30,31,31,30,31,30,31;CustomDate cd0,yr;forint i=0;i cd.da+=da;return cd;int mainDate dt11,17,89;CustomDate cd;cd=dt;cd.displayO;cd=CustomDate dt;cd.display;cd=CustomDatedt;cd.displayO;return0;
五、转换发生的情形上面的几种例子都是通过不能类型对象之间的互相赋值来调用转换函数,尚有几种调用的也许参数传递初始化返回值体现式语句这些状况下,均有也许调用转换函数下面的程序不难理解,就不分析了#include iostream.hclass CustomDatepublic:int da,yr;CustomDate{}CustomDateint d,int y{da=d;yr=y;}void displayOcout};class Dateint mo,da,yr;public:Dateint m,int d,int y{mo=m;da=d;yr=y;}operator CustomDate;;Date:operator CustomDatestatic int dys[]={31,28,31,30,31,30,31,31,30,31,30,31;CustomDate cd0,yr;for int i=0;i cd.da+=da;return cd;class TesterCustomDate cd;public:explicit TcstcrCustomDatcc{cd=c;}void displayO{cd.display;};void dispdateCustomDate cdcd.displayO;CustomDate rtndateDate dt9,ll,l;return dt;int mainDate dt12,24,3;CustomDate cd;cd=dt;cd.displayO;dispdatedt;Tester tsdt;ts.display;cd=rtndate;cd.displayO;return0;
六、显式构造函数注意上面类的构造函数前面有一种修饰符假如不加上这个关键字,那Tester explicit么在需要把对象转换成对象时,编译器会把该函数当作转换构造函数来CustomDate Tester调用不过有时候,并不想把这种只有一种参数的构造函数用于转换目的,而仅仅但愿用它来显式地初始化对象,此时,就需要在构造函数前加假如在申明了对象explicit Tester后来使用了下面的语句将导致一种错误ts=jd;//error这个错误阐明,虽然类中有一种以型变量为参数的构造函数,编译器却Tester Date不会把它看作是从到的转换构造函数,由于它的申明中包括了修饰符Date Testerexplicit
七、体现式内部的转换在体现式内部,假如发现某个类型和需要的不一致,就会发生错误数字类型的转换是很简朴,这里就不举例了下面的程序是把对象转换成长整型值Date#include iostream.hclass Dateint mo,da,yr;public:Dateint m,int d,int ymo=m;da=d;yr=y;operator long;;Date:operator longstatic int dys[]={31,28,31,30,31,30,31,31,30,31,30,31};long days=yr;days*=365;从月日开始计算days+=yr-l900/4;//1911forint i=0;i days+=da;return days;}int mainDate today12,24,;const longott=123;long sum=ott+today;cout return0;在体现式中,当需要转换的对象可以转换成某个数字类型,或者体现式调用了作用于某个类的重载运算符时,就会发生隐式转换运算符重载后来再学习二级辅导笔记私有数据组员和友元C++
一、私有数据组员的使用取值和赋值组员函数
1.面向对象的约定就是保证所有数据组员的私有性一般我们都是通过公有组员函数来作为公共接口来读取私有数据组员的某些时候,我们称这样的函数为取值和赋值函数取值函数的返回值和传递给赋值函数的参数不必一一匹配所有数据组员的类型#include iostream.hclass Dateint mo,da,yr;public:Dateint m,int d,int y{mo=m;da=d;yr=y;}int getyearconst{return yr;}void setyearint y{yr=y;};int mainDate dt4,l,89;cout dt.setyear97;cout return0;上面的例子很简朴,不分析了要养成这样的习惯,通过组员函数来访问和变化类中的数据这样有助于软件的设计和维护例如,变化类内部数据的形式,但仍然用修Date改正的和来提供访问接口,那么使用该类就不必修改他们的代码,仅需getyear setyear要重新编译程序即可中还包括」数据类型,」也是字符类型,不过是那些宽度超过位的C++wchar wchar8数据类型许多外文字符集所含的数目超过个,字符类型无法完全囊括256char wchar_t数据类型一般为位16原则的类库中包括了可以支持宽字符的类和对象用替代即可C++iostream woutcout#include iostream.hint mainwchar_t wc;wc=,b,;wout wc=y;wout wc=e;wout return0;阐明一下某些编译器无法编译该程序不支持该数据类型
三、强制类型转换有时候,根据体现式的需要,某个数据需要被当成此外的数据类型来处理,这时,就需要强制编译器把变量或常数由申明时的类型转换成需要的类型为此,就要使用强制类型转换阐明,格式如下int*iptr=int*table;体现式的前缀就是老式风格的强制类型转换阐明又可称为强制转换int*C typecast,阐明强制转换阐明告诉编译器把体现式转换成指定的类型有些状况下强制转换是cast禁用的,例如不能把一种构造类型转换成其他任何类型数字类型和数字类型、指针和指针之间可以互相转换当然,数字类型和指针类型也可以互相转换,但一般认为这样做是不安全并且也是没必要的强制类型转换可以防止编译器的警告long int el=123;short i=int el;float m=
34.56;int i=int m;上面两个都是风格的强制类型转换,还增长了一种转换方式,比较一下上面和CC++下面这个书写方式的不一样long intel=123;short i=intel;float m=
34.56;int i=int m;使用强制类型转换的最大好处就是严禁编译器对你故意去做的事发出警告不过,运用强制类型转换阐明使得编译器的类型检查机制失效,这不是明智的选择一般,是不倡导进行强制类型转换的除非不可防止,如要调用函数时要用的型指针转换malkc void成指定类型指针
四、原则输入输出流在语言中,输入输出是使用语句和来实现的,而中是使用类来实C scanfprintf C++现的#include iostream.h中函数默认为型,而语言中默认为型main//C++main intC void.常量组员函数2注意上面的程序中被申明为常量型,这样可以保证该组员函数不会修改调用getyear他的对象通过加上修饰符,可以使访问对象数据的组员函数仅仅完毕不会引起数const据变动的那些操作假如程序申明某个对象为常量的话,那么该对象不得调用任何非常量型组员函Date数,不管这些函数与否真的试图修改对象的数据只有把那些不会引起数据变化的函数都申明为常量型,才可以让常量对象来调用.改善的组员转换函数3下面的程序改善了从对象到对象的组员转换函数,用取值和赋值函Date CustomDate数取代了使用公有数据组员的做法此前的程序代码在上一帖中#include iostream.hclass CustomDateint da,yr;public:CustomDate{}CustomDateint d,int y{da=d;yr=y;}void display const{cout intgetday const{return da;}void setdayint d{da=d;};class Date{int mo,da,yr;public:Dateint m,int d,int y{mo=m;da=d;yr=y;}operator CustomDateconst;};Date:operator CustomDateconststatic int dys[]={31,28,31,30,31,30,31,31,30,31,30,31;CustomDate cd0,yr;int day=da;forint i=0;i cd.setdayday;return cd;int mainDate dt11,17,89;CustomDatecd;cd=dt;cd.displayO;return0;注意上面的程序中申明为常量型,由于这个函数没有变化Date::operator CustomDate调用它对象的数据,尽管它修改了一种临时对象并将其作为函数返回值
二、CustomDate友元前面已经说过了,私有数据组员不能被类外的其他函数读取,不过有时候类会容许某些特殊的函数直接读写其私有数据组员关键字可以让特定的函数或者别的类的所有组员函数对私有数据组员进行读写friend这既可以维护数据的私有性,有可以保证让特定的类或函数可以直接访问私有数据友元类
1.一种类可以申明另一种类为其友元,这个友元的所有组员函数都可以读写它的私有数据#include iostream.hclass Date;class CustomDateint da,yr;public:CustomDateint d=O,int y=0{da=d;yr=y;}〃这儿void displayO const{cout friend Date;};class Dateint mo,da,yr;public:Dateint m,int d,int y{mo=m;da=d;yr=y;}operator CustomDate;;Date:operator CustomDatestatic int dys[]={31,28,31,30,31,30,31,31,30,31,30,31};CustomDatecd0,yr;for int i=0;i cd.da+=da;return cd;int mainDate dt11,17,89;CustomDate cddt;cd.displayO;return0;在上面的程序中,有这样一句该语句告诉编译器,类的所有组员函数friend Date;Date有权访问类的私有组员由于类的转换函数需要懂得类的每CustomDate Date CustomDate个数据组员,因此真个类都被申明为类的友元Date CustomDate.隐式构造函数2上面程序对的构造函数的调用私有显示该类需要如下的一种转换构造CustomDate函数CustomDateDate dt;不过唯一的一种构造函数是CustomDateint d=O;int y=0;这就出现了问题,编译器要从对象构造一种对象,不过类Date CustomDate CustomDate中并没有定义这样的转换构造函数不过类中定义了一种组员转换函数,它可以把Date对象转换成对象于是编译器开始搜索类,看其与否有一种Date CustomDate CustomDate构造函数,能从一种已存在的的对象创立新的对象这种构造函CustomDate CustomDate数叫拷贝构造函数拷贝构造函数也只有一种参数,该参数是它所属的类的一种对象,由于类中没有拷贝构造函数,于是编译器就会产生一种默认的拷贝构造函数,CustomDate该函数简朴地把已存在的对象的每个组员拷贝给新对象目前我们已经懂得,编译器可以把对象转换成对象,也可以从已存在的对象生成一种新的DateCustomDateCustomDate对象那么上面提出的问题,编译器就是这样做的它首先调用转换函数,从CustomDate对象创立一种隐藏的、临时的、匿名的对象,然后用该临时对象作为参DateCustomDate数调用默认拷贝构造函数,这就生成了一种新的对象CustomDate.预引用3上面的例子中尚有这样一句class Date;这个语句叫做预引用它告诉编译器,类将在背面定义编译器必须懂得这个Date信号,由于类中引用了类,而里也引用了类,必须首CustomDate Date DateCustomDate先申明其中之一使用了预引用后,就可以申明未定义的类的友元、指针和引用不过不可以使用那些需要懂得预引用的类的定义细节的语句,如申明该类的一种实例或者任何对该类组员的引用.显式友元预引用4也可以不使用预引用,这只要在申明友元的时候加上关键自就行了class#include iostream.hclass CustomDateint da,yr;public:CustomDateint d=0,int y=0{da=d;yr=y;}〃这儿,去掉前面的预引用void displayOconst{cout friendclass Date;;classDate・・・・••;Date:operator CustomDateint main.友元函数5一般,除非真的需要,否则并不需要把整个类都设为另一种类的友元,只需挑出需要访问目前类私有数据组员的组员函数,将它们设置为该类的友元即可这样的函数称为友元函数下面的程序限制了类数据组员的访问,类中只有需要这些数据的组CustomDate Date员函数才有权读写它们#include iostream.hclass CustomDate;class Dateint mo,da,yr;public:Dateconst CustomDate;void displayOconst{cout};class CustomDateint da,yr;public:CustomDateint d=O,int y=0{da=d;yr=y;}friendDate::Dateconst CustomDate;;Date::Dateconst CustomDatecdstatic int dys[]={31,28,31,30,31,30,31,31,30,31,30,31;yr=cd.yr;da=cd.da;formo=0;mol1;mo++ifdadys[mo]da-=dys[mo];else break;mo++;int mainDate dtCustomDate123,89;dt.displayO;return0;.匿名对象6上面函数中对象调用类的构造函数创立了一种匿名mainDateCustomDateCustomDate对象,然后用该对象创立了一种对象这种使用方法在中是常常出现的DateC++.非类组员的友元函数7有时候友元函数未必是某个类的组员这样的函数拥有类对象私有数据组员的读写权,但它并不是任何类的组员函数这个特性在重载运算符时尤其有用非类组员的友元函数一般被用来做为类之间的纽带一种函数假如被两个类同步申明为友元,它就可以访问这两个类的私有组员下面的程序阐明了一种可以访问两个类私有数据组员的友元函数是怎样将在两个类之间架起桥梁的#include iostream.hclass Time;class Dateint mo,da,yr;public:Dateint m,int d,int y{mo=m;da=d;yr=y;}friend void displayconst Date,const Time;;class Time{int hr,min,sec;public:二Timeint h,int m,int s{hr=h;min m;sec=s;}friend void displayconst Date,const Time;;void displayconst Date dt,const Time tmcout«dt.mo«7«dt.da«7,«dt.yr;cout«cout«tm.hr««tm.min««tm.sec;int mainDate dt2,16,97;Timetm10,55,0;displaydt,tm;return0;二级辅导笔记析构函数和指针C++this
一、析构函数前面的某些例子都没有阐明析构函数,这是由于所用到的类在结束时不需要做尤其的清理工作下面的程序给出了一新的类,其中包括一种字符串指针,用来表达月份Date#include iostream.h#include string.hclass Dateint mo,da,yr;char month;public:Dateint m=O,int d=O,int y=O;;〜Datevoid displayOconst;;Date::Dateint m,int d,int y口=static char*mos{January,February,March,April,May,June,July,August,September,October,November,December;mo=m;da=d;yr=y;ifm!=0month=new char[strlenmos[m-1]+1];strcpymonth,mos[m-l];else month=0;Date::〜Datedelete[]month;void Date::display constifmonth!=0cout}int mainDatebirthday8,11,1979;birthday.displayO;return0;在对象的构造函数中,首先用运算符为字符串动态分派了内存,然Date new month后从内部数组中把月份的名字拷贝给字符串指针month析构函数在删除指针时,也许会出现某些问题当然从这个程序自身来看,没month什么麻烦;不过从设计一种类的角度来看,当类用于赋值时,就会出现问题假设上Date面的修改为“mainint mainDatebirthday8,11,1979;Date today;today=birthday;birthday.displayO;return0;这会生成一种名为的空的型变量,并且把值赋给它假如不尤其today Datebirthday告知编译器,它会简朴的认为类的赋值就是组员对组员的拷贝在上面的程序中,变量有一种字符型指针并且在构造函数里用运算符初始化过了当birthday month,new birthday离开其作用域时,析构函数会调用运算符来释放内存但同步,当离开它的作delete today用域时,析构函数同样会对它进行释放操作,而里的指针是里的today monthbirthday month指针的一种拷贝析构函数对同一指针进行了两次删除操作,这会带来不可预知的后果假如假设是一种外部变量,而是一种自变量当离开其作用域today birthdaybirthday时,就已经把对象里的指针删除了显然这也是不对的的today month再假设有两个初始化的变量,把其中一种的值赋值给另一种DateDate birthday8,l1,1979;Date today12,29,;today=birthday;问题就更复杂了,当这两个变量离开作用域时,中的的值已经通过赋birthday month值传递给了而中构造函数用运算符给的值却由于赋值被覆盖了todayo todaynewmonth这样,中的被删除了两次,而中却没有被删除掉birthday monthtoday month
二、重载赋值运算符为了处理上面的问题,我们应当写一种特殊的赋值运算符函数来处理此类问题当需要为同一种类的两个对象互相赋值时,就可以重载运算符函数这个措施可以处理类的赋值和指针的释放下面的程序中,类中的赋值函数用运算符从堆中分派了一种不一样的指针,该指new针获取赋值对象中对应的值,然后拷贝给接受赋值的对象在类中重载赋值运算符的格式如下void operator=const Date背面我们回加以改善目前,重载的运算符函数的返回类型为它是类总的组员void函数,在本程序红,是类的组员函数它的函数名一直是参数也一直是同Date operator=,一种类的对象的引用参数表达的是源对象,即赋值数据的提供者重载函数的运算符作为目的对象的组员函数来使用#include iostream.h#include string.hclass Dateint mo,da,yr;char month;public:Dateint m=0,int d=0,int y=0;;〜Datevoid operator=const Date;void displayOconst;Date::Dateint m,int d,int y口=static char*mosJanuary,February,March,April,May,June,July,August,September,October,November,December;mo=m;da=d;yr=y;if m!=0month=new char[strlenmos[m-1]+1];strcpymonth,mos[m-l];else month=0;Date::〜Datedelete[]month;}void Date::displayconst{if month!=0cout char name
[25];cin»name;if strncmpname,end,3==0break;ListEntry*list=new ListEntryname;if prev!=0prev-AddEntry*list;prev=list;while prev!=0prev-display;ListEntry*hold=prev;prev=prev-PrevEntry;delete hold;return0;程序运行时,会提醒输入一串姓名,当输入完毕后,键入然后程序会逆序显示刚end,刚输入的所有姓名程序中类具有一种字符串和一种指向前一种表项的指针构造函数从对中获ListEntry取内存分派给字符串,并把字符串的内容拷贝到内存,然后置链接指针为析构函NULL数将释放字符串所占用的内存组员函数返回指向链表前一种表项的指针,另一种组员函数显示目前的表PrevEntry项内容组员函数,它把指针拷贝给参数的指针,即把目前表项的地AddEntry this preventry址赋值给下一种表项的链接指针,从而构造了一种链表它并没有变化调用它的listEntry对象的内容,只是把该对象的地址赋给函数的参数所引用的那个对象的ListEntry preventry指针,尽管该函数不会修改对象的数据,但它并不是常量型这是由于,它拷贝对象的地址指针的内容给一种非长常量对象,而编译器回认为这个非常量对象就有也许通过拷this贝得到的地址去修改目前对象的数据,因此函数在申明时不需要用AddEntry const.二级辅导笔记类对象数组和静态组员C++
一、类对象数组类的对象和其他数据类型同样,也可认为其建立数组,数组的表达措施和构造同C++样#include iostream.hclass Dateint mo,da,yr;public:Dateint m=0,int d=0,int y=0{mo=m;da=d;yr=y;}void displayconst{cout};int mainDate dates
[2];Date today12,31,;dates
[0]=today;dates[O].display;dates[l].display;return0;类对象数组和默认构造函数L在前面已经说过,不带参数或者所有参数均有默认值的构造函数叫做默认构造函数假如类中没有构造函数,编译器会自动提供一种什么都不做的公共默认构造函数假如类当中至少有一种构造函数,编译器就不会提供默认构造函数假如类当中不含默认构造函数,则无法实例化其对象数组由于实例花类对象数组的格式不容许用初始化值来匹配某个构造函数的参数表上面的程序中,函数申明了一种长度为的对象数组,尚有一种包括初始main2Date化值的单个对象接着把这个初始化的对象赋值给数组中第一种对象,然后显Date Date示两个数组元素中包括的日期从输出中可以看到,第一种日期是有效日期,而第二个显示的都是0当申明了某个类的对象数组时,编译器会为每个元素都调用默认构造函数下面的程序去掉了构造函数的默认参数值,并且增长了一种默认构造函数#includeclass Dateint mo,da,yr;public:Date;Dateint m,intd,int y{mo=m;da=d;yr=y;}void displayconst{cout};Date::Date{coutmo=0;da=0;yr=O;int mainDate dates
[2];Date today2,31,;dates
[0]=today;dates[O].display;dates[l].display;return0;运行程序,输出为Date constructorrunningDate constructorrunning12/31/0/0/0从输出中可以看出,这个默认构造函数被调用了两次Date.类对象数组和析构函数2当类对象离开作用域时,编译器会为每个对象数组元素调用析构函数#include iostream.h classDate int mo,da,yr;public:Dateintm=0,intd=0,int y=0{mo=m;da=d;yr=y;}〜Date{cout void displayOconst{cout};int mainDate dates
[2];Date today12,31,;dates
[0]=today;dates
[0].displayO;datcs[l].displayO;return0;运行程序,输出为12/31/0/0/0int a;cout1输入一种数值*/cin»a;/*cout return0;对象,他们自身并不是语言的构成部分虽然他们已经是原则cin,cout,endl C++ANSI中被定义,不过他们不是语言的内在构成部分在中不提供内在的输入输出运算C++C++符,这与其他语言是不一样的输入和输出是通过类来实现的,和是这些类的C++cin cout实例,他们是在语言的外部实现C++在语言中,有了一种新的注释措施,就是,//二在该行〃后的所有阐明都被编译器C++认为是注释,这种注释不能换行中仍然保留了老式语言的注释风格/*……*/C++C也可采用格式化输出的措施C++#include iostream.hint main{int a;coutcin»a;cout
五、函数重载在中,容许有相似的函数名,不过它们的参数类型不能完全相似,这样这些函数C++就可以互相区别开来而这在语言中是不容许的C.参数个数不一样1#include iostream.hvoid aint,int;void aint;int maina5;a6,7;return0;void aint icout}void ainti,int jcout},参数格式不一样2#include iostream.hvoid aint,int;Date destructorrunningDate destructorrunningDate destructorrunning表明析构函数被调用了三次,也就是这三个对象离开作用域时dates
[0],dates
[1],today调用的
二、静态组员可以把类的组员申明为静态的静态组员只能存在唯一的实例所有的组员函数都可以访问这个静态组员虽然没有申明类的任何实例,静态组员也已经是存在的不过类当中申明静态组员时并不能自动定义这个变量,必须在类定义之外来定义该组员静态数据组员
1.静态数据组员相称于一种全局变量,类的所有实例都可以使用它组员函数能访问并且修改这个值假如这个静态组员是公有的,那么类的作用域之内的所有代码不管是在类的内部还是外部都可以访问这个组员下面的程序通过静态数据组员来记录链表首项和末项的地址#include iostream.h#include string.hclass ListEntrypublic:static ListEntry*firstentry;private:static ListEntry*lastentry;char*listvalue;ListEntry*nextentry;public:ListEntrychar*;{〜ListEntry delete[]listvalue;}ListEntry*NextEntryO const{return nextentry;};void displayconst{cout};ListEntry*ListEntry::firstentry;ListEntry*ListEntry::lastentry;ListEntry::ListEntrychar*siffirstentry==O firstentry=this;iflastentry!=0lastentry-nextentry=this;lastentry=this;listvalue=new char[strlens+l];strcpylistvalue,s;ncxtcntry=0;int mainwhile1cout«\nEnter aname endwhen done:;char name
[25];cin»name;ifstrncmpname,end,3==0break;new ListEntryname;ListEntry*next=ListEn try::firs tentry;while next!=0next-display;ListEntry*hold=next;next=next-NextEntry;delete hold;return0;程序首先显示提醒信息,输入一串姓名,以作为结束标志然后按照输入次序来end显示姓名构造函数将表项加入链表,用运算符来申明一种表项,但并没有把运new new算符返回的地址赋值给某个指针,这是由于构造函数会把该表项的地址赋值给前一种表项的指针nextentry这个程序和前面将的逆序输出的程序都不是最佳措施,最佳的措施是使用类模板,这在背面再简介函数获得的值,开始遍历链表,因此必需把main ListEntry::firs tentry设置成公有数据组员,这不符合面向对象程序的约定,由于这里数据组ListEntry::firstentry员是公有的.静态组员函数2组员函数也可以是静态的假如一种静态组员函数不需要访问类的任何实例的组员,可以使用类名或者对象名来调用它静态组员一般用在只需要访问静态数据组员的状况下静态组员函数没有指针,由于它不能访问非静态组员,因此它们不能把指针this this指向任何东西下面的程序中,ListEntry类中加入了一种静态组员函数FirstEntryO,它从数据组员获得链表第一项的地址,在这儿,已经申明为私有数据组员了firstentry firstentry#include iostream.h#include string.hclass ListEntrystatic ListEntry*firstentry;static ListEntry*lastcntry;char*listvalue;ListEntry*nextentry;public:ListEntrychar*;〜ListEntry{delete[]listvalue;}staticListEntry*FirstEntryO{return firstentry;}ListEntry*NextEntryO const{returnnextentry;};void displayOconst{cout};ListEntry*ListEntry::firstentry;ListEntry*ListEntry::lastentry;ListEntry::ListEntrychar*siffirstentry==Ofirstentry=this;iflastentry!=0lastentry-nextentry=this;lastentry=this;listvalue=new char[strlens+l];strcpylistvalue,s;nextentry=0;int mainwhile1cout«\nEnter aname endwhen done:;char name
[25];cin»name;ifstrncmpname,end,3--0break;new ListEntryname;ListEntry*next=ListEntry::FirstEntry;while next!=0next-display;ListEntry*hold=next;next=next-NextEntry;delete hold;return0;函数是静态的,返回静态数据组员的值ListEntry::FirstEntry firstentry.公有静态组员3假如一种静态组员象上面程序同样是公有的,那么在整个程序中都可以访问它可以在任何地方调用公有景泰组员函数,并且不需要有类的实例存在但公有静态组员函数不完全是全局的,它不仅仅存在于定义类的作用域内在这个作用域里面,只要在函数名前加上类名和域解析运算符::就可以调用该函数二级辅导笔记类和堆C++
一、构造函数和析构函数前面的例子已经运用了和来为类对象分派和释放内存new delete当使用为类对象分派内存时,编译器首先用运算符分派内存,然后调用类的new new构造函数;类似的,当使用来释放内存时,编译器会首先调用泪的析构函数,然delete后再调用运算符delete#include iostream.hclass Date{intmo,da,yr;public:Date{cout〜Date{cout}int main{Date*dt=new Date;cout deletedt;return0;程序定义了一种有构造函数和析构函数的类,这两个函数在执行时会显示一条Date信息当运算符初始化指针出时,执行了构造函数,当运算符释放内存时,又new delete执行了析构函数程序输出如下Date constructorProcessthe dateDatedestructor
二、堆和类数组前面提到,类对象数组的每个元素都要调用构造函数和析构函数下面的例子给出了一种错误的释放类数组所占用的内存的例子#include iostream.hclass Dateintmo,da,yr;public:{Date{cout〜Date cout}int mainDate*dt=new Date[5|;〃这儿cout deletedt;return0;指针指向一种有五个元素的数组按照数组的定义,编译器会让运算符调用dt new类的构造函数五次不过被调用时一,并没有明确告诉编译器指针指向的Date deleteDate对象有几种,因此编译时,只会调用析构函数一次下面是程序输出;Date constructorDate constructorDate constructorDate constructorDate constructorProcessthe dateDatedestructor为了处理这个问题,容许告诉运算符,正在删除的那个指针时指向数组的,C++delete程序修改如下#include iostream.hclass Dateintmo,da,yr;public:Date{cout〜Date{cout}int mainDate*dt=new Date
[5];〃这cout delete[]dt;JLreturn0;最终输出为DateconstructorDateconstructorDateconstructorDateconstructorDate constructorProcessthe dateDatedestructorDate destructorDate destructorDatedestructorDatedestructor
三、重载和运算符new delete前面已经简介了怎样用和运算符函数来动态第管理内存,在那些例子中使new delete用的都是全局的和运算符我们可以重载全局的和运算符,但这不new deletenew delete是好的想法,除非在进行低级的系统上或者嵌入式的编程不过,在某个类的内部重载和运算符时可以的这容许一种类有它自己的new delete和运算符当一种类需要和内存打交道时,采用这种措施来处理其中的细节,new delete可以获得很搞的效率,同步防止了使用全局和运算符带来的额外开销由于全new delete局堆操作时调用操作系统函数来分派和释放内存,这样效率很低假如确定某个类在任何时候,其实例都不会超过一种确定的值,那么就可以一次性为类的所有实例分派足够的内存,然后用该类的和运算符来管理这些内存下面new delete的程序阐明了怎样对和进行重载new delete#include iostream.h#include string.h#include stddef.h#include new.hconst intmaxnames=5;class Namescharname
[25];static char Names::pool[];static bool Names::inuse[maxnames];public:Nameschar*s{strncpyname,s,sizeofname;}void*operator newsize_tthrowbad_alloc;void operator deletevoid*throw;void displayOconst{cout;char Names::pool[maxnames*sizeofNames];bool Names::inuse[maxnames];void*Names:operator newsize_t throwbad_alloc forint p=0;p{if!inuse[p]inuse|p]=true;return pool+p*sizeofNames;throw bad_alloc;}void Names::operator deletevoid*p throwifp!=Oinuse[char*p-pool/sizeofNames]=false;int mainNames*nm[maxnames];inti;fori=0;i{cout charname
[25];cin»name;nm[i]=new Namesname;fori=0;i{nm[i]-display;delete nm[i];return0;上面的程序提醒输入个姓名,然后显示它们程序中定义了名为的类,它的5Names构造函数初始化对象的值这个类定义了自己的和运算符这是由于程name new delete序能保证不会一次使用超过个姓名,因此可以通过重载默认的和运maxnames new delete算符来提高运行速度类中的内存池是一种字符数组,可以同步容纳程序需要的所有姓名与之有关Names的布尔型数组为每个姓名记录了一种和值,指出内存中的对应的项与否正inuse truefalse在使用重载的运算符在内存池中寻找一种没有被使用的项,然后返回它的地址重载的new运算符则标识那些没有被使用的项delete在类定义中重载的和运算符函数一直是静态的,并且没有和对象有关的new deletethis指针这是由于编译器会在调用构造函数之前调用函数,在调用析构函数后调用new delete函数函数是在类的构造函数之前被调用的由于这时内存中还不存在类的对象并且构new造函数也没有提供任何初始化值,因此它不可以访问类的任何组员同理,运算符delete是在析构函数之后被调用的,因此它也不可以访问类的组员
四、异常监测和异常处理.检测异常1上面的例子还缺乏必要的保护机制例如,重载的运算符函数并没有检查它的delete参数,确认其与否落在内存池内部假如你绝对相信自己编的程序中不会传递错误的指针值给运算符,那么可以省掉合法性检查以提高效率,尤其是在优先考虑效率的程序delete中否则应当使用预编译的条件语句在软件的测试版本中加入这些检测,在正式的发行版本中去掉这些检查.重载和中的异常处理2new delete上面的两个重载运算符函数都是用了异常处理异常处理是的新内容之一,目前C++还没有讲到在这里不必关怀它是怎样工作的上面程序中,当试图分派超过内存池容量的缓冲区,重载的运算符函数就会抛出异常,终止程序Names new
五、重载□和new delete[]对于上面的程序,假如有下面的语句二Names*nms new Names
[10]•••delete[]nms;那么,这些语句会调用全局和运算符,而不是重载过的和为new deletenew delete了重载能为对象数组分派内存的和运算符,必须像下面的程序同样,对口new deletenew和[也进行重载delete#include iostream.h#include string.h#include stddef.h#include new.hconst intmaxnames=5;class Names{charname
[25];static charNames::pool[];static boolNames::inuse[maxnames];public:Nameschar*s{strncpyname,s,sizeofname;}void*operator newsize_t throwbad_alloc;void operatordeletevoid*throw;void displayconst{cout};charNames::pool[maxnames*sizeofNames];boolNames::inuse[maxnames];void*Names:operator new[]size_t sizethrowbad_allocint elements=size/sizeofNames;intp-1;inti=0;whilei{if!inuse|i|p=i;++i;//Not enoughroom.if p==-l||maxnames-p forintx=0;x returnpool+p*sizeofNames;口void Names::operatordeletevoid*b throwifb!=Oint p=char*b-pool/sizeofNames;int elements=inuse[p];for inti=0;i}int mainNames*np=newNames[maxnames];inti;fori=0;i{cout charname
[25];cin»name;*np+i=name;fori=0;idisplayO;delete[]np;return0;重载口和□要比重载和考虑更多的问题这是由于口运算符new deletenew deletenew时为数组分派内存,因此它必须记住数组的大小,重载的口运算符才能对的地把缓delete冲区释放回内存池上面的程序采用的措施比较简朴,吧本来寄存缓冲区使用标志的布尔型数组换成一种整型数组,该数组的每个元素记录□运算符分派的缓冲区个数,而不new再是一种简朴的当口运算符函数需要把缓冲区释放回内存池时,它就会用该true delete数组来确认释放的缓冲区个数二级辅导笔记类的其他几点问题C++
一、拷贝构造函数拷贝构造函数在下列状况下被调用用已经存在的对象去初始化同一种类的另一种对象;在函数的参数中,以传值方式传递类对象的拷贝;类对象的值被用做函数的返回值拷贝构造函数和前面说到的转换构造函数有些相似转换构造函数是把一种类的对象转化为另一种类的对象;拷贝构造函数是用一种已经存在的对象的值实例化该类的一种新对象不一样对象间的初始化和赋值的区别赋值操作是在两个已经存在的对象间进行的;而初始化是要创立一种新的对象,并且其初值来源于另一种已存在的对象编译器会区别这两种状况,赋值的时候调用重载的赋值运算符,初始化的时候调用拷贝构造函数假如类中没有拷贝构造函数,则编译器会提供一种默认的这个默认的拷贝构造函数只是简朴地复制类中的每个组员#include iostream.h#include string.hclass Dateintmo,da,yr;char*month;public:Dateintm=0,intd=0,int y=0;Dateconst Date;;〜Datevoid displayOconst;;Date::Dateintm,intd,int ystaticchar*mos[]=January,February,March,April,May,June,July,August,September,October,November,December;mo=m;da=d;yr=y;if m!=0month=new char[strlcnmos[m-1]+1];strcpymonth,mos[m-l];elsemonth=0;Date::Dateconst Date dtmo=dt.mo;da=dt.da;yr=dt.yr;if dt.month!=0{month=new char[strlendt.month+1];strcpymonth,dt.month;}elsemonth=0;Date::〜Datedelete[]month;void Date::display constifmonth!=0cout«month«*«da«,«yr«std::endl;int mainDatebirthday6,24,1940;birthday.displayO;Date newday=birthday;newday.displayO;Date lastdaybirthday;lastday.display;return0;本例中,用到了两次拷贝构造函数一种是使用一般的初始化变量的语句C++Date newday=birthday;另一种是使用构造函数的调用约定,即把初始化值作为函数的参数Date lastdaybirthday;
二、类的引用在函数参数和返回值中,假如一定要使用传值方式,那么使用类对象的引用,是一种提高效率的措施类的数据组员也可以是一种引用,但必须注意第一,一种引用必须初始化一般一种类对象并不会像构造那样用大括号来初始化,而是调用构造函数因此在构造函数里必须初始化类当中的引用组员第二,引用是一种别名尽管类里面的引用在使用方式上看起来和类的一般数据组员没有什么区别,不过作用在其上的操作,实际上是对用来初始化它的那么对象进行的void aint,float;int maina5,6;a6,
7.0;return0;void ainti,int jcout}void ainti,float j{cout}
六、变量作用域语言中,容许变量定义语句在程序中的任何地方,只要在是使用它之前就可以;而C++语言中,必须要在函数开头部分并且容许反复定义变量,语言也是做不到这一CC++C点的看下面的程序#include iostream.hint a;int maincin»a;语言中,不容许在这里定义变量forint i=l;i=10;i++//C语言中,同一函数块,不容许有同名变量staticint a=0;//Ca+=i;cout«::a«}return0;
七、和运算符newdelete在语言中,仍然支持和来分派和释放内存,同步增长了和C++mallocfreenewdelete来管理内存为固定大小的数组分派内存
1.#include iostream.hint main二int birthdaynew int
[3];birthday
[0]=6;birthday[l]=24;birthday⑵=1940;〃注意这儿coutdelete[]birthday;return0;在删除数组时,运算符后要有一对方括号delete#include iostream.h classDate intda,mo,yr;public:Dateint d,intm,int y{da=d;mo=m;yr=y;}void DisplayOconst{cout«da«71«mo«7«yr;};class Time{int hr,min,sec;public:Timeint h,intm,ints{hr=h;min=m;sec=s;}void DisplayOconst{cout«hr««min««sec;}};class DateTimeconst Date dt;const Timetm;public:DateTimeconst Dated,const Timet:dtd,tmt//emptyvoid DisplayOconst dt.DisplayO;cout«1tm.DisplayO;;int mainDatetoday7,4,;Time now15,20,0;DateTime dtmtoday,now;dtm.DisplayO;return0;我们来看看这个程序中的构造函数的格式冒号操作符引出了一种参数初DateTime始化表必须使用这种格式来初始化引用数据组员,而不可以在函数体内来进行初始化工作假如构造函数像上例同样不是内联的,那么最佳不要在类中明中构造函数的原型上使用冒号和初始化值表,而是像下面这样,把参数初始化表放在定义构造函数的地方Class DateTimeconst Date dt;const Timetm;public:DateTimeconst Dated,const Timet;DateTime::DateTimeconst Dated,const Timet:dtd,tmt//empty可以使用构造函数的参数初始化表来初始化任何数据组员尤其是常量数据组员,和引用同样,只能在参数初始化表里进行初始化,这是由于不可以在构造函数内部为常量数据组员赋值当一种类具有引用数据组员时,一旦引用被实例化和初始化后来,就无法修改它的值,因此该类不也许彻底地重载赋值运算符函数
三、构造函数的参数初始化表假如类对象的某些数据组员没有载构造函数内部被初始化,那么必须使用构造函数的参数初始化表对他们进行初始化否则,编译器不止到该怎样初始化这些还等着在构造函数内部赋值的组员我们习常用参数初始化表来初始化所有数据组员class Dateintmo,da,yr;public:Dateintm=0,intd=0,int y=0;;class Employee{int empno;Date datehired;public:Employeeint en,Date dh;;可以用下面两种措施编写类的构造函数EmployeeEmployee::Employccint cn,Datc dtempno=en;datehired=dh;或者;Employee::Employeeint en,Date dt:empnoen,datehireddh//empty虽然这两种措施效果是同样的,不过根据对象默认构造函数的复杂性的不一样,Date这两种形式的效率差异是很大的
四、对修饰符的简朴阐明const假如一种对象被申明为常量,那么该对象就不可以调用类当中任何非常量型的组员函数除了被编译器隐式调用的构造函数和析构函数看下面的代码;#include iostream.hclass Date{int month,day,year;public:Dateintm,d,y monthm,dayd,yeary{}void display{cout}int mainconstDate dt4,7J;dt.displayO;//errorreturn0;这个程序尽管编译时没有问题,但运行时却出错了这是由于常量对象不能调用非常量函数编译器只看函数的申明,而不在意函数的详细实现实际上函数的实现可以在程序中的任何地方,也可以是在另一种源代码文献中,这就超过了编译器的目前可见范围//date.hclass Date{int month,day,year;public:Dateintm,d,y;void displayQ;;//date.cpp#includc iostream.h#include date.hDate::Dateintm,d,y:monthm,dayd,yeary{}void Date::displaycout}//program,cpp#include iostream.h#include date.cppint mainconstDate dt4,7J;dt.displayO;return0;}处理出错的问题有两个措施第一是申明函数为常量型的display//in date.hvoid displayOconst//int date.cppvoid Date::display constcout}另一种处理方式就是省略掉对象申明里的修饰符Date constDate dt4,7,;尚有另一种轻易出错的地方void abcconstDatedt提醒没有修饰符dt.displayO;//error displayconst函数申明了一种对象的常量引用,这阐明该函数不会修改传递进来的参数abc Date的值假如函数不是常量型的,那么在函数里就不能调用它,由于编Date::display abc译器会认为函数有也许会修改常量的值Date::display不管类对象与否是常量型的,它必须修改某个数据组员的值时,委员会设置了ANSI关键字mutable
五、可变的数据组员假设需要记录某个对象出现的次数,不管它与否是常量那么类当中就应当有一种用来计数的整型数据组员只要用修饰符来申明该数据组员,一种常量型的组员函mutable数就可以修改它的值#include iostream.hclass AValueintval;mutable intrptct;public:AValucint v:valv,rptctO{}〜AValuecout}void reportconst;void AValue::report constrptct++;cout«val«endl;}int main{const AValueavall23;avaLreport;aval.report;aval.report;return0;二级辅导笔记重载运算符C++重载是由发现的一重载运算符的时机需要在定义的对象间互相赋值时,重载赋值运算符lo需要在数字类型增长算术属性时,重载算术运算符2需要为定义的对象进行逻辑比较时,重载关系运算符3o对于重载下标运算符口4o container,需要从流中读写对象时,重载<<和>>运算符5o I/O重载组员指针运算符->以实现指针6o smart在少数状况下重载运算符7new,deleteO不重载其他运算符8o实际上任何用重载运算符完毕的工作都可以使用组员函数来实现重载的运算符可以和本来的运算符不一定有必然联络,例如我重载中运算马夫,可以不做加法运算,而是把字符串连接起来当然你要是用中运算符来做减法运算,也是可以的,不过这不是明智之举二重载运算符的规则重载的运算符不能违反语言的语法规则lo假如一种运算符可以放在两个操作数之间,就可以重载它来满足类操作的需要,哪2o怕这种使用方法原本为编译器不能接受不能发明语言中没有的运算符3o C++下列运算符不能重载4o・类组员运算符.*组员指针运算符::域解析运算符:条件体现式运算符重载时不能变化运算符的优先级5o三运算符重载运算符重载是通过对运算符函数的重载来实现的对于每一种运算符@,在C++中都对应一种运算符函数其中@为多种运算符operator©,C++运算符函数的一般原型为type operator@arglist—、级辅导笔记重:载双目运算符C++其中为运算成果的类型,为操作数列表type arglist在五我们已经简介了重载赋值运算符,这里就不重新阐明了一作为类组员函数的重载为了能进行类对象和一种整型值的加法运算,需要写一种类的组员函数来重载双目加法+运算符该函数在类中的申明如下Date operator+int const;函数的申明指出,返回值是一种类对象,函数名是运算符+,只有一种整型参数,Date并且函数是常量型的当编译器发现某个函数以加上前缀的真实运算符作为函数operator名,就会把该函数当作重载运算符函数来处理假如在体现式中,该运算符的左边是一种类对象,右边是一种参数类型的一种对象,那么重载运算符函数就会被调用调用形式如下Datedt6,9,;dt=dt+100;也可以显式的调用重载运算符函数dt.operator+100;下面代码重载了双目加法运算符来计算一种整数和一种类对象之和,并且返回Date类对象Date#include iostream.h classDateintmo,da,yr;staticintdys[];public:Dateintm=0,intd=0,int y=0{mo=m;da=d;yr=y;}void displayconst{cout Date operator+int const;;int Date::dys[]={31,28,31,30,31,30,31,31,30,31,30,31;Date Date::operator+int constDatedt=*this;n+=dt.da;whilen=dys[dt.mo-1]n-=dys[dt.mo-l];if++dt.da==13dt.mo=l;dt,yr++;dt.da=n;return dt;int mainDate olddatel,l,;Date newdate;newdate=olddate+100;newdate.display;return0;二非类组员的运算符重载在重载运算符的原则中说到,要保持运算符的可互换性而上面的程序只容许类Date对象在运算符的左边而整型值在右边,不支持下面的语句Date newdate=1OO+olddate;因此,仅仅靠一种类的组员重载运算符是无法实现上面功能的对重载双目运算符的类组员函数来说,总是认定调用函数的对象位于运算符左边不过,我们可以再写一种非类组员的重载运算符函数,可以规定类的对象在运算符右边,而别的类型在运算符左Date边例如,我们可以这样在类的外部定义一种函数Date operator+int n,Datedt下面代码在原先的基础上增长了一种非类组员函数来实现双目加法运算符的重载#include iostream.hclass Dateintmo,da,yr;staticintdys[];public:Dateintm=0,intd=O,int y=0{mo=m;da=d;yr=y;}voiddisplayconst{cout Date operator+int const;;int Date::dys[]={31,28,31,30,31,30,31,31,30,31,30,31;Date Date::operator+int constDatedt=*this;n+=dt.da;whilcn=dys[dt.mo-1]n-=dys|dt.mo-l];if++dt.da==13dt.mo=l;什+;dt,ydt.da=n;return dt;Date operator+int n,Datedt{return dt+n;}int main{Date olddatel,l,;Date newdate;newdate=olddate+100;newdate.displayO;return0;上面的例子中非类组员重载运算符函数调用了类中的重载+运算符来实现加法运算假如类当中没有提供这样的函数,那么非类组员的重载运算符函数将被迫访问类的私有数据来实现加法运算这样的话,需要把这个函数申明为类的友元,如下class DatefriendDateoperator+int n,Date;;上例中重载运算符函数申明了所有两个参数,这是由于它不是类的组员,因此它不能作为类的组员函数被调用,就缺乏了一种隐含的参数第一种重载加法运算符函数也可以用类的友元函数来实现作为一种约定,这一般把所有为类重载的运算符都设定为该类的友元例子中只给出了重载加法的代码,我们同样可以来重载减法,乘除法等等三重载关系运算符假如想要对两个日期进行比较,例如出现下面这样的代码可以向上面用类ifolddate似的措施重载关系运算符#include iostream.h classDateintmo,da,yr;public:Datcint m=0,intd=0,int y=0{mo=m;da=d;yr=y;}voiddisplayconst{cout int operator==Datedtconst;intoperatorDatedtconst;int Date::operator==Datedtconst return this-mo==dt.mothis-da==dt.dathis-yr=dt.yr;int Date:operatorDatedtconstifthis-yr==dt.yr{ifthis-mo==dt.mo return this-dadt.da;returnthis-modt.mo;returnthis-yrdt.yr;int mainDate date12,14,;Datedate26,9,;Datedate32,14,;ifdatel{date
1.display;cout date
2.display;cout ifdatel==date3date
1.display;cout date
3.display;return0;可以类似的重载其他关系运算符,如!=四其他赋值运算符intoperator!=Datedt{return!*this==dt;}#include iostream.hclass Dateintmo,da,yr;staticintdys[];public:Datcint m=0,intd=0,inty=0{mo=m;da=d;yr=y;}voiddisplayconst{cout Dateoperator+int const;Dateoperator+=int{*this=*this+n;return*this;}int Date::dys[]={31,28,31,30,31,30,31,31,30,31,30,31;DateDate::operator+int constDatedt=*this;n+=dt.da;whilen=dys[dt.mo-1]n-=dys[dt.mo-l];if++dt.da==13dt.mo=l;dt,yr++;dt.da=n;return dt;int mainDateolddatel,l,;olddate+=100;olddate.displayO;return0;.为动态数组分派内存2#include iostream.h#include stdlib.hint mainintsize;cin»size;int*array=new int[size];forint i=0;i arrayi]=rand;fori=0;i cout«\n delete[]array;return0;
八、引用型变量在中,引用是一种常常使用的概念引用型变量是其他变量的一种别名,我们可C++以认为他们只是名字不相似,其他都是相似的.引用是一种别名3中的引用是其他变量的别名申明一种引用型变量,需要给他一种初始化值,在C++变量的生存周期内,该值不会变化运算符定义了一种引用型变量inta;int b=a;先申明一种名为的变量,它尚有一种别名我们可以认为是一种人,有一种真名,a b一种外号,后来不管是喊他还是都是叫他这个人同样,作为变量,后来对这两个标a b,识符操作都会产生相似的效果#include iostream.hint maininta=123;int b=a;cout a++;cout b++;cout return0;,引用的初始化4和指针不一样,引用变量的值不可变化引用作为真实对象的别名,必须进行初始化,除非满足下列条件之一引用变量被申明为外部的,它可以在任何地方初始化1引用变量作为类的组员,在构造函数里对它进行初始化2引用变量作为函数申明的形参,在函数调用时,用调用者的实参来进行初始化
3.作为函数形参的引用5引用常常被用作函数的形参以引用替代拷贝作为形参的长处引用防止了传递大型数据构造带来的额外开销引用不必象指针那样需要使用*和-等运算符#include iostream.hvoid funclsp;void func2sp;struct sintn;char text
[10];;int mainstatics str={123,China};fund str;func2str;return0;void funcls pcout cout}void func2spcoutcout}从表面上看,这两个函数没有明显区别,不过他们所花的时间却有很大差异,函func2数所用的时间开销会比函数少诸多它们尚有一种差异,假如程序递归伴随func2funcl,递归的深入,会由于栈的耗尽而瓦解,但没有这样的担忧func
2.以引用方式调用6当函数把引用作为参数传递给另一种函数时,被调用函数将直接对参数在调用者中的拷贝进行操作,而不是产生一种局部的拷贝传递变量自身是这样的这就称为以引用方式调用把参数的值传递到被调用函数内部的拷贝中则称为以传值方式调用#include iostream.hvoid displayconstDate,const char*;void sDate,Date;struct Dateintmonth,day,year;;int mainstatic Date now={2,23,90};staticDatethen={9,10,60;displaynow,Now:;displaythcn,Thcn:;snow,then;displaynow,Now:;displaythen,Then:;return0;void sDatedtl,Datedt2Date save;save=dtl;dtl=dt2;dt2=save;void displayconstDatedt,const char*scoutcout}.以引用作为返回值7#include iostream.h structDateintmonth,day,year;};Date birthdays[]={12,12,60;{10,25,85;{5,20,73};;constDategetdateint nreturn birthdays[n-l];int mainint dt=l;whiledt!=0cout cin»dt;ifdt0dt4|constDatebd=getdatedt;cout}return0;程序都很简朴,就不讲解了辅导笔记类的设计、构造函数和析构函数C++
一、类的设计.类的申明1类名class〃私有private:•••公有public://♦・♦;.类的组员2一般在类中,所有定义的变量和函数都是类的组员假如是变量,我们就叫它数C++据组员假如是函数,我们就叫它组员函数.类组员的可见性3和访问控制符决定了组员的可见性由一种访问控制符设定的可访问状private public态将一直持续到下一种访问控制符出现,或者类申明的结束私有组员仅能被同一种类中的组员函数访问,公有组员既可以被同一类中的组员函数访问,也可以被其他已经实例化的类中函数访问当然,这也有例外的状况,这是后来要讨论的友元函数类中默认的数据类型是构造中的默认类型是一般状况下,变量都作为private,public私有组员出现,函数都作为公有组员出现类中尚有一种访问控制符叫保护组员,后来再阐明protected,.初始化4在申明一种类的对象时,可以用圆括号包括一种初始化表看下面一种例子#include iostream.hclass Boxprivate:个私有数据组员int height,width,depth;//3public:Boxint,int,int;〜Box;;〃组员函数int volume;Box::Boxint ht,int wd,int dp{height=ht;width=wd;depth=dp;Box::〜Box//nothingint Box::volumereturnheight*width*depth;int main〃申明一种类对象并初始化Box thisbox3,4,5;cout return0;当一种类中没有组员和组员时,也没有虚函数,并且不是从其他类private protected中派生出来的,可以用{}来初始化后来再讲解.内联函数5内联函数和一般函数的区别是内联函数是在编译过程中展开的一般内联函数必须简短定义类的内联函数有两种措施一种和语言同样,在定义函数时使用关键字C inline如oinline intBox::volume returnheight*width*depth;尚有一种措施就是直接在类申明的内部定义函数体,而不是仅仅给出一种函数原型我们把上面的函数简化一下{#include iostream.h classBox private:intheight,width,depth;public:Boxint ht,int wd,int dpheight=ht;二width=wd;depth dp;〜Box;int volumereturnheight*width*depth;;int main〃申明一种类对象并初始化Box thisbox3,4,5;coutreturn0;这样,两个函数都默认为内联函数了
二、构造函数什么是构造函数?通俗的讲,在类中,函数名和类名相似的函数称为构造函数上。
个人认证
优秀文档
获得点赞 0