《C++程序设计》课件-第3章_第1页
《C++程序设计》课件-第3章_第2页
《C++程序设计》课件-第3章_第3页
《C++程序设计》课件-第3章_第4页
《C++程序设计》课件-第3章_第5页
已阅读5页,还剩56页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C++程序设计第3章类和对象第3章类和对象本章学习要点类和对象的概念及其关系类和对象的定义及其使用构造函数与析构函数的作用及使用对象与指针对象与const对象的赋值和复制对象作为函数的参数学生信息管理系统中类和对象的实例第3章类和对象本章学习目标正确理解类和对象以及封装的概念熟练掌握类和对象的定义及其使用理解构造函数与析构函数的作用及使用掌握对象与指针及const的特点及使用理解并掌握对象的赋值和复制理解对象作为函数的参数传递的实质掌握基本的面向对象的设计与实现§3.1类的声明和对象的定义面向对象的核心是对象系统是由一个一个对象构成的对象是由类实例化得到的程序员在程序设计时是针对类进行的本节主要是关于类和对象的概念以及类的声明和对象的定义

3.1.1类和对象的概念及关系对象封装了数据及在这些数据之上的操作的封装体类对具有相同属性和操作的一组对象的抽象描述类和对象的关系类是对象的抽象;对象是对类的实例化类和对象的关系3.1.2类的声明class类名{public:

公用成员…protected:

受保护成员…private:

私有成员…};声明类的一般形式:声明类的关键字合法标识符公用成员限定符受保护成员限定符私有成员限定符类结束要加分号3.1.2类的声明【例3-1】声明一个学生类,要求包括学生的学号、姓名、性别等信息,并且能够显示学生的信息。//========================================================classStudent//声明Student类{public: //以下部分为公用成员函数

voidShow() { cout<<"No.:"<<stuNo<<endl; cout<<"Name:"<<stuName<<endl; cout<<"Sex:"<<stuSex<<endl; }private: //以下部分是私有数据成员

intstuNo; charstuName[20]; charstuSex;}; //类声明结束,此处必须有分号//========================================================3.1.2类的声明1.类的成员分为数据成员和成员函数2.成员的可访问性可分为三类:私有的(private)、受保护的(protected)、公用的(public)3.由访问限定符限定它后面的成员的访问属性,直到出现下一个访问限定符或者类的结束为止4.在声明类时,这三种访问属性的成员的声明次序是任意的,并且在一个类的声明中不一定这三种访问属性全部都出现,可能只出现两种或一种。5.某个成员访问限定符在一个类的声明中也可以出现多次。注意3.1.3

对象的定义声明类之后,再定义对象如:Studentzhang,wang;或:classStudentzhang,wang;在声明类的同时定义对象如:classStudent{…}zhang,wang;不出现类名,直接定义对象如:class{…}zhang,wang;声明类时系统并不分配内存单元,而定义对象时系统会给每个对象分配内存单元3.2.1成员函数的性质不属于任何类的函数称为普通函数成员函数隶属于某个类成员函数与普通函数的区别成员函数是属于某个类,定义在类的内部成员函数可以指定为访问属性成员函数可以访问本类的任何成员普通函数只能访问对象的公用成员对于成员函数,一般是将需要被类外调用的声明为公用的,不需要被类外调用的声明为私有的3.2.1成员函数的性质不属于任何类的函数称为普通函数成员函数隶属于某个类成员函数与普通函数的区别成员函数是属于某个类,定义在类的内部成员函数可以指定为访问属性成员函数可以访问本类的任何成员普通函数只能访问对象的公用成员对于成员函数,一般是将需要被类外调用的声明为公用的,不需要被类外调用的声明为私有的3.2.2在类外定义成员函数【例3-4】将Student类的成员函数改为在类外定义的形式。//===========================================================classStudent //声明Student类类型{public: //以下部分为公用成员函数

voidShow();private: //以下部分是私有数据成员

