910 likes | 1.14k Views
Visual C++ 程序设计. 武汉职业技术学院计算机科学系. 万 彪 2004.11. 第三章 C++ 语言基础. 本 章 内 容. 1 、 C++ 语言概述. 6 、函数. 2 、基本数据类型. 7 、指针与数组. 3 、常量和变量. 8 、扩展数据类型. 4 、表达式. 9 、类与对象. 5 、流程控制. 10 、多态性. 3.9 类与对象. 3.9.1 类 3.9.2 对象 3.9.3 构造函数与析构函数 3.9.4 类模板 3.9.5 友元 3.9.6 类的继承与派生.
E N D
Visual C++程序设计 武汉职业技术学院计算机科学系 万 彪 2004.11
第三章 C++语言基础 本 章 内 容 1、C++语言概述 6、函数 2、基本数据类型 7、指针与数组 3、常量和变量 8、扩展数据类型 4、表达式 9、类与对象 5、流程控制 10、多态性
3.9 类与对象 3.9.1 类 3.9.2 对象 3.9.3 构造函数与析构函数 3.9.4 类模板 3.9.5 友元 3.9.6 类的继承与派生
3.9.1 类——类与对象 • 对象由属性和操作构成 属性:状态、特征、组成成员 操作:修改属性,访问属性,执行命令 • 类是具有相似特征的对象的抽象 学生类:所有具体学生对象的抽象 文件类:所有具体文件对象的抽象
3.9.1 类——类与对象 • 类是抽象的,对象是具体的。 • 类是类型,对象是变量。 • 类是模型,对象是实例。
3.9.1 类——类的定义 • 类是对一组客观对象的抽象,它将该组对象所 具有的共同特征(包括结构特征和行为特征)集 中起来,以说明该组对象的能力和性质。 • 利用类可以实现数据的封装、隐藏、继承与派生。 • 利用类易于编写大型复杂程序,其模块化程度比C中采用函数更高。
3.9.1 类——类的描述 形式: 例: class 类名 { [private:] 私有数据成员和成员函数; [protect:] 保护数据成员和成员函数; [public:] 公有数据成员和成员函数; }; class horse { private: char color; //属性 char sort; public: //操作 void move(); void eat(); };
3.9.1 类——类的成员 类的成员访问控制 公有(public):——完全公开 保护(protected):——适当公开 私有(private):——不公开
3.9.1 类——类的成员 类的成员访问控制 私有(private)类型成员:在关键字private后 面声明,只允许本类中的函数访问,而类外部 的任何函数都不能访问。 如果紧跟在类名称的后面声明私有成员, 则关键字private可以省略。 保护(protected)类型成员:与private类似, 其差别表现在继承与派生时对派生类的影响不 同。
3.9.1 类——类的成员 • 成员数据:与一般的变量声明相同,但需要将它们放在类的声明体中。 • 成员函数:在类中说明原形,可以在类外给出函数体实现,并在函数名前使用类名加以限制。也可以直接在类中给出函数体,形成内联成员函数。 允许声明重载函数和带缺省行参值的函数。
3.9.1 类——类的成员 • class clock • { • public: • void SetTime(int h,int m,int s); //成员函数 • void ShowTime(); • private: • int Hour,Minute,Second; //成员数据 • }; • void clock::SetTime(int h,int m,int s) • { • Hour=h; • Minute=m; • Second=s; • } • void clock::ShowTime() • { • cout<<Hour<<":"<<Minute<<":"<<Second; • }
3.9.1 类——内联成员函数 • 为了提高运行时的效率,对于较简单的函数可以声明为内联形式。 • 内联函数体中不要有复杂结构(如循环语句和swtich语句等)。 • 在类中声明内联成员函数的方式: -将函数体放在类的声明中——隐式; -使用inline关键字——显式。
3.9.1 类——内联成员函数举例(隐式) • class Point • { • public: • void Init(int initX,int initY) • { • X=initx; • Y=inity; • } • int GetX(){return X;} • int GetY(){return Y;} • private: • int X,Y; • }
3.9.1 类——内联成员函数举例(显式) • class Point • { • public: • void Init(int initX,int initY) • int GetX(); • int GetY(); • private: • int X,Y; • } • inline void Point::Init(int initX,int initY) • { • X=initx; • Y=inity; • } • inline int Point::GetX() • {return X;} • inline int Point::GetY() • {return Y;}
3.9 类与对象 3.9.1 类 3.9.2 对象 3.9.3 构造函数与析构函数 3.9.4 友元 3.9.5 类模板 3.9.6 类的继承与派生
3.9.2 对象的定义 • 类的对象是该类的某一特定实体,即类类型的变量。 • 声明形式: 类名 对象名; • 例: Clock myClock;
3.9.2 对象 类的成员的访问方式 • 类中成员互访 直接使用成员名。 • 类外访问 使用“对象名.成员名”方式访问public属性的成员。 间接访问使用“对象指针->成员名”。
3.9.2 对象的定义 对象的定义及访问 圆点操作符访问 class horse { private: char sort; public: char color;//属性 void move(); //操作 void eat(); }; horse a,b,c,*p; a.color=“red”; a.move(); p=new horse; p->move(); 指针操作符访问
3.9.2 类和对象——举例 • #include<iostream.h> • class clock • { • public: • void SetTime(int h,int m,int s); //成员函数 • void ShowTime(); • private: • int Hour,Minute,Second; //成员数据 • }; • void clock::SetTime(int h,int m,int s) • { • Hour=h; • Minute=m; • Second=s; • }
3.9.2 类和对象——举例 • void clock::SetTime(int h,int m,int s) • { • Hour=h; • Minute=m; • Second=s; • } • void clock::ShowTime() • { • cout<<Hour<<":"<<Minute<<":"<<Second<<endl; • } • void main() • { • clock myClock; • myClock.SetTime(8,30,30); • myClock.ShowTime(); • }
3.9.2 类——类与结构 • struct student • { int num; • char sex; • int age; • }; • void fn() • { student stu1; • stu1.num=1; • stu1.sex=‘M’; • stu1.age=20; • } 结构与类的区别: 类中成员的缺省存储属性为私有的。 结构体中成员的缺省存储属性均为公有。
3.9 类与对象 3.9.1 类 3.9.2 对象 3.9.3 构造函数与析构函数 3.9.4 类模板 3.9.5 友元 3.9.6 类的继承与派生
3.9.3 构造函数和析构函数 • 构造函数:由于类的封装性,不能象普通变量一样对类中的数据进行初始化。 • 构造函数形式: struct savings {unsigned accountNumber; float balance; } savings A={1,2000.0}; saving B={2,3000.0}; 结构体可以 直接初始化,但类不能 class A{ … A( );//构造函数名字必须与类名相同,没有返 } //回值类型,可以有任何类型的参数
3.9.3 构造函数和析构函数 • 构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。 • 创建自定义的构造函数后,在声明对象时的格式如下:类名 对象名(参数); //使用带参数的构造函数 或类名 对象名;//使用无参数的构造函数 • 在对象创建时由系统自动调用。 • 如果程序中未声明,则系统自动产生出一个缺省形式的构造函数。 • 构造函数可以为内联函数、重载函数、带缺省行参值的函数。
3.9.3 构造函数举例 • #include<iostream.h> • class clock • { • public: • clock(int h,int m,int s); //构造函数 • void SetTime(int h,int m,int s); • void ShowTime(); • private: • int Hour,Minute,Second; • };
3.9.3 构造函数举例 构造函数的实现: • clock::clock(int h,int m,int s) • { • Hour=h; • Minute=m; • Second=s; • } 建立对象时构造函数的作用: • void main() • { • clock c(0,0,0); //隐含调用构造函数,将初始值作为实参 • c.ShowTime(); • }
3.9.3 构造函数——重载构造函数举例 • #include<iostream.h> • class demo • {int x,y; • public: • demo(int a,int b) • {x=a;y=b; • cout<<"Constructor demo(int,int) be called...\n"; • } • demo() • {cout<<"Constructor demo(int,int) be called...\n";} • void show() • {cout<<"X="<<x<<'\t'<<"Y="<<y<<endl;} • }; • void main() • { • demo d1(3,5); • d1.show(); //输出结果为x=3,y=5 • demo d2; • d2.show(); //输出结果为随机值 • }
3.9.3 构造函数——拷贝构造函数 • 拷贝构造函数是一种特殊的构造函数,其行参为本类的对象所应用。 • 作用:使用一个对象(参数指定的对象)去初始化一个正在被建立的同类型对象。 class类名 {public: 类名(行参); //构造函数 类名(类名&对象名); //拷贝构造函数 … }; 类名::类名(类名&对象名) //拷贝构造函数的实现 {函数体}
3.9.3 构造函数——拷贝构造函数举例 • class Point • { • public: • Point(int xx=0,int yy=0){X=xx;Y=yy;} • Point(Point& p); • int GetX() {return X;} • int GetY() {return Y;} • private: • int X,Y; • } • Point::Point(Point& p) • { • X=p.X; • Y=p.Y; • cout<<"拷贝构造函数被调用"<<endl; • }
3.9.3 拷贝构造函数举例 用法一:当用类的一个对象去初始化该类的另一个对象时,系统自动调用它实现拷贝赋值。 • void main() • { • Point A(1,2); • Point B(A); //拷贝构造函数被调用 • cout<<B.GetX()<<endl; • }
3.9.3 拷贝构造函数举例 用法二:若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。 • void fun1(Point p) • { • cout<<p.GetX()<<endl; • } • void main() • { • Point A(1,2); • fun1(A); //调用拷贝构造函数 • }
3.9.3 构造函数——拷贝构造函数举例 用法三:当函数的返回值是类对象时,系统自动调用拷贝构造函数。 • Point fun2() • { • Point A(1,2); • return A; //调用拷贝构造函数 • } • void main() • { • Point B; • B=fun2(); • }
3.9.3 构造函数——拷贝构造函数 注意:如果程序员没有为类声明拷贝初始 化构造函数,则编译器自动生成一个拷贝构造 函数。 这个构造函数执行的功能是:用作为初始 值的对象的每个数据成员的值,初始化将要建 立的对象的对应数据成员。
3.9.3 构造函数——析构函数 • 析构函数形式: • 完成对象被删除前的一些清理工作。 • 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。 • 如果程序中未声明析构函数,编译器自动产生一个缺省的析构函数。这个析构函数什么也不做。 class A{ A(); //构造函数 ~A();} //析构函数
3.9.3 构造函数——析构函数举例 • #include<iostream.h> • class A • { • int x,y; • public: • A(int a=0,int b=0) • {x=a;y=b;} • void P(void) • {cout<<x<<'\t'<<y<<endl;} • ~A() • {cout<<"调用了析构函数!"<<endl;} • }; • void main() • { • A b(50,100); • b.P(); • cout<<"退出主函数!"<<endl; • } • 输出结果: • 100 • 退出主函数! • 调用了析构函数!
3.9 类的运用举例 一圆形游泳池如图所示,现在需在其周围建一圆 形过道,并在其四周围上栅栏。栅栏的价格为35元/ 米,过道造价为20元/米。过道宽度为3米,游泳池半 径由键盘输入。要求编程计算并输出过道和栅栏的造 价。 过道 游泳池
3.9 类的运用举例 • #include<iostream.h> • const double PI=3.14159; • const float FencePrice=35; • const float ConcretePrice=20; • //声明类Circle及其数据和方法 • class Circle • { • private: • float radius; • public: • Circle(float r); //构造函数 • float Circumference(); //圆周长 • float Area(); //圆面积 • };
3.9 类的运用举例 • //类的实现 • //构造函数初始化数据成员radius • Circle::Circle(float r) • {radius=r;} • //计算圆周长 • float Circle::Circumference() • { • return 2*PI*radius; • } • //计算圆面积 • float Circle::Area() • { • return PI*radius*radius; • }
3.9 类的运用举例 • void main() • { • float radius; • float FenceCost,ConcreteCost; • //提示用户输入半径 • cout<<"Enter the radius of the pool:"; • cin>>radius; • //声明Circle对象 • Circle Pool(radius); • Circle PoolRim(radius+3); • //计算栅栏造价并输出 • FenceCost=PoolRim.Circumference()*FencePrice; • cout<<"Fencing Cost is ¥"<<FenceCost<<endl; • //计算过道造价并输出 • ConcreteCost=(PoolRim.Area()-Pool.Area())*ConcretePrice; • cout<<"Concret Cost is ¥"<<ConcreteCost<<endl; • }
3.9 类与对象 3.9.1 类 3.9.2 对象 3.9.3 构造函数与析构函数 3.9.4类模板 3.9.5 友元 3.9.6 类的继承与派生
3.9.5 类模板 使用类模板使用户可以为类声明一种模 式,使得类中的某些数据成员、某些成员函数 的参数、某些成员函数的返回值,能取任意类 型(包括系统预定义的和用户自定义的)。 template <模板参数表> 类声明
3.9.5 类模板 定义一个类模板与定义函数模板的格式类 似,必须以关键字template开始,后面是< >括 起来的模板参数,然后是类名,其格式如下: template<class Type> class 类名{ ... ... }; 其中template是一个声明模板的关键字,表 示声明一个模板,Type是模板参数。
3.9.4 类模板举例 例:下面程序建立了一个复数类模板 • #include<math.h> • template<class T> • class complex{ • private: • T real; • T image; • public: • complex(T r=0.0,T i=0.0) • {real=r;image=i;} • T realcomplex() {return real;} • T imagecomplex() {return image;} • T abscomplex() • {double t; • t=(double)real*real+(double)image*image; • return sqrt(t); • } • }
3.9.4 类模板 在类定义体外定义成员函数时,若此成员函数中有 模板参数存在,则需要在函数体外进行模板声明,并 且在函数名前的类名后缀上“<Type>”。 例:成员函数在类定义体外定义为 • template<class T> • T complex<T>::realcomplex() • { • return real; • }
3.9.4 类模板 类模板不代表一个具体的、实际的类,而代 表着一类类,实际上类模板的使用就是将类模 板实例化成一个具体的类。格式为: 类名 <实际的类型>对象名; 例:使用上面类模板创建两个模板参数为 double型的对象 complex<double>s1,s2;
3.9.4 类模板——举例 • #include<iostream.h> • #include<stdlib.h> • struct Student • { • int id; //学号 • float gpa; //平均分 • }; • template<class T> //类模板,实现存取任意数据类型 • class Store • {private: • T item; //存放任意类型数据 • int haveValue; //标记item是否已被存入内容 • public: • Store(void); //缺省形式(无参数)的构造函数 • T GetElem(void);//提取数据函数 • void PutElem(T x); //存入数据函数 • };
3.9.4 类模板——举例 • //缺省形式构造函数的实现 • template<class T> • Store<T>::Store(void):haveValue(0){} • //提取构造函数的实现 • template<class T> • T Store<T>::GetElem(void) • { //如果试图提取未初始化的数据,则中止程序 • if(haveValue==0) • {cout<<"No item present!"<<endl; • exit(1); • } • return item; //返回item存放的数据 • } • //存入数据函数的实现 • template<class T> • void Store<T>::PutElem(T x) • { • haveValue++;//将haveValue值置为true,表示item已存入数 • item=x; //将x值存入item • }
3.9.4 类模板——举例 • void main() • { • Student g={1000,23}; • Store<int> s1,s2; • Store<Student> s3; • Store<double> s4; • s1.PutElem(3); • s2.PutElem(-7); • cout<<s1.GetElem()<<" "<<s2.GetElem()<<endl; • s3.PutElem(g); • cout<<"The Student id is:"<<s3.GetElem().id<<endl; • cout<<"Retrieving object s4:"; • cout<<s4.GetElem()<<endl; • //由于s4未经初始化,执行函数s4.GetElem(),无值 • }
3.9.4 类模板 类 模 板 Store<T> 实例化 实例化 模 板 类 Store<Student> 模 板 类 Store<double> 模 板 类 Store<int>
3.9 类与对象 3.9.1 类 3.9.2 对象 3.9.3 构造函数与析构函数 3.9.4 类模板 3.9.5 友元 3.9.6 类的继承与派生