Presentation is loading. Please wait.

Presentation is loading. Please wait.

第八章 类与对象 本章要求: 掌握类的含义与定义格式。 掌握类的无参构造函数、带参构造函数、拷贝构造函数和赋值重载函数的定义格式及作用。

Similar presentations


Presentation on theme: "第八章 类与对象 本章要求: 掌握类的含义与定义格式。 掌握类的无参构造函数、带参构造函数、拷贝构造函数和赋值重载函数的定义格式及作用。"— Presentation transcript:

1 第八章 类与对象 本章要求: 掌握类的含义与定义格式。 掌握类的无参构造函数、带参构造函数、拷贝构造函数和赋值重载函数的定义格式及作用。
第八章 类与对象 本章要求: 掌握类的含义与定义格式。 掌握类的无参构造函数、带参构造函数、拷贝构造函数和赋值重载函数的定义格式及作用。 掌握类的构造函数中初始化表的使用格式及功能。 掌握析构函数的定义格式与功能。 了解友元函数和友元类的声明与作用。

2 8.1 类的定义 类是对具有共同属性和行为的一类事物的抽象描述

3 8.1 类的定义 共同属性被描述为类中的数据成员 共同行为被描述为类中的成员函数 脊椎动物共同的属性:脊椎(长度、节数等)
8.1 类的定义 共同属性被描述为类中的数据成员 脊椎动物共同的属性:脊椎(长度、节数等) 鸟类的共同属性:翅膀(长度、羽毛等) 共同行为被描述为类中的成员函数 爬行动物共同的行为:爬行 猫科动物共同的行为:奔跑、捕食

4 8.1 类的定义 同结构和联合一样,类也是一种用户定义的类型,它包括定义数据成员和定义成员函数两个方面,用数据成员来描述同类事物的属性,用成员函数来描述他们的行为。 类是抽象的,不是实际存在的,既不占据存储 对象是具体的,象是类的实例化,是实际存在的,占据存储。

5 8.1 类的定义 8.1.1 类的定义格式 基本格式: class <类名> {<成员表>}; class为类类型定义的关键字,
8.1 类的定义 类的定义格式 基本格式: class <类名> {<成员表>}; class为类类型定义的关键字, <类名>为用户命名的标识符,用它可以定义该类的对象以及对象的引用、对象指针和对象数组。 <成员表>为该类包含的数据成员和成员函数的列表,每一个成员都具有一定的存取权限(或称访问权限),成员的存取权限是由存取指明符关键字public,private或protected所指定。

6 8.1 类的定义 8.1.1 类的定义格式 三个存取指明符的含义如下: public:公用访问属性,成员可以为任意函数所使用。
8.1 类的定义 类的定义格式 三个存取指明符的含义如下: public:公用访问属性,成员可以为任意函数所使用。 private:私有访问属性,成员只能为该类的成员函数和友元函数所使用。 protected:保护访问属性,成员只能为该类的成员函数和友元函数以及派生类中的成员函数和友元函数所使用。 说明:若成员定义的前面没有使用存取指明符规定存取权限,则类成员的访问属性默认为private,对于结构和联合成员的访问属性默认为public