intstuNo; charstuName[20]; charstuSex;}; //类声明结束voidStudent::Show();//在类的声明之外定义成员函数{ cout<<"No.:"<<stuNo<<endl; cout<<"Name:"<<stuName<<endl; cout<<"Sex:"<<stuSex<<endl;}//===========================================================3.2.2在类外定义成员函数(1)成员函数在类内定义或是在类外定义,对程序执行的效果基本一样。(2)在类外定义成员函数时,必须首先在类内写出成员函数的原型,然后再在类外定义。(3)如果在类外有函数定义,但是在函数名前没有类名和作用域运算符进行限定,则该函数被认为是普通函数。(4)如成员函数的函数体很短,也可以将其定义在类内。(5)在类内声明成员函数,在类外定义成员函数,是软件工程中要求的良好的编程风格。注意3.2.3inline成员函数inline函数在编译时将被调用函数的代码直接嵌入到调用函数处inline成员函数就是将类中的成员函数声明为内置的当类中的成员函数是在类内定义时,默认该成员函数是inline成员函数如果成员函数定义在类的外部,则在成员函数声明或定义前必须要有inline关键字3.2.4成员函数的存储方式实例化对象时需要分配内存空间,数据和函数都需要存储空间同一个类的不同对象的数据是不一样的,因此要为每个对象的数据成员分配内存单元同一个类的不同对象的函数是一样的,因此将同类的所有对象的函数放在一个公共的区域。3.2.4成员函数的存储方式【例3-5】类的对象占用内存空间实验。//===========================================================#include<iostream>usingnamespacestd;classTest{public: voidShow() {cout<<"charinTestis:"<<c<<endl;}private: charc;};intmain(){Testtest;cout<<"SizeofTestis"<<sizeof(test)<<endl;return0;}//===========================================================3.2.4成员函数的存储方式【例3-6】相同类的不同对象执行相同成员函数输出不同结果。//===========================================================#include<iostream>usingnamespacestd;classTest{public: voidSet(charch){c=ch;} voidShow() {cout<<"charinTestis:"<<c<<endl;}private: charc;};intmain(){Testtest1,test2;test1.Set('a');test2.Set('b');test1.Show();test2.Show();return0;}//===========================================================3.3对象成员的访问使用对象时经常需要使用对象中的公用成员,即对象成员的访问访问对象的成员主要有3种方法通过对象名和成员运算符访问对象中的成员通过指向对象的指针访问对象中的成员通过对象的引用访问对象中的成员3.3.1成员运算符访问成员通过对象名和成员运算符访问对象中的成员的一般形式对象名.成员名在使用对象的成员时一定要写清楚成员所属的对象,如果只写成员名则系统会误认为是一个普通的变量或函数如:在【例3-6】中main函数里的“test1.Show();”语句3.3.2通过指针访问成员通过指向对象的指针访问对象中的成员可以通过C++的“->”运算符方便直观的进行,“->”称为指向运算符。例如:

Testtest1;test1.Set('a');Test*pTest=&test1;test1.Show();pTest->Show();此处两个语句的执行结果完全相同,只是采用了不同的访问对象成员的形式而已。3.3.3通过引用访问成员对象的引用和普通变量的引用在本质上是一样的通过对象的引用访问对象成员和通过对象访问成员形式上是一样的例如:

Testtest1;test1.Set('a');Test&refTest=test1;test1.Show();refTest.Show();此处两个语句的执行结果完全相同,只是采用了不同的访问对象成员的形式而已。3.4.1构造函数构造函数的作用创建对象时对对象的数据成员初始化构造函数的特点构造函数与类名相同,且没有返回值构造函数不需要用户调用,由系统在创建对象时自动调用的构造函数内容一般是初始化数据语句,但也可以是其他的语句创建对象时肯定会执行一个构造函数3.4.1构造函数带参数的构造函数一般格式为:构造函数名(参数表);实参是在定义对象时给出的,一般格式为:类名对象名(实参表);带参数的构造函数形式可以方便的实现对不同对象进行不同的初始化3.4.1构造函数【例3-10】定义两个长方体,分别求出它们的体积。这两个长方体的长宽高分别是4,2,3和5,1,2。#include<iostream>usingnamespacestd;classBox{public: Box(floatL,floatw,floath)//带有参数的构造函数{length=L;width=w;height=h;} floatVolume(){returnlength*width*height;}private: floatlength,width,height;};intmain(){Boxbox1(4,2,3);//创建对象时给出实参

