面向对象技术基础1.构造函数和析构函数和特殊成员构造函数的作用:PS:构造函数可以在类外定义1.给对象一个标识符2.为对象数据成员开辟内存空间3.完成对象数据成员的初始化4.如果没有显示定义构造函数,则默认构造函数只完成1、2两步5.初始化表达式:1.可用于初始化类的任意数据成员,static数据成员除外(在类外初始化)2.只能用初始化表初始化基类,const数据成员,引用成员,类对象成员3.Const数据成员,只能在初始化表中初始化,必须显示的定义构造函数,而且要注意类中const整型数据成员不能作为常量指明一个数组的大小(运行才确定)构造函数允许按参数默认方式调用(带有多个默认值得构造函数)classA{private:intx;inty;public:A(intxyp=0){x=xyp;y=xyp;cout一个默认值的构造函数被执行endl;}A(intxp=0,intyp=0){x=xp;y=yp;cout两个默认值的构造函数被执行endl;}};intmain(){Aa1(1);Aa2(1,2);return0;}复制构造函数:1.原型:Point::Point(constPoint&pt);2.调用:Pointpt2=pt1;或者Pointpt2(pt1);3.默认复制构造函数:将源对象中的成员按“内存单元复制”的方式复制到目的对象中,复制后,源对象和目的对象除了地址不同外,各个成员的取值都是相同的,特别是对于含有指针类型的数据成员,指向的内存单元相同4.显示定义复制构造函数:1.类中含有指针型的数据成员,需要使用动态内存的,需要显示定义2.自定义复制构造函数,也可以使用初始化表来给目的对象赋值构造函数注意点:1.如果类中有类对象成员,那么该对象所在的类中必须定义了无参构造函数或所有参数都有默认值的构造函数,或默认构造函数,否则不合法(对象成员所占内存空间无法开辟,编译器报错)2.只要自定义了构造函数(包括复制构造函数),则编译器不会提供默认构造函数Static数据成员和static成员函数1.static数据成员在编译的时候就被创建,此时仅知道如何分配内存,但是必须在类外(cpp文件中)进行初始化2.类定义:Classcomputer{private:staticfloattotal_price;}3.在cpp文件中初始化(不能再使用static关键字):floatcomputer::total_price=0;4.静态成员函数只能调用静态成员变量,但是可以在函数中创建一个本类对象(当构造函数定义为private类型后),也可以delete一个本类对象(析构为private型)5.如果静态数据成员使用const修饰,而且是整型,浮点类型、布尔类型或枚举型,但不能是类对象,数组、引用和指针,C++允许该成员在类定义中初始化,此时不能再外部再次对该静态成员进行定义性声明,但可以对该成员进行引用性声明6.定义性声明:指在一个文件中定义一个全局变量,如inta;7.引用性声明:指当该文件需要使用另一个文件的某个变量时,则需要使用引用性声明这个是另一个文件中的全局变量:externalinta;使用new和delete为对象数组分配释放动态空间:1.Point*p=newpoint[2];申请了一块内存,连续存放连个point对象,此时不能显示调用对象的构造函数,因此,对象要么没有定义任何形式的构造函数(编译器提供),要么显示定义了一个(有且只能有一个:否则无法判断调用哪个构造函数)所有参数都有默认值的构造函数(包括无参构造函数)。PS:只能使用p[0]来访问对象,如果使用p-print();p++;来访问则delete[]p;p=NULL;操作会出错2.delete[]p;释放了数组所占的内存空间,new和delete激活了数组中每个对象的构造函数和析构函数3.malloc和free不能为对象动态的申请内存,因为无法像new/delete或new/deltete[]那样自动调用对象的构造函数和析构函数4.deletep;操作后p指针不会被销毁,而且指向原来的地方,应及时的置NULLConst对象和Const成员函数1.const成员函数无法修改数据成员,否则编译器报错2.定义:voidprint()const{函数体内不能修改数据成员}3.能作用于const对象的成员函数除了构造函数和析构函数外,就只有const成员函数了,因为const对象只能被创建,撤销以及只读访问。即:const对象只能调用const成员函数(对应只读访问)内存空间结构对象的大小:1.对象在内存中以结构的形式(只包括非static数据成员),存放在数据段中或堆中2.Sizeof(),计算的是所有非static成员的大小,注意还要保证数据对齐(填充),引用成员当指针来维护,类中有虚函数还需要额外分配一个指针指向虚函数表(+4)3.Static成员变量在编译期就已经在静态存储区分配了内存,在程序整个运行期间4.类中的成员函数存在于代码段中,一个类只有一个副本this指针:1.this指针隐含在成员函数内的一种指针,指向本对象的指针2.this指针和对象同生共死,具有类作用域3.主要作用:a.显示指明类中数据成员;b.返回本对象的指针或引用(return*this)4.Const类名*constthis:表示在程序中即无法修改this指针(constthis),也无法通过指针this指针修改该对象(Const类名)友元和重载2.类作用域和可见域(类没有生存期)类的作用域(可见域包含在作用域中)1.作用域分类:类作用域、类名作用域、对象的作用域2.类作用域:类中(包含类的定义和类外的实现部分)定义的数据成员和函数成员的作用域是整个类,在类中是可见的,在类外是不可见的3.类作用域意味着不能从外部直接访问类的任何成员,即使该成员的访问权是public,也要通过对象名来调用,对于static成员,要指定类名来调用4.发生屏蔽现象(可见域小于作用域),此时借助this指针或类名::形式指明访问的类成员5.使用::x,可以访问全局变量,可以在程序的任何地方访问全局变量6.全局作用域:在函数和其他类定义的外部所定义的类为全局类,绝大多数C++类是定义在该作用域中,这些类具有全局作用域7.类作用域:嵌套类且是定义的访问权限为public,则该嵌套类和外类作用域相同,只是必须使用外类::内类的形式来访问内类的成员或创建对象;如果定义的权限是private时,则只能在外部类定义中使用类名来创建该嵌套类的对象8.块作用域:类的定义在代码块(包括函数)中,则该类为局部类,具有块作用域。局部类必须完全定义在局部作用域内,所以它的所有成员函数必须是内联的,因为函数内不能再定义函数(在类外定义函数)对象的生存期、作用域和可见域1.对象的生存期也是对象中所有非静态成员的生存期,对象的所有非静态数据成员(包括const数据成员)都随着对象的创建而创建和初始化,随着对象的撤销而撤销2.对象的生存期、作用域和可见域取决于对象的创建位置,同样有全局、局部和类内之分,同普通变量并无区别先定义,后实例化(定义在类对象声明之前)对象内存的释放或堆内存1.通过B*pB=newB;一个对象来创建一个对象的,在使用完对象后需deletepB;2.通过B*pB=newB[2];创建了一个对象数组,在使用完后需delete[]pB;3.在对象创建时和函数执行中通过new和malloc申请的动态内存只能通过显示的用delete或free释放,申请的动态内存不会随着对象的撤销而撤销,在程序结束时,操作系统会回收程序所开辟的所有内存,但要养成及时释放内存的习惯3.友元非成员形式的友元函数1.定义:如果在某个类的定义中用friend声明了一个外部函数(或者是其他类的函数成员,既可以是public型也可以是private型,于声明位置没有关系)后,则这个外部函数即为该类的友元函数2.非成员的友元函数是为了让外部函数也能访问类的私有成员classpoint{private:intx,y;friendfloatdis(point&p1,point&p2);public:point(inti=0,intj=0){x=i;y=j;}};intmain(){pointp1(1,2),p2(4,5);coutdis(p1,p2)endl;return0;}floatdis(point&p1,point&p2){floatd;d=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));returnd;友元的成员函数classpoint;classline{public:floatdis(point&p1,point&p2);//类成员函数原型};classpoint{private:intx,y;friendfloatline::dis(point&p1,point&p2);//友元的声明public:point(inti=0,intj=0){x=i;y=j;}};intmain(){lineline1;pointp1(1,2),p2(4,5);coutline1.dis(p1,p2)endl;return0;}floatline::dis(point&p1,point&p2){floatd;d=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));returnd;}友元函数的重载要想使得一组重载函数全部成为类的友元,必须一一声明,否则只有匹配的那个函数会成为类的友元,编译器会将其他的当成普通函数来处理备注:上面的代码中只有test(int)才是Exp的友元函数,只能这个函数才能在函数中利用类对象来直接访问该类的私有成员,其他重载函数不能通过对象来直接访问类Exp的私有数据友元类类A作为类B的友元时,A中的所有成员函数都是B的友元函数,都可以通过对象访问B的私有成员。PS:friendcz;的友元类声明位置没有要求关于友元类的注意点:1.友元关系是单向的,不具有交换性:类A是类B的友元,类B不一定是类A的友元2.友元关系不具有传递性:类A是类B友元,类B是类C友元,类A不一定是类C友元3.友元关系不能被继承:友元在一定程度上破坏了信息隐藏机制,应合理使用友元4.重载运算符重载1.可以重载的特殊运算符:[],(),逗号运算符,new,delete,new[],delete[],-,*2.不能重载的运算符:.(成员运算符),.*(指向成员的指针),::,?:,sizeof3.只能以成员函数形式重载的运算符:[],=,函数调用运算符:(),-4.重载原则:不改变优先级和结合性,不改变语法结构,一般不改变语义5.用户自定义的重载运算符,要能访问对象的private成员的,因此运算符重载有成员函数和友元函数两种形式6.重载运算符时要注意各运算符之间的关联(等价):[],*,&,-要同时被重载友元函数形式和成员函数形式的比较(以+为例)成员函数形式:complexoperator+(constcomplex&);友元函数形式:friendcomplexoperator+(constcomplex&,constcomplex&);构造函数:complex(doubler=0.0,doublei=0.0){real=r;imag=i;}总结:1.友元函数更容易实现类型装换,使两个操作符都被当成函数的参数2.如果程序中有大量用到complex类对象和内置类型(int,double)相加操作,最好的方式重载几个complex类和内置数据类型相加的版本(不需编译器去转换)以成员函数形式重载(前置++,后置++)1.先在类定义中声明(或者定义为inline):返回类型operator运算符(参数列表)2.在类外定义:返回类型类名::operator运算符(参数列表)以友元函数形式重载(前置++,