7 8.1 类的定义 8.1.2 定义格式举例 1:struct CA { int a; int b; } ax; 2: class CB{
8.1 类的定义 定义格式举例 1:struct CA { int a; int b; } ax; 2: class CB{ int a; } bx; 3:class CC { int a; public: void init(int aa) { a=aa; } int GetData() { return a;} }cx;

8 8.1 类的定义 8.1.2 定义格式举例 5. class CE {private: int a,b;
8.1 类的定义 定义格式举例 5. class CE {private: int a,b; int getmax() {return(a>b? a:b);} public: int c; void setvalue(int ,int ,int ); int getmax() {int d=getmax(); return (d>c? d:c); } }; void CE::setvalue(int x1,int x2,int x3) {a=x1; b=x2; c=x3;} … … CE ex,*ep=&ex; 4. class CD { char* a; int b; public: void init( char* aa,int bb) {a=new char[strlen(aa)+1]; strcpy(a,aa); b=bb; } char* geta(){return a;} int getb() {return b;} void output() {cout<<a<<‘ ‘<<b<<endl;} }dx;

9 8.1 类的定义 有关说明 类中的成员函数和数据成员一样,都是在给定类中定义的,必须通过对象(包括直接对象和指针对象)调用成员函数。 在一个类的成员函数中,能够直接使用该类定义的所有数据成员和成员函数,其使用表示也是抽象的,因为并没有将它们同任何一个类对象具体联系起来。 一个类的每个成员函数中都隐含有一个所属类的指针参数,其名字由系统规定为this,它是一个c++关键字,this指针指向调用该成员函数的对象。

10 8.1 类的定义 有关说明 成员函数可以在类中给出定义;也可以使成员函数的声明和定义分开,即只在类中给出声明,而在类外给出完整的定义,这样做可以避免类体过于冗长。 成员函数同普通函数一样,也可以通过使用inline关键字把它定义为内联函数。若成员函数是在类中定义的,则隐含为内联的。 同普通函数一样,每个成员函数中说明的形参也允许带有默认值。

11 8.1 类的定义 8.1.3 有关说明 每个类类型的大小,即由该类定义的对象所占用存储空间的字节数等于所有数据成员所占存储字节数的总和。
8.1 类的定义 #include<iostream.h> class Time { private: int h,m,s; public: void SetTime(int,int,int); void DisplayTime() { cout<<h<<":"<<m<<":"<<s<<endl;} }; void Time::SetTime(int initH,int initM,int initS) { h=initH; m=initM; s=initS;} void main() Time t; t.SetTime(9,25,45); t.DisplayTime(); } 运行结果: 9:25:45 有关说明 每个类类型的大小,即由该类定义的对象所占用存储空间的字节数等于所有数据成员所占存储字节数的总和。 同普通函数一样,类中的成员函数也允许函数名重载和操作符重载。 例:定义一个时间类Time,能够表示时、分、秒组成 的时间和设置、显示时间,并编写应用程序,定 义时间对象,设置、输出该对象的时间。 例:(P237)

12 8.2 构造函数 构造函数和析构函数属于类中的成员函数。
8.2 构造函数 构造函数和析构函数属于类中的成员函数。 构造函数与所在的类具有相同的名字,并且不带任何返回类型,也不需要返回任何值,函数的参数表和函数体由用户根据需要编写,是否为一个类建立重载的多个构造函数,也由用户根据使用类的需要而定。 构造函数的作用是建立对象,为类对象中的数据成员赋初值,有时还为其中的指针数据成员动态分配所指向的存储空间。 构造函数是在建立对象时自动调用的,而不允许像其他成员函数那样由用户直接调用。 因为建立对象都是在类外进行的,必须把每个构造函数定义为类的公用成员。

13 8.2 构造函数 无参构造函数和带参构造函数 当定义一个类时,若没有定义构造函数,则系统隐含定义一个无参构造函数,该构造函数的函数体也为空,调用系统所给的构造函数不会执行任何操作,只是建立对象。 类定义中的无参构造函数可能是系统定义的(用户未定义任何构造函数时),也可能是用户定义的,但带参构造函数必定是由用户定义的。 当用类类型定义一个类对象时,若需要它自动调用无参构造函数对其进行初始化,则只需给出对象名,若需要它自动调用带参构造函数对其进行初始化,则给出的对象名后必须带有用圆括号括起来的实参表。

14 8.2 构造函数 8.2.2 拷贝构造函数 类中的构造函数当有并且只有一个所属类的引用参数时,则称此构造函数为拷贝构造函数或复制构造函数。
8.2 构造函数 #include<iostream.h> class A { public: A( );//声明无参构造函数 A(int,int=0);//声明有参构造函数 A(A&);//声明拷贝构造函数 private: int a,b; }; A::A( )//定义无参构造函数 { a=0;b=0; cout<<"Constructor!"<<endl; } A::A(int initA,int initB)//定义有参构造函数 { a=initA;b=initB; cout<<"Constructor:"<<a<<','<<b<<endl; A::A(A&x)//定义拷贝构造函数 { a=x.a;b=x.b; cout<<"Copying Constructor:"<<a<<','<<b<<endl; void main(){ A m(2);//调用有参构造函数一次 A *p=new A[2];//调用无参构造函数2次 A n(m);//调用拷贝构造函数一次 拷贝构造函数 类中的构造函数当有并且只有一个所属类的引用参数时,则称此构造函数为拷贝构造函数或复制构造函数。 当用一个类对象初始化同类的另一个对象时需要调用相应的拷贝构造函数。 若一个类中不带有拷贝构造函数,则系统为该类隐含定义一个拷贝构造函数。 X(X& x) { *this=x; //将引用形参的值赋给被初始化的对象 } 例:构造函数、拷贝构造函数举例。

15 8.2 构造函数 #include<iostream.h> #include<string.h> class A { public: A(char*);//声明构造函数 A&operator=(A&);//声明对象赋值重载函数 A&operator=(char*);//声明字符串赋值重载函数 private: char *a; }; A::A(char*init)//定义构造函数 { a=new char[strlen(init)+1];//分配存储空间 strcpy(a,init); cout<<"Constructor:"<<a<<endl; } A& A::operator=(A&x)//定义赋值重载函数 { delete[]a;//释放a所指向的存储空间 a=new char[strlen(x.a)+1];//按新的长度重新分配存储空间 strcpy(a,x.a); cout<<"operator=:"<<a<<endl; return *this; A& A::operator=(char*init)//定义赋值重载函数 a=new char[strlen(init)+1];//按新的长度重新分配存储空间 void main(){ A x("string"),y("str");//调用A(char*)二次 y=x;//调用operator=(A&) x="The string";//调用operator=(char*) 赋值重载函数 在一个类中,若存在指针成员指向动态分配的存储空间的情况,则进行类对象赋值时,同样是把一个对象中指针成员的值赋给另一个对象的相应指针成员中,使它们共同指向同一个动态存储空间。当一个对象中指针成员所指向的存储空间被释放后,致使另一个对象中相应的指针成员指向一个无效的存储空间,为避免这种现象发生,同样可以定义一个赋值操作符重载函数。 例:赋值重载函数举例。

16 8.2 构造函数 #include<iostream.h> class Time { private: int h,m,s; public: Time(int,int,int); void DisplayTime( ) { cout<<h<<":"<<m<<":"<<s<<endl;} }; Time::Time(int initH,int initM,int initS):h(initH),m(initM),s(initS){ } void main( ) Time t(9,25,45); t.DisplayTime(); } 构造函数中的初始化表 在构造函数中给数据成员赋值时,可以采用两种格式,一种是在函数体中使用赋值语句把表达式的值赋给成员变量,第二种是在形参表后和函数体之前使用初始化表(又称初值表)赋值,并且初始化表同形参表之间必须用冒号分开,初始化表中用逗号分开的每一项用于给一个成员变量赋值,每一项的格式为“成员变量名(初值表达式)”。 例:在构造函数中采用初始化表举例。

17 8.3 析构函数 析构函数的名字与类名相同,不过应在函数名前加上波折号(~),以示同构造函数的区别。
#include<iostream.h> #include<string.h> class AB { private: int a; char *b; public: AB(int,char*); ~AB();//声明析构函数 }; AB::AB(int aa,char*bb) { a=aa; b=new char[strlen(bb)+1]; strcpy(b,bb); cout<<"Constructor:"<<a<<","<<b<<endl; } AB::~AB( )//定义析构函数 cout<<"Destructor:"<<a<<","<<b<<endl; delete b; void main() AB x(10,"ABC"), *p=new AB(1,"DEFG"); delete p;//调用析构函数撤销对象*p } //调用析构函数撤销对象x 8.3 析构函数 析构函数的名字与类名相同,不过应在函数名前加上波折号(~),以示同构造函数的区别。 析构函数不允许带任何参数(所以析构函数不可能重载),并且也不允许带有返回类型。 析构函数可以同其他成员函数一样由对象调用,但通常析构函数是在对象撤消时由系统自动调用的,并且调用执行后才真正撤消对象。 当用户没有给一个类定义析构函数时,系统隐含给这个类定义一个析构函数,该函数的函数体为空。 由于析构函数是在对象撤消时被自动调用的,所以通常利用析构函数删除对象中由指针成员所指向的动态分配的存储空间,当类中不使用动态存储空间时,则通常不需要定义析构函数。 例:构造函数、析构函数举例。

18 //使用共用函数实现私有成员的访问 #include<iostream.h> class Complex{ private: double real,imag; public: Complex(double r,double i){real=r; imag=i;}//定义构造函数 double getreal(){return real;}//定义共用函数 double getimag(){return imag;} //定义共用函数 }; void add(Complex &x,Complex &y)//定义普通函数 { double r1,r2,i1,i2; r1=x.getreal(); r2=y.getreal();//获取私有成员信息 i1=x.getimag(); i2=y.getimag(); //获取私有成员信息 double real=r1+r2;cout<<real<<"+"; double imag=i1+i2;cout<<imag<<"i"<<endl; } void main() { Complex z1(5,2.5),z2(-3,0.8); add(z1,z2); 运行结果: 2+3.3i 8.4 友元函数和友元类 在一个类中,类对象的私有成员只能由该类的成员函数访问,外部定义的普通函数和其他类中定义的成员函数都不得访问,这些外部函数只能通过该类提供的公用成员函数访问类对象的私有成员。这将带来很低的访问效率。

19 //使用友元函数实现复数的加法 #include<iostream.h> class Complex{ private: double real,imag; public: Complex(double r,double i){real=r; imag=i;}//定义构造函数 friend void add(Complex &x,Complex &y);//声明友元函数 }; void add(Complex &x,Complex &y)//定义普通函数 { double real=x.real+y.real;cout<<real<<"+"; double imag=x.imag+y.imag;cout<<imag<<"i"<<endl; } void main() Complex z1(5,2.5),z2(-3,0.8); add(z1,z2); 运行结果: 2+3.3i 8.4 友元函数和友元类 C++允许在一个类中把外部的有关函数或类声明为它的友元函数或友元类,被声明为一个类的友元函数或友元类具有直接访问该类的私有成员的特权。 声明友元函数或友元类的语句以关键字friend开始,后跟一个函数或类的声明。此语句可以放在类中的任何位置,与它前面使用的任一访问权限关键字无关。 例:使用友元函数实现复数的加法。

20 8.4 友元函数和友元类 例:使用友元类对数组逆置。 例1:友元函数(P251) 例2:友元类(P253) 例3:友元类(P255)
//使用友元类对数组逆置 #include<iostream.h> const int n=5; class MyClass;//类MyClass的不完整定义 class YourClass//定义类YourClass { private: int a[n]; friend class MyClass;//声明友元类 public: YourClass(const int&);//声明构造函数 }; YourClass::YourClass(const int&size)//定义构造函数 for(int i=0;i<size;i++) a[i]=i+1; } class MyClass//定义类MyClass void Convert(YourClass&s)//定义实现逆置的成员函数 for(int i=0;i<n/2;i++) { int swap=s.a[i]; s.a[i]=s.a[n-i-1]; s.a[n-i-1]=swap; } void print(YourClass&s)//定义输出数组的成员函数 for(int i=0;i<n;i++) cout<<s.a[i]<<" "; cout<<endl; }; void main( ) YourClass YourObj(n); MyClass MyObj; MyObj.print(YourObj);//输出数组 MyObj.Convert(YourObj);//数组逆置 8.4 友元函数和友元类 例:使用友元类对数组逆置。 例1:友元函数(P251) 例2:友元类(P253) 例3:友元类(P255)

21 8.4 友元函数和友元类 封装--把类当中的细节隐含起来 友元函数、友元类从某种程度上破坏了数据的封装性,应当有限制地使用。
8.4 友元函数和友元类 封装--把类当中的细节隐含起来 电视机是一个封装好的机器,包含电源、扫描系统、升压系统、电子管等许多环节,而这些内容全部封装在其内部,用户无须关心 电视机提供了一些简单而有效的控制方法,如按键和遥控,用户只需要学会使用这些接口就行了 一个封装好的类是不希望用户去访问其私有成员的,只希望用户访问其共用成员,以保证其纯洁性 友元函数、友元类从某种程度上破坏了数据的封装性,应当有限制地使用。


Download ppt "第八章 类与对象 本章要求: 掌握类的含义与定义格式。 掌握类的无参构造函数、带参构造函数、拷贝构造函数和赋值重载函数的定义格式及作用。"

Similar presentations


Ads by Google