Boxbox2(5,1,2); cout<<"Volumeofbox1is"<<box1.Volume()<<endl; cout<<"Volumeofbox2is"<<box2.Volume()<<endl;return0;}3.4.1构造函数构造函数与参数初始化表这种方法不在构造函数的函数体内对数据成员初始化,而是在函数的首部实现例如:classBox{public:Box(floatL,floatw,floath):length(L),width(w),height(h){}floatVolume() {returnlength*width*height; }private:floatlength,width,height;};使用参数初始化表的构造函数3.4.1构造函数构造函数重载在类中定义多个构造函数,这些构造函数具有相同的函数名而参数表中参数的个数或类型不同相当于给类实例化对象时提供了不同的初始化方法3.4.1构造函数【例3-12】构造函数重载。//=============================================#include<iostream>usingnamespacestd;classBox{public: Box()//无参数的构造函数

{length=1;width=1;height=1;}Box(floatL,floatw,floath) //带有参数的构造函数

{length=L;width=w;height=h;} floatVolume(){returnlength*width*height; }private: floatlength,width,height;};//=============================================intmain(){ Boxbox1(4,2,3); //调用带有三个参数的构造函数创建对象

Boxbox2;//调用没有参数的构造函数创建对象

cout<<"Volumeofbox1is"<<box1.Volume()<<endl; cout<<"Volumeofbox2is"<<box2.Volume()<<endl; return0;}3.4.1构造函数(1)如果在类的声明中没有写一个构造函数,系统会自动生成一个无参的、函数体为空的默认构造函数。默认构造函数只是在形式上保证创建对象时必须有构造函数。(2)在程序中定义对象时一定要注意类中有几个构造函数,它们要求的参数分别是什么样的,如果创建对象时给出的参数表和所有的构造函数的参数表都不符合,则系统无法创建对象。(3)使用参数实例化对象时的格式是:类名对象名(实参表);。而使用默认构造函数实例化对象时的格式是:类名对象名;注意3.4.2析构函数析构函数的作用在系统释放对象之前进行清理工作。析构函数的特点析构函数的函数名是固定的,由“~”+“类名”组成析构函数没有返回值析构函数没有参数如果没有自己写出析构函数,系统会自动生成一个析构函数3.4.2析构函数析构函数的特点析构函数在对象生命周期结束时由系统自动调用析构函数的作用不是释放对象,释放对象是由系统来进行的,而是在系统释放对象之前进行一些清理工作,把对象所占用的额外内存空间归还给系统注意3.4.2析构函数【例3-13】带有析构函数的长方体类。//===========================================================classBox{public: Box()//无参数的构造函数

{length=1;width=1;height=1;} Box(floatL,floatw,floath) //带有参数的构造函数

{length=L;width=w;height=h;} floatVolume(){returnlength*width*height;} ~Box()//析构函数

{cout<<"DestructorofBoxiscalled!"<<endl;}private: floatlength,width,height;};//===========================================================intmain(){ Boxbox1(4,2,3); //调用带有3个参数的构造函数创建对象

Boxbox2;//调用没有参数的构造函数创建对象

