Upload
alpha
View
53
Download
4
Embed Size (px)
DESCRIPTION
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 类的继承与派生. - PowerPoint PPT Presentation
Citation preview
1武汉职业技术学院计算机科学系 万 彪2004.11
Visual C++ 程序设计
万 彪
2004.11
武汉职业技术学院计算机科学系
2武汉职业技术学院计算机科学系 万 彪2004.11
第三章 C++ 语言基础
本 章 内 容
1 、 C++ 语言概述1 、 C++ 语言概述
2 、基本数据类型2 、基本数据类型
3 、常量和变量 3 、常量和变量
4 、表达式 4 、表达式
6 、函数 6 、函数
7 、指针与数组 7 、指针与数组
8 、扩展数据类型8 、扩展数据类型
9 、类与对象 9 、类与对象
5 、流程控制 5 、流程控制 10 、多态性10 、多态性
3武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类与对象
3.9.1 类3.9.2 对象3.9.3 构造函数与析构函数3.9.4 类模板3.9.5 友元3.9.6 类的继承与派生
4武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——类与对象
对象由属性和操作构成 属性:状态、特征、组成成员 操作:修改属性,访问属性,执行命令类是具有相似特征的对象的抽象 学生类:所有具体学生对象的抽象 文件类:所有具体文件对象的抽象
5武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——类与对象
类是抽象的,对象是具体的。
类是类型,对象是变量。
类是模型,对象是实例。
6武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——类的定义类是对一组客观对象的抽象,它将该组对象所 具有的共同特征(包括结构特征和行为特征)集 中起来,以说明该组对象的能力和性质。利用类可以实现数据的封装、隐藏、继承与派生。利用类易于编写大型复杂程序,其模块化程度比
C 中采用函数更高。
7武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——类的描述
形式: 例:
class 类名{ [private:] 私有数据成员和成员函数 ; [protect:] 保护数据成员和成员函数 ; [public:] 公有数据成员和成员函数 ; } ;
class horse{ private: char color; // 属性 char sort; public: // 操作 void move(); void eat();};
8武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——类的成员
类的成员访问控制公有 (public) :——完全公开
保护 (protected) :——适当公开
私有 (private) :——不公开
9武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——类的成员
类的成员访问控制 私有 (private) 类型成员:在关键字 private 后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。 如果紧跟在类名称的后面声明私有成员,则关键字 private 可以省略。 保护 (protected) 类型成员:与 private 类似,其差别表现在继承与派生时对派生类的影响不同。
10武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——类的成员
成员数据:与一般的变量声明相同,但需要将它们放在类的声明体中。
成员函数:在类中说明原形,可以在类外给出函数体实现,并在函数名前使用类名加以限制。也可以直接在类中给出函数体,形成内联成员函数。
允许声明重载函数和带缺省行参值的函数。
11武汉职业技术学院计算机科学系 万 彪2004.11
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;• }
12武汉职业技术学院计算机科学系 万 彪2004.11
3.9.1 类——内联成员函数
为了提高运行时的效率,对于较简单的函数可以声明为内联形式。
内联函数体中不要有复杂结构(如循环语句和 swtich 语句等)。
在类中声明内联成员函数的方式: -将函数体放在类的声明中——隐式; -使用 inline 关键字——显式。
13武汉职业技术学院计算机科学系 万 彪2004.11
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;• }
14武汉职业技术学院计算机科学系 万 彪2004.11
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;}
15武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类与对象
3.9.1 类3.9.2 对象3.9.3 构造函数与析构函数3.9.4 友元3.9.5 类模板3.9.6 类的继承与派生
16武汉职业技术学院计算机科学系 万 彪2004.11
3.9.2 对象的定义
类的对象是该类的某一特定实体,即类类型的变量。
声明形式: 类名 对象名;例: Clock myClock ;
17武汉职业技术学院计算机科学系 万 彪2004.11
3.9.2 对象
类的成员的访问方式类中成员互访 直接使用成员名。类外访问 使用“对象名 . 成员名”方式访问 public
属性的成员。 间接访问使用“对象指针 -> 成员名”。
18武汉职业技术学院计算机科学系 万 彪2004.11
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();
圆点操作符访问
指针操作符访问
19武汉职业技术学院计算机科学系 万 彪2004.11
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;• }
20武汉职业技术学院计算机科学系 万 彪2004.11
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();• }
21武汉职业技术学院计算机科学系 万 彪2004.11
3.9.2 类——类与结构
• struct student• { int num;• char sex;• int age;• };• void fn()• { student stu1;• stu1.num=1;• stu1.sex=‘M’;• stu1.age=20;• }
结构与类的区别: 类中成员的缺省存储属性为私有的。 结构体中成员的缺省存储属性均为公有。
22武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类与对象
3.9.1 类3.9.2 对象3.9.3 构造函数与析构函数3.9.4 类模板3.9.5 友元3.9.6 类的继承与派生
23武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 构造函数和析构函数
构造函数:由于类的封装性,不能象普通变量一样对类中的数据进行初始化。
构造函数形式:
struct savings{unsigned accountNumber; float balance;}savings A={1,2000.0};saving B={2,3000.0};
结构体可以直接初始化,但类不能
class A{ … A( );// 构造函数名字必须与类名相同 ,没有返} // 回值类型,可以有任何类型的参数
24武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 构造函数和析构函数构造函数的作用是在对象被创建时使用特定的值构
造对象,或者说将对象初始化为一个特定的状态。创建自定义的构造函数后,在声明对象时的格式如下:类名 对象名 ( 参数 ); // 使用带参数的构造函数
或类名 对象名; // 使用无参数的构造函数在对象创建时由系统自动调用。如果程序中未声明,则系统自动产生出一个缺省形
式的构造函数。构造函数可以为内联函数、重载函数、带缺省行参
值的函数。
25武汉职业技术学院计算机科学系 万 彪2004.11
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; • };
26武汉职业技术学院计算机科学系 万 彪2004.11
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();• }
27武汉职业技术学院计算机科学系 万 彪2004.11
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(); //输出结果为随机值• }
28武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 构造函数——拷贝构造函数 拷贝构造函数是一种特殊的构造函数,其行参为本类的对象所应用。 作用:使用一个对象(参数指定的对象)去初始化一个正在被建立的同
类型对象。
class 类名{public: 类名 ( 行参 ); // 构造函数 类名 ( 类名 & 对象名 ); //拷贝构造函数 …} ;类名 :: 类名 ( 类名 & 对象名 ) //拷贝构造函数的实现{ 函数体 }
29武汉职业技术学院计算机科学系 万 彪2004.11
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;• }
30武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 拷贝构造函数举例
用法一:当用类的一个对象去初始化该类的另一个对象时,系统自动调用它实现拷贝赋值。
• void main()
• {
• Point A(1,2);
• Point B(A); //拷贝构造函数被调用• cout<<B.GetX()<<endl;
• }
31武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 拷贝构造函数举例用法二:若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。
• void fun1(Point p)• {• cout<<p.GetX()<<endl;• }• void main()• {• Point A(1,2);• fun1(A); //调用拷贝构造函数• }
32武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 构造函数——拷贝构造函数举例用法三:当函数的返回值是类对象时,系统自动调用拷贝构造函数。
• Point fun2()• {• Point A(1,2);• return A; //调用拷贝构造函数• }• void main()• {• Point B;• B=fun2();• }
33武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 构造函数——拷贝构造函数
注意:如果程序员没有为类声明拷贝初始化构造函数,则编译器自动生成一个拷贝构造函数。 这个构造函数执行的功能是:用作为初始值的对象的每个数据成员的值,初始化将要建立的对象的对应数据成员。
34武汉职业技术学院计算机科学系 万 彪2004.11
3.9.3 构造函数——析构函数
析构函数形式:
完成对象被删除前的一些清理工作。在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。
如果程序中未声明析构函数,编译器自动产生一个缺省的析构函数。这个析构函数什么也不做。
class A{ A(); // 构造函数 ~A();} // 析构函数
35武汉职业技术学院计算机科学系 万 彪2004.11
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;• }
输出结果:50 100退出主函数!调用了析构函数!
36武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类的运用举例
一圆形游泳池如图所示,现在需在其周围建一圆形过道,并在其四周围上栅栏。栅栏的价格为 35 元 /
米,过道造价为 20 元 /米。过道宽度为 3米,游泳池半径由键盘输入。要求编程计算并输出过道和栅栏的造价。 过道
游泳池
37武汉职业技术学院计算机科学系 万 彪2004.11
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(); // 圆面积• };
38武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类的运用举例• // 类的实现• // 构造函数初始化数据成员 radius• Circle::Circle(float r)• {radius=r;}
• // 计算圆周长• float Circle::Circumference()• {• return 2*PI*radius;• }• // 计算圆面积• float Circle::Area()• {• return PI*radius*radius;• }
39武汉职业技术学院计算机科学系 万 彪2004.11
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;• }
40武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类与对象
3.9.1 类3.9.2 对象3.9.3 构造函数与析构函数3.9.4 类模板3.9.5 友元3.9.6 类的继承与派生
41武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 类模板
使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值,能取任意类型(包括系统预定义的和用户自定义的)。
template < 模板参数表 >类声明
42武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 类模板
定义一个类模板与定义函数模板的格式类似,必须以关键字 template 开始,后面是 < > 括起来的模板参数,然后是类名,其格式如下: template<class Type>
class 类名 {
... ...
};
其中 template 是一个声明模板的关键字,表示声明一个模板, Type 是模板参数。
43武汉职业技术学院计算机科学系 万 彪2004.11
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);• }• }
44武汉职业技术学院计算机科学系 万 彪2004.11
3.9.4 类模板
在类定义体外定义成员函数时,若此成员函数中有模板参数存在,则需要在函数体外进行模板声明,并且在函数名前的类名后缀上“ <Type>” 。 例:成员函数在类定义体外定义为• template<class T>• T complex<T>::realcomplex()• {• return real;• }
45武汉职业技术学院计算机科学系 万 彪2004.11
3.9.4 类模板
类模板不代表一个具体的、实际的类,而代表着一类类,实际上类模板的使用就是将类模板实例化成一个具体的类。格式为: 类名 < 实际的类型 > 对象名; 例:使用上面类模板创建两个模板参数为double 型的对象 complex<double>s1,s2;
46武汉职业技术学院计算机科学系 万 彪2004.11
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); // 存入数据函数• };
47武汉职业技术学院计算机科学系 万 彪2004.11
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• }
48武汉职业技术学院计算机科学系 万 彪2004.11
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() ,无值• }
49武汉职业技术学院计算机科学系 万 彪2004.11
3.9.4 类模板
类 模 板Store<T>
模 板 类Store<int>
模 板 类Store<Student>
模 板 类Store<double>
实例化 实例化
50武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类与对象
3.9.1 类3.9.2 对象3.9.3 构造函数与析构函数3.9.4 类模板3.9.5 友元3.9.6 类的继承与派生
51武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 友元——定义 友元的引出 类的封装性使得外部函数不能访问类中的私有成员,
使得两个类共享同一函数或数据带来额外的开销。为了寻求一种途径使得类以外的对象或函数能够访问类中的私有成员,就引入了友元的概念。
友元的作用 外部对象或函数访问类的私有数据或函数。 友元的副作用 使得数据的封装性受到削弱,导致程序可维护性变
差,因此一定要慎重使用。 为了确保数据的完整性及数据封装与隐藏的原则,建议尽量少用或不用友元。
52武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 友元——友元函数
友元函数 , 是指在该类中说明的某个函数不
是该类的成员函数,而是独立于任何类的一般的外界函数,它被允许访问该类的所有对象的私有成员。
定义时,在其函数名前加上关键字 friend.在类外实现函数体时,函数前没有类名和作用域运算符 ::
53武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 友元——友元函数例• #include<iostream.h>• class Point• {• private:• int x,y;• public:• Point(int ix,int iy)• {x=ix;y=iy;}• friend void show(Point &ob);// 声明友元函数• };• void show(Point &ob) // 友元函数的实现• {• cout<<"x="<<ob.x<<",y="<<ob.y<<endl;• }• main()• {• Point p(10,20);• show(p);• }
54武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 友元——友元成员
友元成员是指一个类的成员函数作为另一个类的友元。这个友元成员可以访问本类的私有成员和公有成员,以及 friend 友元声明所在类的私有成员和公有成员。 定义时,友元函数所在的类必须先于友元声明所在的类定义,在友元函数之前给出类名。
55武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 友元——友元类 当一个类作为另一个类的友元时,这个类称为友元类。这时它的所有成员函数都成为另一个类的友元函数。• #include<iostream.h>• class Point{• int x,y;• friend class Circle; // 声明友元类• public:• Point(int xx,int yy){• x=xx;• y=yy;• }• };
56武汉职业技术学院计算机科学系 万 彪2004.11
3.9.5 友元——友元类• class Circle{• Point center; // 圆心,对象作为类成员• int radius; // 坐标• public:• Circle(int a,int b,int r):center(a,b){• radius=r;• }• void print(){• cout<<"center:("<<center.x<<","• <<center.y<<"),radius="<<radius;• }• };• void main()• {• Circle c1(2,3,4);• c1.print();• }
57武汉职业技术学院计算机科学系 万 彪2004.11
3.9 类与对象
3.9.1 类3.9.2 对象3.9.3 构造函数与析构函数3.9.4 类模板3.9.5 友元3.9.6 类的继承与派生
58武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 类的继承与派生
保持已有类的特性而构造新类的过程称为继承。
在已有类的基础上新增自己的特性而产生新类的过程称为派生。
被继承的已有类称为基类(或父类)。派生出的新类称为派生类(或子类)。
59武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 类的继承与派生——派生类的声明
class 派生类名:继承方式 基类名 {
成员声明; };
60武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 类的继承与派生——访问控制
不同继承方式的影响主要体现在: 1 、派生类成员对基类成员的访问控制。 2 、派生类对象对基类成员的访问控制。三种继承方式
公有继承 私有继承 保护继承
61武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 类的继承与派生——公有继承
基类的 public 和 protected 成员的访问属性在派生类中保持不变,但基类的 private 成员不可访问。
派生类中的成员函数可以直接访问基类中的public 和 protected 成员,但不能访问基类的private 成员。
通过派生类的对象只能访问基类的 public 成员。
62武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 公有继承举例• class Point // 基类声明• {• public: // 公有成员函数• void InitP(float xx=0,float yy=0)• {X=xx;Y=yy;}• void Move(float xOff,float yOff)• {X+=xOff;Y+=yOff;}• float GetX(){return X;}• float GetY(){return Y;}• private:• float X,Y;• }
63武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 公有继承举例• class Rectangle:public Point // 派生类声明• {• public: //新增公有成员函数• void InitR(float x,float y,float w,float h)• {InitP(x,y);W=w;H=h;} //调用基类公有成员
函数• float GetH(){return H;}• float GetW(){return W;}• private: //新增私有数据成员• float W,H;• }
64武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 公有继承举例• int main()• {• Rectangle rect;• rect.InitR(2,3,20,10);• // 通过派生类对象访问基类公有成员• rect.Move(3,2);• cout<<rect.GetX()<<","<<rect.GetY()<<","• <<rect.GetW()<<","<<rect.GetH()<<endl;• return 0;• }
65武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 类的继承与派生——私有继承
基类的 public 和 protected 成员都以 private身份出现在派生类中,但基类的 private 成员不可访问。
派生类中的成员函数可以直接访问基类中的public 和 protected 成员,但不能访问基类的private 成员。
通过派生类的对象不能访问基类中的任何成员。
66武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 私有继承举例• class Rectangle:private Point // 派生类声明• {• public: //新增公有成员函数• void InitR(float x,float y,float w,float h)• {InitP(x,y);W=w;H=h;} //调用基类公有成员函数• void Move(float xOff,float yOff)• {Point::Move(xOff,yOff);}• float GetX(){return Point::GetX();}• float GetY(){return Point::GetY();}• float GetH(){return H;}• float GetW(){return W;}• private: //新增私有数据成员• float W,H;• };
67武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 私有继承举例• int main()• {• // 通过派生类对象只能访问本类成员• Rectangle rect;• rect.InitR(2,3,20,10);• rect.Move(3,2);• cout<<rect.GetX()<<","<<rect.GetY()<<","• <<rect.GetW()<<","<<rect.GetH()<<endl;• return 0;• }
68武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 类的继承与派生——保护继承
基类的 public 和 protected 成员都以 protected身份出现在派生类中,但基类的 private 成员不可访问。
派生类中的成员函数可以直接访问基类中的public 和 protected 成员,但不能访问基类的private 成员。
通过派生类的对象不能访问基类中任何成员。
69武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 protected 成员特点与作用
对建立其所在类对象的模块来说(水平访问),它与 private 成员的性质相同。
对于其派生类来说(垂直访问),它与 public 成员的性质相同。
即实现了数据隐藏,又方便继承,实现代码重用。
70武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 protected 成员举例• class A• {• protected:• int x;• };• int main()• {• A a;• a.x=5;
//错误• }
• class A• {protected:• int x;};• class B:public A{• public:• void Function();• };• void B:Function()• {x=5; //正确 }
71武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 类的继承与派生
基类与派生类的对应关系单继承 派生类只从一个基类派生。多继承 派生类从多个基类派生。多重派生 由一个基类派生出多个不同的派生类。多层派生 派生类又作为基类,继续派生新的类。
72武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 多继承时派生类的声明
class 派生类名:继承方式 1 基类名 1 ,继承方式 2 基类名 2 , ...
{
成员声明; ... ...
} ; 注意:每个“继承方式”,只用于限制对紧随
其后之基类的继承。
73武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 多继承举例• class A• {• public:• void setA(int);• void showA();• private:• int a;• };• class B• {• public:• void setB(int);• void showB(int);• private:• int b;• };
• class C:public A,private B
• {
• public:
• void setC(int,int,int);
• void showC();
• private:
• int c;
• };
• void A::setA(int x)
• {a=x;}
• void B::setB(int x)
• {b=x;}
74武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 多继承举例• void C::setC(int x,int y,int z)• {// 派生类成员直接访问基类的公有成员• setA(x);• setB(x);• c=z;• }• int main()• {• C obj;• obj.setA(5);• obj.showA();• obj.setC(6,7,9);• obj.setB(6); //错误• obj.showB(); //错误• return 0;• }
75武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造、析构函数
继承时的构造函数基类的构造函数不被继承,需要在派生类中自行声明。
声明构造函数时,只需对本类中的新增成员进行初始化,对继承来的基类成员的初始化由基类完成。
76武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造、析构函数
单一继承时的构造函数派生类名 :: 派生类名(基类所需的行参,本类
成员所需的行参) : 基类名(参数){
本类成员初始化赋值语句;}
77武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 单一继承时的构造函数举例• #include<iostream.h>• class B• {• public:• B();• B(int i);• ~B();• void print();• private:• int b;• };• B::B()• {• b=0;• cout<<"B's default constructor called."<<endl;• }
78武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 单一继承时的构造函数举例• B::B(int i)• {• b=i;• cout<<"B's constructor called."<<endl;• }• B::~B()• {• cout<<"B's destructor called."<<endl;• }• void B::print()• {• cout<<b<<endl;• }
79武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 单一继承时的构造函数举例• class C:public B• {• public:• C();• C(int i,int j);• ~C();• void print();• private:• int c;• };• C::C()• {• c=0;• cout<<"C's default constructor called."<<endl;• }
80武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 单一继承时的构造函数举例• C::C(int i,int j):B(i)• {• c=j;• cout<<"C's constructor called."<<endl;• }• C::~C()• {• cout<<"C's destructor called."<<endl;• }• void C::print()• {• B::print();• cout<<c<<endl;• }• int main()• {• C obj(5,6);• obj.print();• return 0;• }
输出结果:B's constructor called.C's constructor called.56C's destructor called.B's destructor called.
81武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造、析构函数
多继承时的构造函数派生类名 :: 派生类名 ( 基类 1 行参 , 基类 2 行
参 ,..., 基 类 n 行参 , 本类行参 ): 基类名 1( 参数 ), 基类
名 2( 参 数 ),..., 基类名 n( 参数 ), 对象数据成员的初始
化{
本类成员初始化赋值语句;}
82武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造、析构函数
派生类与基类的构造函数当基类中声明有缺省形式的构造函数或未声
明构造函数时,派生类构造函数的声明中可以省略对基类构造函数的调用。
若基类中未声明构造函数,派生类中也可以不声明,全采用缺省形式构造函数。
当基类声明有带行参的构造函数时,派生类也应声明带行参的构造函数,提供将参数传递给基类构造函数的途径。
83武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造、析构函数
派生类的构造函数的调用次序1. 调用基类构造函数,调用顺序按照它们被继
承时声明的顺序(从左向右)。2. 调用成员对象的构造函数,调用顺序按照它
们在类中声明的顺序。3. 派生类的构造函数体中的内容。
84武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造函数举例• #include<iostream.h>• class B1• {• public: // 基类 B1 ,构造函数有参数• B1(int i){cout<<"constructing B1,"<<i<<endl;}• };• class B2• {• public: // 基类 B2 ,构造函数有参数• B2(int j){cout<<"constructing B2,"<<j<<endl;}• };• class B3• {• public: // 基类 B3 ,构造函数没有参数• B3(){cout<<"constructing B3,*"<<endl;}• };
85武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造函数举例• class C:public B2,public B1,public B3• {• public: // 派生类的公有成员• C(int a,int b,int c,int d):• B1(a),memberB2(d),memberB1(c),B2(b){}• private: // 派生类的私有对象成员• B1 memberB1;• B2 memberB2;• B3 memberB3;• };• void main()• {• C obj(1,2,3,4);• }
86武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类的构造、析构函数
继承时的析构函数析构函数也不被继承,派生类自行声明。声明方法与一般(无继承关系时)类的析构
函数相同。不需要显示的调用基类的析构函数,系统会自动隐式调用。
析构函数的调用次序与构造函数相反。
87武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 继承时的析构函数举例• #include<iostream.h>• class B1• {• public: // 基类 B1 ,构造函数有参数• B1(int i){cout<<"constructing B1,"<<i<<endl;}• ~B1(){cout<<"destructing B1"<<endl;}• };• class B2• {• public: // 基类 B2 ,构造函数有参数• B2(int j){cout<<"constructing B2,"<<j<<endl;}• ~B2(){cout<<"destructing B2"<<endl;}• };• class B3• {• public: // 基类 B3 ,构造函数没有参数• B3(){cout<<"constructing B3,*"<<endl;}• ~B3(){cout<<"destructing B3"<<endl;}• };
88武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 继承时的析构函数举例• class C:public B2,public B1,public B3• {• public: // 派生类的公有成员• C(int a,int b,int c,int d):• B1(a),memberB2(d),memberB1(c),B2(b){}• private: // 派生类的私有对象成员• B1 memberB1;• B2 memberB2;• B3 memberB3;• };• void main()• {• C obj(1,2,3,4);• }
89武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 继承与派生——派生类成员的标识与访问
同名覆盖原则当派生类与基类中有相同成员时:若未强行指明,则通过派生类对象使用的是
派生类中的同名成员。如要通过派生类对象访问基类中被覆盖的同
名成员,应使用基类名限定。
90武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类成员的标识与访问举例• class B1 // 声明基类 B1• {• public:• int nV;• void fun(){cout<<"Member of B1"<<endl;}• };• class B2 // 声明基类 B2• {• public:• int nV;• void fun(){cout<<"Member of B2"<<endl;}• };• class D1:public B1,public B2• {• public:• int nV; // 同名数据成员• void fun(){cout<<"Member of D1"<<endl;}• // 同名成员函数• };
91武汉职业技术学院计算机科学系 万 彪2004.11
3.9.6 派生类成员的标识与访问举例• void main()• {• D1 d1;• d1.nV=1; // 对象名 . 成员名标识,访问 D1 类成员• d1.fun();
• d1.B1::nV=2; // 作用域分辨标识符,访问基类 B1 成员
• d1.B1::fun();
• d1.B2::nV=3;// 作用域分辨标识符,访问基类 B2 成员• d1.B2::fun();• }