面向对想程序设计5

上传人:lx****y 文档编号:243386537 上传时间:2024-09-22 格式:PPT 页数:160 大小:1.06MB
返回 下载 相关 举报
面向对想程序设计5_第1页
第1页 / 共160页
面向对想程序设计5_第2页
第2页 / 共160页
面向对想程序设计5_第3页
第3页 / 共160页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第四章类和对象,1,第四章 类与对象,类,对象,构造函数和析构函数,const成员函数,成员对象,静态成员,友元,小结,2,第四章 类与对象,类,对象,构造函数和析构函数,const,成员函数,成员对象,静态成员,友元,小结,3,4.1,类,类的定义,class,类名,;,说明:,1,、类名代表所定义的类的名字,用标识符表示。,2,、成员描述给出该类的对象所有的成员的说明,它包,括成员函数和数据成员。,3,、在类定义的成员描述中还包含对成员的访问控制,。,4,一个类中的方法可以直接访问同类中的任何成员。,5,在,C+,定义中,可以用访问控制修饰符,public,、,private,或,protected,来描述对类成员的访问限制。,public:public,成员的访问不受限制,在程序中的任何地方都可以访问一个类的,public,成员。,private:private,成员只能在本类(本类的成员函数)和,友元,中访问。,protected:protected,成员只能在本类、,派生类和友元,中访问。,成员的访问控制:信息隐藏,6,在类定义中可以有多个public、private和protected访问控制说明,它们出现的先后顺序无关。C+的默认访问控制是private。,成员的访问控制,良好编程习惯:,为了保证程序的清晰性和可读性,每个成员访问说明符在类定义中只能使用一次。请将,public,成员放在最前面,这样更便于查找。,7,一般情况下,类的数据成员和在类内部使用的成员函数应该指定为private,只有提供给外界使用的成员函数才指定为public。指定为public的成员构成了类与外界的一种接口。操作一个对象时,只能通过访问对象类中的public成员实现。,成员的访问控制,软件工程知识:,根据经验,数据成员应该声明为,private,,成员函数应该声明为,public,,如果某些成员函数只是被该类的其他成员函数访问,那么它们更适合声明为,private,。,8,类的定义示例,定义一个Student类,class,Student,private:,/,访问控制说明,int number , score;,public:,/,访问控制说明,void init(), number = 1001;,score = 100; ,void show(),coutnumberendlscore=,0,& hh ,数据成员名,对象指针,-,成员函数名,(,实参列表,),对象指针,-,成员名,等价:,(*,对象指针,).,成员名,29,间接方式,间接创建和标识对象是指在程序运行时刻,通过,new,操作来创建对象。所创建的对象称为动态对象,其内存空间在程序的堆区中。动态对象用,delete,操作撤消(即使之消亡)。动态对象需要通过指针变量来标识。,对象的创建和标识,30,对象的创建和标识,单个动态对象的创建与撤消。,A *p;,p=new A;,delete p;,A *p;,p=(A *)malloc(sizeof(A);,free (p);,31,对象的创建和标识,动态对象数组的创建与撤消,A *p;,p=new A100;,delete p;,A *p;,p=(A *)malloc(sizeof(A)*100);,free(p);,32,类作用域,类定义构成一个作用域:类作用域,其中的标识符局部于类定义,它们可以与类定义外的全局标识符或其他类定义中的标识符相同。他们包括:,数据成员,成员函数,在类定义外使用类定义中的,标识符,时,需通过对象名受限或类名受限。,在类定义中使用与局部标识符同名的全局标识符时,需要在全局标识符前面加上全局域分辨符(,:,)来实现。,33,class,Student,private:,int number,score;,public:,void init();,;,void,Student:,init(),number = 1001;,score = 100;,类作用域,34,类作用域,void init();,class Student,private:,int number;,public:,void init(int number);,void f();,;,void,Student:f(),:init(),;/,调用全局函数,init ,35,class,Student,private:,int number;,int score;,public:,void init(int number,int score),Student:,number = number;,Student:,score = score;,;,void,main(),Student s1,;,s1.init();,36,class A,public:,void f();,void g(int i),x=i;,f();,private:,int x,y,z;,;,a,b,a.x,a.y,a.z,b.x,b.y,b.z,A a,b;,g(int i),37,this,指针,每个成员函数都有一个隐藏的指针类型的形参,this,,其类型为:, *const this;,成员函数中对类成员的访问都是通过,this,指针进行的。,void g(A *const this,int i),this-x=i;,this-f();,void g(int i),x=i;,f();,a.g(3);,A:g(,38,class,Student,private:,int number;,int score;,public:,void init(int number,int score),this-,number = number;,this-,score = score;,;,void,main(),Student s1,;,s1.init();,39,void func(A * p),class A, int x;,public:,void f(),func(?),;,void g(int i)x=i;f();,;,A a,b;,a.f();,b.f();,要求:调用,a.f(),时,在,A:f,中调用,func(,调用,b.f(),时,在,A:f,中调用,func(,40,练习:应在下列程序划线处填入的正确语句是( )。,void init();,class Student,private:,int number;,public:,void init(int number);,void f();,;,void Student:init(int number), _= number;,void Student:f(),_ /,调用全局函数,init,41,练习,A. this-number; ,:init();,B. this:number; ,:init();,C. Student:number; ,init();,D. student-number; ,init();,42,小技巧:在以后的,MFC,编程中,如果在成员函数中想调用同类中的某个成员,可以使用,VC+,提供的自动列出成员函数功能,使用,this-,,,VC+,将列出该类中的所有成员,我们可以从列表中选择我们想调用的成员。,自动列出成员函数功能,可以提高编写速度,减少拼写错误。我们经常不能完全记住某个函数的完整拼写,但却能够从列表中辨别出该函数,自动列出成员函数的功能在这时就显得更加有用了。,43,事实上,在各种,IDE,编程环境中,我们通常都不可能记住也没有必要记住所有的函数,只要将常用的函数记住,其他不常用的函数只要记住其大概的写法和功能,在调用该函数时可以从自动列出成员函数中选取,这样可以大大节省我们的学习时间。我们不用花费大量的时间去死记硬背许多函数,利用自动列出成员函数功能和帮助系统,就能够在编程时顺利地使用这些函数,等用的次数多了,也就在不知不觉中完全掌握了这些函数。,44,第四章 类与对象,类,对象,构造函数和析构函数,const,成员函数,成员对象,静态成员,友元,小结,45,构造函数,什么是构造函数,构造函数是一种特殊的,成员函数,,它是在对象诞生后第一个执行,(,并且是自动执行,),的函数,.,46,构造函数的特点,构造函数的名称必须与类名相同,构造函数,没有返回值,,,可以有参数,,,可以重载,构造函数一般是,public,的,但有时也把构造函数声明为私有的(,private,),其作用是限制创建该类对象的范围,这时只能在本类和友元类中创建该对象。,程序中不能直接调用构造函数,在创建对象时系统自动调用构造函数。,47,在创建一个对象时,对象类的构造函数会被自动调用来对该对象进行初始化。至于调用对象类的哪个构造函数,这可以在创建对象的时候指定。,构造函数,48,class A, ,public:,A();,A(int i);,A(char *p);,A a1;,或,A a1=A();,A a2(1);,或,A a2=A(1);,或,A a2=1;,A a3(“abcd”);,或,A a3=A(“abcd”);,或,A a3=“abcd”;,A a1();,49,class A, ,public:,A();,A(int i);,A(char *p);,A a4;,A b5=A(),A(1),A(“abcd”),2,”xyz”;,A *p1=new A;,A *p2=new A(2);,A *p3=new A(“xyz”);,A *p4=new A20;,50,不带参数的(或所有参数都有默认值的)构造函数,即构造对象时不提供参数的构造函数称为,默认构造函数,。,程序中不能同时出现无参数的构造函数和带有全部默认形参值的构造函数。,构造函数,51,class A, ,public:,A();,A(int i=0);,;,A a;,构造函数,(ERROR),52,C+,规定,每个类必须有一个构造函数,没有构造函数,就不能创建任何对象。,构造函数,53,构造函数,C+,又规定,如果一个类没有提供任何的构造函数,则,C+,提供一个默认的构造函数(由,C+,编译器提供),这个默认的构造函数是一个不带参数的构造函数,该构造函数的函数体为空,不做任何的初始化工作。,54,只要一个类定义了一个构造函数,不管这个构造函数是否是带参数的构造函数,,C+,就不再提供默认的构造函数。因此,如果为一个类定义了一个带参数(且不是所有参数都有默认值)的构造函数,还想要创建一个对象而不提供参数,就需要自己定义一个默认构造函数。,构造函数,55,class A, ,public:,A(int i);,;,A a;,构造函数,(ERROR),56,构造函数示例,把,Student,类中的函数,init,改成构造函数,class,Student,private:,int number;,int score;,public:,Student(int number,int score),Student:,number = number;,Student:,score = score;,;,void,main(),Student s1(1002,90);,Student s2;,构造函数也可以“,类内声,明,类外定义,”,/,错误,类中没有默认构造函数,57,构造函数,错误预防技巧:,除非没有必要初始化类的数据成员,否则请提供构造函数,这样可以保证当类的每个新对象被创建时,类的数据成员都用有意义的值进行了初始化。,58,析构函数,什么是析构函数,在对象行将毁灭但未毁灭之前一刻,最后执行,(,并且是自动执行,),的函数。,析构函数是“反向”的构造函数,析构函数不允许有返回值,更重要的是析构函数不允许带参数,并且一个类中只能有一个析构函数,.,析构函数的作用正好与构造函数相反,对象超出其作用范围,对应的内存空间被系统收回或被程序用,delete,删除时,析构函数被调用,.,59,注意:,new,和,delete,会调用构造函数和析构函数,malloc,和,free,不会调用构造函数和析构函数,对于动态分配的数组对象,必须用,delete ,,而不能用,delete,代替,delete ,。,delete gradesArray;,首先调用每个对象的析构函数,然后释放内存,如果语句中没有包括,(),并且,gradesArray,指向一个对象数组,只有第一个对象的析构函数被调用,60,注意:,常见编程错误:,删除数组时,用,delete,代替,delete ,将导致运行时的逻辑错误。为保证数组中的每个对象都接受一个析构函数调用,数组生成的内存空间要用,delete ,运算符删除。类似地,总是使用,delete,运算符将分配给单个元素的内存空间删除。,61,析构函数的特点,析构函数的名称与类名相同,前面加上“,”,析构函数,没有返回值,,,没有参数,,,不能重载,当对象被撤销时,系统自动调用析构函数,类中未定义析构函数,系统会自动生成默认的函数体为空的析构函数,析构函数,62,根据析构函数的特点,我们可以在构造函数中初始化对象的某些成员变量,给其分配内存空间(堆内存),在析构函数中释放对象运行期间所申请的资源,.,析构函数,63,析构函数示例,在构造函数申请空间,析构函数释放空间,class,Student,private:,char,*name,;int number;int score;,public:,Student(char *name,int number,int score),this-name =,new,charstrlen(name) + 1;,strcpy(this-name,name);,this-number = number;,this-score = score;,Student(),delete,name;,;,析构函数同样可以“,类内,声明,类外定义,”,64,析构函数示例,name,number,score,栈内存,堆内存,zhangsan,Stu1,对象,Student stu1(“zhangsan”,101,90);,101,90,65,注意,无论构造函数被调用还是析构函数被调用,对象都是存在的。,66,class A, int x;,char *p;,public:,A(char *p,int x), this-p =,new,charstrlen(p) + 1;,strcpy(this-p,p);,this-x = x;,A(),delete,p;,;,void main(),A a(“lisi”,23);,a,a.x,a.p,对象产生,系统在堆栈中分配内存空间,栈内存,67,class A, int x;,char *p;,public:,A(char *p,int x), this-p =,new,charstrlen(p) + 1;,strcpy(this-p,p);,this-x = x;,A(),delete,p;,;,void main(),A a(“lisi”,23);,a,a.x,a.p,栈内存,调用构造函数,完成初始化,堆内存,lisi,23,对象产生,系统在堆栈中分配内存空间,68,class A, int x;,char *p;,public:,A(char *p,int x), this-p =,new,charstrlen(p) + 1;,strcpy(this-p,p);,this-x = x;,A(),delete,p;,;,void main(),A a(“lisi”,23);,a,a.x,a.p,栈内存,调用构造函数,完成初始化,堆内存,lisi,23,对象产生,系统在堆栈中分配内存空间,对象生命周期结束,在,结束前,先调用析构函数,69,class A, int x;,char *p;,public:,A(char *p,int x), this-p =,new,charstrlen(p) + 1;,strcpy(this-p,p);,this-x = x;,A(),delete,p;,;,void main(),A a(“lisi”,23);,a,a.x,a.p,栈内存,调用构造函数,完成初始化,23,对象产生,系统在堆栈中分配内存空间,对象生命周期结束,在,结束前,先调用析构函数,对象生命周期结束,释放内存,70,析构函数,在某些情况下,我们并不撤消对象,而只是归还对象所申请的资源,这时我们可以通过显示地调用析构函数来实现。,71,小结对象的创建,在,c+,中,有四种方法可以产生一个对象,在栈中产生,在堆中产生,产生一个全局对象,产生一个局部静态对象,72,小结对象的创建,对于全局对象,程序一开始,其构造函数就先被执行。程序即将结束前其析构函数执行。(MFC application object),对于局部对象,当对象诞生时,其构造函数被函数执行。程序流程将离开该对象的存活范围(以致对象将毁灭)时,其析构函数执行。,73,小结对象的创建,对于静态对象,当对象第一次被定义时其构造函数被执行。当程序将结束时(此对象因而遭致毁灭)其析构函数被执行,但比全局对象的析构函数早一步执行。,对于以new方式产生出来的局部对象,当对象诞生时其构造函数被执行。析构函数则在对象被delete时执行。,74,思考,class Person,;,Person,per1(30,“zhangsan”, 170);,Person per2(per1);,75,拷贝构造函数,什么是拷贝构造函数,拷贝构造函数是一种特殊的,构造函数,,它的功能是用一个已知的对象来初始化一个被创建的同类对象。,拷贝构造函数实际上也是构造函数,,具有一般构造函数的所有特性,它是在初始化时被调用来将一个已知对象的数据成员的值逐值拷贝给正在创建的一个同类的对象。,默认情况下系统自动创建拷贝构造函数,76,如果在类定义中没有给出拷贝构造函数,则编译系统将会隐式地为其提供一个拷贝构造函数,该拷贝构造函数的行为是:逐个成员拷贝初始化。对于普通成员,它采用通常的初始化操作;对于成员对象,则调用成员对象类的拷贝构造函数来实现成员对象的初始化。,拷贝构造函数,77,拷贝构造函数的定义,类名,(const,类名,&,object),拷贝构造函数,78,在,Person,类中添加拷贝构造函数,拷贝构造函数,class,Person,private:,int height;,int age;,char name10;,public:,Person,(const,Person,&,person),height =,person,.height;,age =,person,.age;,strcpy(name,person.name);,;,79,class,Person,private:,char,*name,;int age;int height;,public:,Person(int age,char *name,int height),this-name =,new,charstrlen(name) + 1;,strcpy(this-name,name);,this-age = age;,this-height = height;,Student(),delete,name;,;,80,思考,Person p1(11,“zhangsan”, 150);,Person p2(p1);,81,Person,(const,Person,&a),age=a.age;,height=a.height;,name=a.name;,系统提供的默认拷贝构造函数的行为,82,深拷贝和潜拷贝问题,p1,p2,张三,p2 = p1,*,name,height,age,*,name,height,age,栈空间,堆空间,83,深拷贝和潜拷贝问题,类体内的成员需要动态开辟内存的时我们应自定义拷贝构造函进行深拷贝,以防止潜拷贝带来的堆内存的所属权产生混乱,从而造成析构错误,84,Person,(const,Person,&a),age=a.age;,height=a.height;,name=,new charstrlen(a.name)+1;,strcpy(name,a.name);,深拷贝和潜拷贝问题,85,拷贝构造函数,void f(Person s),Person a;,f(a);,86,以下三种情况将调用拷贝构造函数,定义对象时,A a1;,A a2(a1);A a2=a1;A a2=A(a1);,把对象作为值参数传给函数,void f(A x);,A a;,f(a);,/,调用时将创建形参对象,x,,并调用拷贝构造函数(用对象,a,)对其初始化。,把对象作为返回值,87,A f(),A a;,return a;/,创建一个,A,类临时对象,并调用拷贝构造函数(用对象,a,)对其初始化。,void main(),A b;,b=f();,88,const,常量、引用的初始化问题?,思考,89,class A, int x;,const int y=1;,int ,public:,A(),x=0;,y=1;,;,/error,/error,/ error,,,y,是常量成员,其值不能改变,90,成员初始化表,(在定义构造函数时),class A, int x;,const int y;,int ,public:,A(),:z(x),y(1),x=0;,;,91,class A, int x;,const int y;,int ,public:,A(),:z(x),y(1),x(0),;,92,成员初始化表中成员初始化的书写次序并不决定它们的初始化次序,数据成员的初始化次序由它们在类定义中的说明次序来决定。,当类中有常量数据成员或引用数据成员时,如果类中定义了构造函数,则一定要在定义的所有构造函数的成员初始化表中对它们进行初始化,,如果类中没有定义构造函数,则编译程序不会给该类生成一个默认构造函数,。因此,这样的类程序是不能用于创建对象的。,成员初始化表,(在定义构造函数时),93,程序运行的某个时刻,一个对象的所有数据成员的值反映了这个对象在该时刻的状态。在不同时刻,对象的状态可能是不一样的,对象状态的改变往往是由于对象处理了一条消息(某个成员函数被调用)。但是并不是每条消息都会导致对象状态的变化。有些消息只是获取对象在某时刻的状态。,思考,94,第四章 类与对象,类,对象,构造函数和析构函数,const,成员函数,成员对象,静态成员,友元,小结,95,在定义一个成员函数时,可以给它加上一个,const,说明,表示它是一个获取对象状态的成员函数。例如:,class A,void f() const,;,const,成员函数,96,const,成员函数,函数声明和定义处都要加const,class A, int x,y;,public:,void f() const,;,;,void A:f() const,97,const,成员函数,class A, int x;,public:,int f() const,;,class A, int x;,public:,const,int f(),;,98,在,const,成员函数体中不能修改数据成员的值,也不能调用该类中的非常成员函数。,const,成员函数,软件工程知识:,如果成员函数不修改对象,最好将所有类成员函数声明为,const,。,99,class A, int x;,char *p;,public:,void f() const,x=10;/error,p=new char20;/error,;,const,成员函数,100,class A, int x;,char *p;,public:,void f() const,strcpy(p,”abcd”);,*p=A;,;,const,成员函数,101,const,成员函数,const对象,软件工程知识:,将对象声明为,const,有利于实现最低权限原则,这样试图修改对象就会产生编译时错误而非执行时错误。,性能提示:,把变量和对象声明为,const,,这不仅是一种有效的软件工程原则,而且还能提高性能,因为如今复杂的优化编译器能对常量进行某些优化,但无法对变量进行优化。,102,const,成员函数,只有常成员函数才有资格操作常对象。,class A, int x,y;,public:,void f() const ,void g() ;,const A a;,a.f(); /OK,a.g(); /error,103,const,成员函数,软件工程知识:,可以对,const,成员函数进行非,const,版本的重载。编译器将根据调用函数的对象性质选择相应的重载函数来使用。如果对象是,const,的,则编译器使用,const,版本的重载函数;如果对象是非,const,的,则编译器使用非,const,版本的重载函数。,104,const,关键字可以被用于参与对重载函数的区分。如:,void print();,void print() const;,const,成员函数,105,在函数f中不能调用对象*pa或a的非const成员函数。,void f(A *pa) ;,void f(A ,const,成员函数,void f(const A *pa) ;,void f(const A ,106,思考,107,组合(,Composition,),是一种 has-a 关系,一个类可以将其他类的对象作为成员,一种强的“拥有”关系,体现了严格的整体和部分的关系,部分和整体生命周期一样。,108,第四章 类与对象,类,对象,构造函数和析构函数,const,成员函数,成员对象,类的组合,静态成员,友元,小结,109,4.5,类成员是其它类的对象,成员对象,一个类的成员可以是另外一个类的对象。也就是说一个对象可以包含另一个对象(称为成员对象)。,class,Computer,private:,CPU c1,c2;,;,class,CPU,private:,double frequency;,;,110,成员对象,class A, int m;,public:,A() m=0;,A(int m1) m=m1;,;,class B, int n;,A a;,public:,B() n=0;,B(int n1) n=n1;,;,B b1,b2(1);,111,在创建包含成员对象的对象时,对成员对象的初始化是由成员对象类的构造函数来实现的。默认情况下,成员对象由成员对象类的,默认构造函数,进行初始化。,成员对象的初始化,112,成员对象的初始化,class A, int m;,public:,A() m=0;,A(int m1) m=m1;,;,class B, int n;,A a;,public:,B() n=0;,B(int n1) n=n1;,;,B b1,b2(1);,113,如需要调用成员对象的非默认构造函数对成员对象进行初始化,则要在包含成员对象的类的构造函数成员初始化表指出。,成员对象的初始化,114,class A, int m;,public:,A() m=0;,A(int m1),m=m1;,;,class B, int n;,A a;,public:,B() n=0;,B(int n1):a(n1),n=n1;,;,B b1,b2(1);,115,116,117,118,119,判断:是否正确?,class A, int m;,public:,A(int m1) m=m1;,;,class B, int n;,A a;,public:,B() n=0;,B(int n1) n=n1;,;,B b1,b2(1);,120,构造函数的执行顺序是,(如果有多个成员对象)按照成员对象在类的声明中出现的次序,依次调用其成员对象的构造函数。(注意:并不是按照初始化列表中给出的顺序)。,再执行本类的构造函数的函数体。,析构函数的调用执行顺序与构造函数相反。,成员对象的初始化,121,成员对象的初始化,系统提供的隐式拷贝构造函数会去调用成员对象的拷贝构造函数。自定义的拷贝构造函数不会去调用成员对象的拷贝构造函数,必须要在成员初始化列表中显示地指出。若没有指出,则表示调用成员对象的默认构造函数。,122,class A,;,class B, int z;,A a;,public:,B();,B(const B& b):a(b.a),z=b.z,;,123,成员初始化列表,成员初始化列表,一般成员,常量成员,引用成员,自定义的拷贝构造函数调用成员对象的拷贝构造函数,显示调用成员对象的构造函数,124,第四章 类与对象,类,对象,构造函数和析构函数,const,成员函数,成员对象,静态成员,友元,小结,125,同一个类的不同对象需要共享数据,怎么办?,全局变量?,4.6 静态成员,class SavingAccount,private:,char m_name40;/,存户姓名,char m_addr60;/,存户地址,double m_total;/,存款额,double m_rate;/,利率,;,126,静态数据成员,必须在类外定义,定义时可以进行初始化,数据类型 类名,:,静态数据成员名,=,值,;,class A,static,int shared;,int x,y;,public:,A()x=y=0;,void increase_all(),;,int A:shared=0;,A a1,a2;,0,shared,0,0,0,0,a1,a2,a1.x,a1.y,a2.x,a2.y,127,静态数据成员,C+,国际标准:,const static int,或,enum,类型的数据成员,可以在类定义中声明时初始化,class A,static,const,int shared=0;,int x,y;,public:,A()x=y=0;,void increase_all(),;,A a1,a2;,128,静态数据成员,具有默认构造函数的,static,成员对象,因为它们的默认构造函数会被调用,所以不必初始化,129,静态数据成员具有静态生存期,不属于任何一个对象。,类的静态成员与该类的对象存在与否没有关系,.,静态数据成员,130,静态数据成员,class A, int x,y;,public:,A()x=y=0;,void increase_all(),static,int shared;,;,int A:shared=0;,int main(), A a;,a. shared=4;,A: shared=4;,131,思考,private的静态成员变量,不能在外部被访问.只能通过公有的成员函数访问.,如果希望在产生任何对象之前就存取其class的private static成员变量.怎么办?,132,思考,class,A,public:,void getX();,private:,static int x;, ;,int A:x=0;,void A:getX(),coutx;,coutx;,int main(), A a;,a.getX();,133,静态成员函数,class,A,public:,static void getX();,private:,static int x;, ;,int A:x=0;,void A:getX(),coutx;,int main(),A:getX();,134,静态成员函数,静态成员函数没有隐藏的形式参数this.,135,静态成员函数,静态成员函数只能访问静态成员。,静态成员函数,136,class,A,public:,static void f();,private:,int x;, ;,void A:f(),coutx;/error,137,class,A,public:,static void f(A a);,private:,int x;, ;,void A:f(A a),coutx;/error,couta.x;,138,静态成员的使用,除了在类中访问静态成员外,还可以在类的外部访问,public,静态成员,这时有两种访问方式:,通过对象访问。,通过类名访问。,类的静态成员与该类的对象存在与否没有关系。,139,设计模式,设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。设计模式就象经典的棋谱,不同的棋局,我们用不同的棋谱,免得自己再去思考和摸索。,自从对象产生以来,在程序设计领域最具革命性的飞跃是设计模式的引进。设计模式是对应于公认的编程问题的经典解决方案,它独立于语言之外,其表述方法的特殊性使他能应用于许多情况之下,.,小知识,140,底层思维,抽象思维,向下,如何深入把握机器底层,从微观理解对象构造,底层思维,语言构造,编译转换,对象内存模型,运行时机制,向上,如何将我们周围的世界抽象为程序代码,抽象思维,面向对象,组件封装,设计模式,架构模式,141,设计模式,Singleton,模式是做为,全局变量,的替代品出现的。所以它具有全局变量的特点:全局可见、贯穿应用程序的整个生命期,它也具有全局变量不具备的性质:,同类型的对象实例只可能有一个,。,小知识,142,第四章 类与对象,类,对象,构造函数和析构函数,const,成员函数,成员对象,静态成员,友元,小结,143,#include ,#include ,class Point,public:/,外部接口,Point(int xx=0, int yy=0) X=xx;Y=yy;,int GetX() return X;,int GetY() return Y;,private:/,私有数据成员,int X,Y;,;,144,double Distance( Point& a, Point& b),double dx=,a,.,GetX(),-,b,.,GetX(),;,double dy=,a,.,GetY(),-,b,.,GetY(),;,return sqrt(dx*dx+dy*dy);,int main(), Point p1(3.0, 5.0), p2(4.0, 6.0);,double d=Distance(p1, p2);,coutThe distance is dendl;,return 0;,145,4.7 友元(friend),为什么需要友元,为了让类外的普通函数和其它类的成员函数能够对类中的,保护和私有数据,进行操作,,C+,提供了一种称为,友元,的信任机制,友元的分类,友元函数(普通函数),友元成员(类的成员函数),友元类,声明友元的关键字,friend,146,class A,friend,void func();/,友元函数,friend,class B;/,友元类,friend,void C:f();/,友元类成员函数,;,友元(friend),147,友元(,friend,),软件工程知识:,private,、,protected,和,public,的成员访问符号与友元关系的声明无关,因此友元关系声明可以放在类定义中的任何位置。,软件工程知识:,尽管类定义中有友元函数的原型,但友元函数仍然不是成员函数。,148,友元(,friend,),良好编程习惯:,在类定义体之内把所有的友元关系声明放在最前面的位置,并且不要在其前面添加任何成员访问说明符。,149,150,友元函数,在类里,声明,一个普通函数,在前面加上,friend,修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员,一个普通函数可以是多个类的友元函数,151,使用友元函数计算两点距离,#include ,#include ,class Point,public:/,外部接口,Point(int xx=0, int yy=0) X=xx;Y=yy;,int GetX() return X;,int GetY() return Y;,friend double Distance(Point ,private:/,私有数据成员,int X,Y;,;,152,double Distance( Point& a, Point& b),double dx=,a.X-b.X,;,double dy=,a.Y-b.Y,;,return sqrt(dx*dx+dy*dy);,int main(), Point p1(3.0, 5.0), p2(4.0, 6.0);,double d=Distance(p1, p2);,coutThe distance is dendl;,return 0;,153,友元成员,一个类的成员函数也可以是另一个类的友元,从而可以使得一个类的成员函数可以操作另一个类的数据成员,参见工程,0109c,154,友元类,整个类也可以是另一个类的友元,该友元称为友元类,友元类的每个成员函数都可以访问另一个类的所有成员,参见工程,0109d,155,友元类举例,class A,friend class B;,public:,void Display(),coutx
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 大学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!