cout<<"Volumeofbox1is"<<box1.Volume()<<endl; cout<<"Volumeofbox2is"<<box2.Volume()<<endl; return0;}程序执行后运行的结果如下:Volumeofbox1is24Volumeofbox2is1DestructorofBoxiscalled!DestructorofBoxiscalled!3.4.3调用次序总的原则当创建对象时调用构造函数,当释放对象时调用析构函数创建对象是当程序执行到了非静态对象的定义语句或第一次执行到静态对象的定义语句释放对象则是对象到了生命周期的最后时系统释放对象或通过delete运算符动态释放new运算符动态申请的对象【例3-14】验证调用构造函数和析构函数的顺序的例子3.5对象数组对象数组和普通的数组没有本质的区别,只不过普通的数组的元素是简单变量,而对象数组的元素是对象而已对象数组在实际中主要用于系统需要一个类的多个对象的情况在建立数组时,系统会自动调用每一个对象元素的构造函数(参见【例3-15】)3.5对象数组对象数组在建立时还可以给出实参以实现对数组元素进行不同的初始化类有只有一个参数的构造函数,可以使用如下形式的数组初始化形式:Studentstudents[3]={100,200,300};如果对象的构造函数需要多个参数,则在初始化的花括号里要分别写明构造函数,并指定实参对象数组初始化参见【例3-16】3.6对象与指针以指针的概念为基础,同时又加入了对象的特点对象与指针主要从三个方面进行讨论指向对象的指针指向对象成员的指针this指针3.6.1指向对象的指针指针指向的是内存中对象所占用空间的首地址定义指向对象的指针的一般形式是:类名*指针名;通过指向对象的指针访问对象的成员有两种形式通过“->”调用对象的公用成员函数通过“*”运算符得到对象,然后再使用“.”运算符调用对象的公用成员函数3.6.2指向对象成员的指针指向对象数据成员的指针指向对象数据成员的指针和普通的指针是完全相同的指向对象成员函数的指针指向对象成员函数的指针需要在指针名前面加上所属的类名及域运算符“::”指向对象成员函数的指针不但要匹配将要指向函数的参数类型、个数和返回值类型,还要匹配将要指向函数所属的类3.6.2指向对象成员的指针【例3-17】使用指向对象成员函数的指针调用对象的成员函数//===========================================================intmain(){ Boxbox(2,2,2); //创建Box的对象box float(Box::*p)();//定义指向Box类的成员函数的指针p p=&Box::Volume;//给指针p赋值,使其指向Box类的成员函数Volume cout<<"Volumeofboxis"<<(box.*p)()<<endl;//调用指针p指向的函数

return0;}//===========================================================(1)在给指向对象成员函数的指针进行赋值时要把类的函数名赋值给指针,而不是对象的函数名(2)调用指向对象成员函数的指针指向的成员函数时,要通过(对象名.*指针名)(实参表)的形式,而不是(类名.*指针名)(实参表)的形式。(3)定义指向对象成员函数的指针时可以同时进行初始化操作,形式为:返回值类型(类名::*指针名)(形参表)=&类名::成员函数名;如:float(Box::*p)()=&Box::Volume;注意3.6.3

