第 7讲 类的定义及类成员的引用
教学目的与要求:
了解从结构体到类的概念 。
掌握类的定义格式,类成员引用方法 。
教学内容提要:
1,从结构体到类;
2,类的声明;
3,对象的声明;
4,对象赋值语句;
5,类的作用域;
教学重点:类的定义,类成员引用方法 。
教学难点:类的定义,类成员引用方法 。
教学进度,P49~ P61
教学过程:
类 是 C++语言面向对象程序设计的基础,在 C++语言面向对象程序设计中占据着核心地位。在面向对象的程序设计中,
C++程序就是由 类的实例 ——对象构成的 。
本章将详细介绍有关类及对象的基本知识,并开始采用面向对象程序设计方法进行 C++编程。
【 7.1 从结构体到 类 】
在 C语言中结构体中可以含有各种不同类型的数据。
在 C++中对结构体进行扩充,不仅可以含有不同类型的数据(数据成员),而且可以含有函数(成员函数)。
C++规定,在默认情况下,结构体中的成员都是公有的,
在任何函数中都可以访问。
例 7.1有关日期结构的例子。
#include <iostream.h>
struct Date {
int year;
int month;
int day;
void print( )
{ cout<<year<<"."<<month
<<"."<<day<<endl;
}
};
void main()
{ Date date1;
date1.year=2003;
date1.month=8;
date1.day=25;
date1.print( );
}
类也是一种用户自定义数据类型。它不仅包含不同数据类型的变量,还包含了对这些变量数据进行操作的函数。
类的声明形式如下:
class 类名
{
public:
若干成员;
protected:
若干成员;
private:
若干成员;
};
类 是一组变量及其相关函数的组合。类中的 变量 称为类的成员变量或数据成员; 函数 称为类的函数成员或方法。
成员函数 用于处理数据成员,从而描述类的行为,在类的声明内一般只声明其函数原型,在类外定义函数的实现。
指明了这里声明的是一个类类型。
是新建类的名称,它是一个标识符。
花括号内列出的是类的成员,
包括 数据成员和成员函数 。
【 7.2 类的声明 】
如果一个成员函数只供类中的其他成员函数调用,也应该 声明为私有的 。
在类的声明中,关键字 public,protected和 private的出现顺序是任意的,
可以不出现或多次出现。类中的每个成员 只能有一种特定的访问属性 。
声明,圆柱体”的类
class Cylinder
{
公有成员,用关键字 public声明,其中的成员一般是成员函数,用于定义类的外部接口,在程序中的任何部分都可以访问。
私有成员,可用关键字 private声明,其中成员一般是数据成员,用于描述类的属性,它们只能被类自身的成员函数访问。 类的成员在默认情况下都是私有的。
保护成员,用关键字 protected声明。它们只能 被类自身的成员函数访问或派生类的成员函数访问。
类成员按 访问权限控制 分类例 7.2
public,//公有成员,声明类的外部接口
void setcylinder(double r,double h); //成员函数,用来设置圆柱体的半径和高
double getradius(); //成员函数,用来获取圆柱体的半径
double getheight(); //成员函数,用来获取圆柱体的高
double volume(); //成员函数,用来计算圆柱体的体积
double surface_area(); //成员函数,用来计算圆柱体的表面积
private,//私有成员
double radius; //数据成员,声明圆柱体的半径
double height; //数据成员,声明圆柱体的高
};
把私有成员的声明放在了最前面,注意这里 省略 了关键字 private。注说明:把数据成员都声明为私有,并另外建立 getradius(),getheight()及
setcylinder()函数来访问这些私有数据成员。使得程序的其他部分对数据成员的访问只能通过公有成员函数来进行,因而数据成员类型改变所产生的影响被控制在类的内部,对程序的其他部分没有影响。
(续)
在声明类时把私有成员放在最前面
class Cylinder
{ //私有成员
double radius;
double height;
public,//公有成员
void setcylinder(double r,double h);
double getradius();
double getheight();
double volume();
double surfacearea();
};
在声明类时,一般来说应该把类的所有数据成员都声明为 私有的,同时 声明公有成员函数 来访问这些数据成员。
在类内不允许对声明的数据成员进行初始化。注例 7.3
对于成员函数,类的声明内一般 只声明 其函数原型,具体实现 要在 类外定义 。
不能在声明类时给数据成员赋初值
class Cylinder
{
public:
void setcylinder(double r,double h);
double getradius();
double getheight();
double volume();
double surfacearea();
private:
double radius( 5.0) ; //错误,不能在类中给数据成员赋初值
double height=10.0; //错误,不能在类中给数据成员赋初值
};
它的一般格式如下:
返回值类型 类名,:成员函数名(参数表)
{
函数体
}
“::”叫作用域运算符,它标明所要定义的函数属于哪个类。
例 7.4
“圆柱体”类成员函数的定义
void Cylinder::setcylinder(double r,double h)
{
radius=r;
height=h;
}
double Cylinder::getradius()
{
return radius;
}
double Cylinder::getheight()
{
return height;
}
double Cylinder:,volume()
{
double vol;
vol=3.1415926*radius*radius*height;
return vol;
}
例 7.5
double Cylinder::surfacearea()
{
double area;
area=2*3.1415926*radius*height+2*3.1415926*radius*radius;
return area;
}
在定义类的成员函数时,也可以对参数设置默认值。
在定义成员函数时可以为参数设默认值
void Cylinder::setcylinder(double r=0,double h=0)
{
radius=r;
height=h;
}
定义类的成员函数时,对一些只有一、二条语句的函数可以把函数定义成 内联函数 。
内联成员函数的定义 在类的声明中定义在类外定义例 7.6
在类外定义内联成员函数
inline double Cylinder::getradius()
{
return radius;
}
inline double Cylinder::getheight()
{
return height;
}
函数体的定义 放在类的声明内,定义的函数就 自动成为 内联成员函数。
例 7.8 在类的声明内直接定义成员函数
class Cylinder
{
public:
void setcylinder(double r,double h);
double getradius()
{
return radius;
}
说明:在类外定义一个类的内联成员函数,应该在 函数类型之前 用关键字 inline进行说明。
例 7.7
定义类的成员函数时,对一些只有一、二条语句的函数可以把函数定义成 内联函数 。
在实际的 C++程序设计中,把类的声明和类外实现的成员函数放在不同的文件中。其中 类的声明 放在一个称为 头文件 的文件中,
成员函数的定义 放在另一个称为 源文件 的文件中。
注头文件与源文件的 名字一般相同 。
头文件的扩展名为,H(或,HPP) ;源文件的扩展名为,CPP。
说明:在类的声明内定义函数时,必须注意的是在表示函数结束的花括号后,不能加分号 。
例 7.9
double getheight()
{
return height;
}
double volume();
double surface_area();
private:
double radius;
double height;
};
在类的声明内直接定义成员函数这其实和一般变量的声明方式是一样的。
类 是数据和其相关操作函数的封装体,是对对象的抽象及其共性的描述,
对象是 类的实例。类被当作一个 自定义的数据类型,一个类的对象可以看成是 该类型的一个变量 。
对象也必须经过声明后才能使用。在声明了相应的类后,声明这个类的对象。
方式如下,类名 对象名;
例如:
Cylinder cylinder1,cylinder2;
可以声明对象数组。
例如:
Cylinder cylinder1[ 10] ;
声明了两个名字分别为 cylinder1、
cylinder2的类 Cylinder的对象。
声明了一个数组 cylinder1,其中共有 10
个元素,每个元素都是一个对象。
【 7.3 对象的声明 】
可以使用成员选择运算符,,”来访问对象中的公有成员。
其一般形式如下,对象名,数据成员名 //访问数据成员对象名,成员函数据名(参数表) //访问成员函数只有在声明这个类的对象时,才实际分配相应的内存。编译器在声明一个对象时只是为对象的数据成员分配内存,并不需要为成员函数分配存储空间。由于对同一类的对象,成员函数的代码是相同的,故系统一次性地为之分配内存。
例如,cylinder1.volume()
例如,Cylinder cylinder1;
cylinder1.radius=6.0;
cylinder1.height=5.0;
在类外使用下面的方法是错误的。
私有成员 只能 被类内的成员函数访问。
例如:
cylinder1.setcylinder(6.0,5.0);
一个 C++面向对象程序设计的例子
//求圆柱体的体积及表面积
//EXAMPLE3_9.H
#include<iostream.h>
class Cylinder //声明圆柱体类
{
public:
void setcylinder(double r=5.0,double h=10.0);
double getradius()
{
return radius;
}
double getheight()
{
return height;
}
double volume(); //声明求体积函数的原型
double surface_area(); //声明求表面积函数的原型 private:
double radius; //底圆半径
double height; //圆柱体高
};
第 1部分例 7.10
//EXAMPLE3_9.CPP
// #include″EXAMPLE3_9.h″
const double PI=3.1415926;
void Cylinder::setcylinder(double r,double h) //定义函数设置半径和高
{
radius=r;
height=h;
}
double Cylinder:,volume() //定义函数求体积
{
double vol;
vol=PI*radius*radius*height;
return vol;
}
double Cylinder::surface_area() //定义函数求表面积
{
double area;
area=2*PI*radius*height+2*PI*radius*radius;
return area;
}
第 2部分
(续)
void main()
{
Cylinder cylinder1,cylinder2; //声明圆柱体对象
cylinder1.setcylinder(); //给对象 cylinder1半径和高赋值
cylinder2.setcylinder(10.2,15.6); //给对象 cylinder2半径和高赋值
cout<< ″ The radius of the first cylinder is:\ t ″<<cylinder1.getradius()<<endl;
//输出对象 cylinder1的半径
cout<< ″The height of the first cylinder is:\ t ″<<cylinder1.getheight()<<endl;
//输出对象 cylinder1的高
cout<< ″The volume of the first cylinder is:\ t ″<<cylinder1.volume()<<endl;
//计算对象 cylinder1的体积,并输出
cout<< ″The surface area of the first cylinder is:\ t ″
<<cylinder1.surface_area()<<endl; //计算对象 cylinder1的表面积,并输出
cout<< ″The radius of the second cylinder is:\ t ″<<cylinder2.getradius()<<endl;
//输出对象 cylinder2的半径
cout<< ″The height of the second cylinder is:\ t ″<<cylinder2.getheight()<<endl;
//输出对象 cylinder2的高
cout<< ″The volume of the second cylinder is:\ t ″<<cylinder2.volume()<<endl;
//计算对象 cylinder1的体积,并输出第 3部分
(续)
cout<< ″The surface area of the second cylinder is:\ t ″
<<cylinder2.surface_area()<<endl; //计算对象 cylinder1的表面积,并输出
}
The radius of the first cylinder is,5
The height of the first cylinder is,10
The volume of the first cylinder is,785.398
The surface area of the first cylinder is,471.239
The radius of the second cylinder is,10.2
The height of the second cylinder is,15.5
The volume of the second cylinder is,5098.88
The surface area of the second cylinder is,1653.48
说明:程序由 3个相对独立的部分组成。
第 1部分是类 Cylinder的声明,存储在 EXAMPLE3_9.H文件中;
第 2部分是类 Cylinder的成员函数的实现,存储在
EXAMPLE3_9.CPP文件中;
第 3部分是主函数 main()。
(续)
作为数据成员的对象所属的类,应该在声明这个对象之前进行声明。注可以为类作 引用性声明 。这种声明 只声明类名,即只为程序引入了一个类标识符,而标识符的 实际意义 在其他部分定义。这种引用性声明引入的标识符,在其 实际意义未定义前 只能被用于声明函数原型等场合。
类的数据成员可以是类类型,也就是说类的声明中数据成员可以是另一个类的对象。 这个对象不能是本类的对象。
正确的如,class A
{
...
};
class B
{
...
A a;
...
};
∵ 对于程序中声明的每一个对象,编译器都要为之确定存储的布局。但引用性声明中并未说明对象的数据结构,以及对数据的相关操作。
∴ 编译器不仅不能为对象分配内存空间,也无法对对象能参与的操作进行类型检查。
只经过引用性声明的类标识符,不能用于建立对象。
如,class B;
class A
{
public:
void fun(B b);
...
};
class B
{
...
};
class B; //引用性声明
class A
{
public:
void fun(B b); //正确
private:
B b; //错误,类 B尚未定义
};
void A::fun(B b)
{
cout<<b.getx(); //错误
}
class B //声明类 B,也即定义类 B
{
public:
void setx(int a){x=a;}
int getx() {return x;}
private:
int x;
};
例如,下面的使用方法就是错误的。
例 7,11 用对象赋值语句的例子 。
#include<iostream.h>
class abc{
public:
void init(int i,int j) { a=i; b=j; }
void show(){ cout<<a<<" "<<b<<endl; }
private:
int a,b;
};
main()
{ abc o1,o2;
o1.init(12,34);
o2=o1; // 将对象 o1数据成员的值赋给对象 o2
o1.show();
o2.show();
return 0;
}
【 7.4 对象赋值语句 】
所谓类的作用域就是指在类声明中的一对花括号所形成的作用域 。
一个类的所有成员都在该类的作用域内,一个类的任何成员可以访问该类的其他成员 。
而在类的外部,对该类的数据成员和成员函数的访问则要受到一定的限制,有时甚至是不允许的,这体现了类的封装功能。
【 7.5 类的作用域 】
例 7.12 理解类的作用域 。
# include<iostream.h>
class myclass{
public:
int i;
void init(int);
void show(){ cout<<,i=” <<i<<endl;} // 可以访问类中的数据成员 i
};
void myclass::init(int si){ i=si;} // 可以访问类中的数据成员 i
int fun(){ return i; } // 非法,不能直接访问类中的 i
void main()
{ myclass ob;
ob.init(5); // 给数据成员 i赋初值 5
ob.show();
i=8; // 非法,不能直接访问类中的 i,可改写成 ob.i=8
ob.show();
}
1、下面程序段是否存在错误:
( 1) class point
{ public:
void setp(int a,int b) { x=a;y=b;}
void print(){cout<<x<<?,?<<y<<endl;}
protected:
int x=0,y=0;
};
课堂练习:
1( 2) class A
{
private,int a1,a2;
public,
void init(int x,int y){ a1=x; a2=y;}
void print()
{ cout<<”a1=”<<a1
<<”a2=”<<a2<<endl; }
};
void main()
{
A obj;
obj.init(3,9);
cout<<obj.a1<<obj.a2<<endl;
obj.print();
}
#include <iostream.h>
class MyClass
{
//在下面写出类的定义体
};
float MyClass::Getm()
{
return member;
}
void MyClass::Setm(float m)
{
member=m;
}
void main()
{
MyClass obj;
obj.Setm(7.8);
cout<<obj.Getm()<<endl;
}
float member;
public:
float Getm();
viod Setm(float m);
2、程序填空编写程序:定义一个满足下列要求的 Date类:
( 1)用日 /月 /年的格式输出日期;
( 2)可运行在日期上加一天操作;
( 3)设置日期操作
class Date
{
int day,month,year;
public:
void print( )
{ cout<<day<<?/?<<month<<?/?<<year; }
int addday( )
{ return day+1; }
void setdate(int d,int m,int y)
{ day=d; month=m; year=y }
};
class Date
{ int day,month,year;
public:
void print( )
{ cout<<day<<?/?<<month<<?/?<<year; }
int addday( )
{ return day+1; }
void setdate(int d,int m,int y);
};
void Date:,setdate(int d,int m,int y)
{ day=d; month=m; year=y }
小结:
1、类的定义格式,及定义方法
2、类对象的定义;
3、类成员的引用方法。
作业:
P108-110
3.18,3.19,3.21,3.22