this指针在每一个成员函数中都包含了一个特殊指针,这个指针的名字是固定的,称为this指针如Box类中的Volume函数,其中的height*width*length实际上是(this->height)*(this->width)*(this->length)this指针是指向本类对象的指针,它的指向是被调用成员函数所在的对象this指针是由系统通过参数隐式传递给成员函数的this指针的处理过程源程序编译后调用时floatBox::Volume(){returnlength*width*height;}floatBox::Volume(Box*this){returnthis->length*this->width*this->height;}box1.Volume(&box1);3.7对象与const在程序设计的过程中需要考虑的一个非常重要的因素就是数据的安全性在程序中,不同的模块之间经常出现需要共享数据的情况,此时数据的安全性降低在程序中既要让数据在一定范围内共享,又要保证数据的安全,这时可以使用const,把对象或对象相关成员定义成常量本节主要从常对象、常对象成员、指向对象的常指针、指向常对象的指针和对象的常引用五个方面进行说明3.7.1常对象常对象中的所有成员的值都不能被修改常对象中数据成员为常变量且必须有初值声明常对象的一般形式const类名对象名[(实参表)];类名const对象名[(实参表)];如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数(构造函数和析构函数除外)在成员函数声明的后面加上const即可访问3.7.2常对象成员常数据成员常数据成员的声明和作用与普通的常变量类似在程序运行过程中常数据成员的值不能修改常变量在声明的同时必须初始化注意常数据成员在初始化时必须使用构造函数的参数初始化表Box::Box(floatL,floatw,floath){ length=L;

width=w; height=h;}×不能使用这种形式进行初始化Box::Box(floatL,floatw,floath):length(L){width=w; height=h;}√3.7.2常对象成员常成员函数就是const型成员函数如果在常成员函数中出现了修改数据成员的语句,系统编译是通不过的声明常成员函数的一般形式:返回值类型成员函数名(形参表)const;成员函数分类数据成员分类常成员函数非常成员函数常数据成员可以访问,但不可修改值可以访问,但不可修改值非常数据成员可以访问,但不可修改值可以访问,也可以修改值常对象的数据成员可以访问,但不可修改值不允许访问和修改值3.7.2常对象成员(1)在一个类中可以根据需要将部分数据成员声明为常数据成员,另一部分数据成员为非const数据成员(2)如果一个类的所有数据成员都不允许修改,可以将这个类中的所有数据成员都声明成const数据成员,或者定义对象时声明为const对象。(3)常对象中的数据成员都是const数据成员,但是常对象中的成员函数不一定都是const成员函数(4)如果是常对象,只能调用其中的const成员函数(5)在类的定义中,常成员函数不能调用非常成员函数注意3.7.3指向对象的常指针将指向对象的指针变量声明为const型定义指向对象的常指针的一般形式:类名*const指针名[=&类的对象];在给pbox赋初值后pbox的值不能再修改一般情况下指向对象的const指针用作函数的形参指针在函数的执行过程中不会改变指针的指向可以防止误操作,增加系统的安全性3.7.4指向常对象的指针变量指向常对象的指针变量和指向常变量的指针变量的概念和用法非常接近定义指向常对象的指针变量的一般形式:const类名*指针变量名;说明:如果一个对象已被声明为常对象,只能用指向常对象的指针变量指向它,而不能用一般的(指向非const型对象的)指针变量去指向它如果定义了一个指向常对象的指针变量,并使它指向一个非const的对象,则其指向的对象是不能通过指针来改变的3.7.4指向常对象的指针变量说明:如果定义了一个指向常对象的指针变量,虽然不能通过它改变所指向的对象的值,但是指针变量本身的值是可以改变的指向常对象的指针变量最常用于函数的形参,目的是在保护形参指针所指向的对象,使它在函数执行过程中不被修改当希望在调用函数时参数对象的值不被修改,就应当把形参定义为指向常对象的指针变量,同时用对象的地址作实参,而对象参数可以是const或非const型。3.7.5对象的常引用对象的常引用表示一个对象的别名,但是无法通过引用来修改对象的数据成员声明对象的常引用的一般形式:const类名&引用名=对象名;常引用的应用也是主要用在函数的形参中,保证函数调用时实参对象的安全性例如:Clockclock(12,12,12);constClock&refclock=clock;refclock.Display();若Display函数是const成员函数,则合法;若Display函数是非const成员函数,则调用是非法的。3.8对象的动态创建和释放使用new和delete运算符实现对对象的动态创建与释放在程序执行到new语句时,系统会从内存堆中分配一块内存空间,存放类的对象,调用构造函数初始化对象。如果内存分配成功,返回分配的内存的首地址;如果分配内存失败,则会返回一个NULL。但是通过new运算符动态创建的对象没有名字,要声明一个指针变量来保存对象的首地址3.8对象的动态创建和释放可以在使用new运算符创建对象时给出实参,调用带有参数的构造函数初始化对象如:Box*pc=newBox(2,2,2);

为了保险起见,在使用对象指针之前一般先判断指针的值是否为NULL使用delete运算符释放该对象delete运算符的使用格式是:delete指针名;通过new运算符动态创建的对象只能通过delete运算符动态的释放3.9对象的赋值和复制对象赋值的一般形式对象名1=对象名2;对象赋值就是把对象2的数据成员的值复制给对象1对应的数据成员这个操作通过对赋值运算符的重载来实现默认的赋值运算符重载函数Box&Box::operator=(constBox&source){length=source.length;width=source.width;height=source.height;}3.9.1对象的赋值(1)同类对象之间的赋值操作只对其中的数据成员赋值,而不对成员函数赋值(2)如果类的数据成员中包含动态分配的数据,则不能使用默认的赋值运算符重载函数,必须亲自去写赋值运算符重载函数,否则就会引起指针悬挂问题。注意【例3-19】默认赋值运算符重

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论