对象与类Word下载.docx
《对象与类Word下载.docx》由会员分享,可在线阅读,更多相关《对象与类Word下载.docx(13页珍藏版)》请在冰豆网上搜索。
类可以定义为具有类似特征和行为的对象的集合,如人类共同具有的区别于其他动物的特征有直立行走、使用工具、使用语言交流等。
所有的事物都可以归到某类中。
例如,家用电器是一类电子产品。
属于某个类的某一个具体的对象称为该类的一个实例(instance)。
例如,我的汽车是汽车类的一个实例。
实例与对象是同一个概念。
类与实例的关系是抽象与具体的关系。
类是多个实例的综合抽象,实例是某个类的个体实物。
面向对象编程的基本特征
1.封装性
封装(encapsulation)就是把对象的状态(属性)和行为(方法)结合成一个独立的系统单位,并尽可能地隐藏对象的内部细节。
例如,一辆汽车就是一个封装体,它封装了汽车的状态和操作。
封装使一个对象形成两个部分:
接口部分和实现部分。
对于用户来说,接口部分是可见的,而实现部分是不可见的。
封装提供了两种保护。
首先封装可以保护对象,防止用户直接存取对象的内部细节;
其次封装也保护了客户端,防止对象实现部分的改变可能产生的副作用,即实现部分的改变不会影响到客户端的改变。
2.继承性
继承(inheritance)的概念普遍存在于现实世界中。
它实际上是一种概念的分类或特殊化。
比如,我们说交通工具,它是一个一般的概念。
交通工具又可分为陆上交通工具、水上交通工具和空中交通工具。
这三种交通工具都是一种(isa)交通工具,都具有交通工具的特征。
如果将交通工具作为一个类,那么,陆上交通工具就是交通工具的子类(subclass),并且陆上交通工具具有交通工具的所有特征,我们说陆上交通工具继承了交通工具的所有特征。
除此之外,陆上交通工具又具有自己的特征。
继承性体现了类之间的一种关系。
类之间的关系还有组合(has-a)等。
3.多态性
多态性(polymorphism)是面向对象编程语言的一个重要特性。
所谓多态,是指一个程序中相同的名字表示不同含义的情况。
面向对象的程序中的多态有多种情况。
在简单的情况下,在同一个类中定义了多个名称相同的方法,即方法重载(overloading),另一种情况是子类中定义的与父类中的方法同名的方法,即方法覆盖(overriding)。
这两种情况都称为多态,且前者称为静态多态,后者称为动态多态。
C++的类和对象
类主要由3部分组成,分别是:
类名、数据成员(datamember,也称为属性)、成员函数(memberfunction,也称为服务)。
在设计类时,首先要确定“类”的数据成员(属性),然后再围绕数据成员确定与其有关的成员函数(操作),不要设置与系统无关的数据成员与成员函数。
设计过程中不要期望第一次就能正确地设计出有关的类,要不断地对实际问题进行分析、整理和抽象,以便得出较好的结果。
类定义的一般形式为:
class类名
{
private:
//私有成员数据和私有成员函数(方法)
protected:
//保护成员数据和保护成员函数(方法)
public:
//公有成员数据和保护成员函数(方法)
};
例如声明一个虫子类
classCWorm
intm_x,m_y;
//保护成员变量,存储当前屏幕坐标
HBITMAPm_hBmp;
//保护成员变量,存储虫子的图片
intm_iDistance;
//保护成员变量,保存虫子跑过的距离
voidCumDistance();
//保护成员函数,累加虫子跑过的距离
CWorm();
//构造函数,在实例化小虫子时调用
CWorm(intx,inty);
//构造函数,在实例化小虫子时调用
voidDraw(CDC*pDC);
//调用m_hBmp成员变量,把自己画出来
voidMove(intx,inty);
//请虫子爬行
~CWorm();
//析构函数,在虫子牺牲时调用
然后实例化一条小虫子
CWormworm(20,30);
//设置好小虫子的初始屏幕坐标,并在构造函数里Load自己的图片
worm.Draw(&
dc);
//在屏幕上把自己画出来
worm.Move(100,100);
//移动小虫子到100,100
//在当前坐标再一次画小虫子
或者
CWorm*pWorm=newCWorm(20,30);
pWorm->
Draw(&
Move(100,100);
Dram(&
delete[]pWorm;
//杀死小虫子
●类的成员函数可以访问同类型类的其它对象的任何成员。
例如
#include"
stdafx.h"
#include<
iostream>
usingnamespacestd;
classCTest2
voidPrivateFunc()
{
cout<
<
"
CallPrivatefunction"
endl;
}
voidPublicFunc(void*pvObj)
CTest2*pTest=(CTest2*)pvObj;
pTest->
PrivateFunc();
voidmain()
CTest2test1,test2;
test1.PublicFunc(&
test2);
}
●成员函数的定义既可以在类声明内,也可以分开定义,通常将类声明放.h文件,类函数定义放.cpp文件中。
内联的方式:
//...
inlinevoidMove(intx,inty)
//.....
CumDistance(x,y);
//
分离的方式:
voidCWorm:
:
Move(intx,inty)
//......
CumDistance(x,y);
练习:
1、创建文件student.h,并在文件中声明类
classCStudent
private:
intm_iId;
charm_szName[32];
public:
//将学生ID和姓名赋值给成员变量
voidSetInfo(intiId,char*pszName);
//打印出成员变量
voidDisplay();
创建文件student.cpp,并在文件中定义SetInfo和Display成员函数的实现。
最后在main.cpp中使用该类
CStudentstud,*pStud;
stud.SetInfo(3,”O’Nil”);
stud.Display();
pStud=newCStudent;
pStud->
SetInfo(0,”Bill”);
(*pStud).Display();
Display();
deletepStud;
2、定义一个类,类中分别有private、protected、public类型的成员数据和成员函数,并在成员函数内部和类的外部测试各种成员数据和成员函数的可访问性。
●对象的成员数据和成员函数的存储。
对象的成员数据分开存放,但是同一个类的所有对象共享成员函数代码区。
成员函数通过this指针区别不同对象的成员数据。
类和结构体的异同
结构体的成员缺省是public的,类的成员缺省是private的
●this指针
在每一个成员函数中都包含一个指向对象的首地址的指针,称为this指针,既指向对象本身的指针。
对象的初始化与清除、对象赋值
构造函数
构造函数是类的一种特殊成员函数,它在类实例化对象时自动执行,构造函数的名字必须与类名同名,它不具有任何类型,不返回任何值,即使是void也不允许。
classCTest
intm_i1;
intm_i2;
voidPrint()
printf("
m_i1:
%dm_i2:
%d\n"
m_i1,m_i2);
/*
缺省构造函数,如果定义类时未指定任何构造函数,
系统将自动生成不带参数的缺省构造函数
*/
CTest()
m_i1=0;
m_i2=0;
}
带一个参数的可用于类型转换的构造函数
CTest(inti1)
m_i1=i1;
带参数的构造函数
CTest(inti1,inti2)
m_i2=i2;
拷贝构造函数,如果此函数不定义,系统将生成缺省拷贝构造函数功能,
缺省拷贝构造函数的行为是:
用传入的对象参数的成员初始化正要建立的对象的相应成员
CTest(constCTest&
oTest)
m_i1=oTest.m_i1;
m_i2=oTest.m_i2+2;
//区别于缺省拷贝构造函数的行为
析构函数,一个类中只能有一个析构函数,如果用户没有定义析构函数,
系统会自动未类生成一个缺省的析构函数
~CTest()
intmain(intargc,char*argv[])
CTesttest1;
//调用缺省构造函数
CTesttest2();
//这是函数的声明,不是实例化类
CTesttest3
(1);
//调用带一个参数的构造函数
CTesttest4(1,2);
//调用带多个参数的构造函数
CTesttest5=5;
//等价于CTesttest5(5);
CTesttest6=CTest(6);
//等价于CTesttest6(6);
test1=5;
//生成临时对象CTest(5),并把该对象的成员赋值给对象test1
test1=CTest(7,77);
//生成临时对象CTest(6,66),并把该对象的成员赋值给对象test1
CTesttest8(test1);
//调用拷贝构造函数
CTesttest9=test1;
//等价于CTesttest9(test1)
test1=test9;
//对象间的赋值,缺省行为是将test9的成员值诸葛赋值给test1的成员
return0;
练习,写程序测试上例中每条语句对象生成的个数.
初始化成员列表(参数初始化表)
通常在类的构造函数中初始化类的成员数据,除此外还可以通过初始化成员列表的方式初始化数据成员。
初始化成员列表的形式为:
构造函数名(构造函数参数列表):
成员1(参数列表1),成员2(参数列表2),,,成员n(参数表n)
classCTest1
intm_iRef;
CTest1(intiRef)
m_iRef=iRef;
constintm_iConst;
CTest1m_obj;
CTest2();
CTest2:
CTest2():
m_i1
(1),m_iConst(4),m_obj(0)
m_i2=2;
下列两种情况的数据成员的初始化只能使用初始化成员列表:
1、类的成员是常量成员,对常量成员赋初始值只能在初始化成员列表中。
2、类的成员是对象成员,对象成员必须用带参数的构造函数初始化。
则该对象成员的初始化必须在初始化成员列表中。
1、写程序,测试在初始化成员列表各个成员初始化的顺序。
2、写程序,测试初始化成员列表与构造函数体中赋值两者的先后顺序
析构函数
对象的生命期结束时,会自动调用析构函数。
析构函数名是在类名前加”~”,析构函数同样不能返回任何值,也没有函数参数,并且不能被重载,所以一个类可以有多个构造函数,却只能有一个析构函数。
一般说来,每当创建一个对象时就调用对象的构造函数;
每当撤消一个对象就调用该对象的析构函数。
具体有以下4种情况:
●对于全局定义的对象,每当程序开始运行,在主函数main(或WinMain)接受程序控制权之前,就调用全局对象的构造函数。
整个程序结束时调用析构函数。
●对于局部定义的对象,每当程序流程到达该对象的定义处就调用构造函数,在程序离开局部变量的作用域时调用对象的析构函数。
●对于关键字static定义的局部变量,当程序流程第一次到达该对象定义处调用构造函数,在整个程序结束时调用析构函数。
●对于用new运算符创建的对象,每当创建该对象时调用构造函数,当用delete删除该对象时,调用析构函数。
对象与常量
●常对象。
常对象指在任何场合都不能对其成员的值进行修改的对象。
定义常对象的形式为:
const类名对象名(参数列表);
类名const对象名(参数列表);
●常数据成员。
将对象成员声明为const,则为常对象成员。
常对象成员只能在构造函数的初始化成员列表中对其进行初始化。
classCA
constintm_iConst;
●常成员函数。
常成员函数不能修改类中的成员数据。
常成员函数的声明形式为:
返回类型函数名()const。
voidPrint()const;
voidCA:
Print()const
cout<
CallCA:
Print()"
作业:
1、给出下面的类的定义,请写出成员函数set的适合实现。
classTemperature
public:
//将成员变量的值设置为参数给出的值。
voidset(doublenewDegrees,charnewScale);
doubledegrees;
charscale;
//'
F'
代表华氏温度,'
C'
代表摄氏温度
2、定义一个名为CounterType的类。
此类的对象用于计数,可以记录所有的非负整数。
此类包含一个赋值函数来为计数赋值,还包含将计数每次增1或者减1的成员函数。
所有的成员函数都不允许将计数变成负数。
当然,类还包含返回当前计数值的成员函数以及输出函数。
将定义好的类放在程序中进行测试。
3、定义基于汽车加油站中油泵模型的名为GasPump的类。
在作此练习之前,请先从买方的角度出发,写下你所期望的油泵的行为。
下面列出了一些可能的行为,如果你所列出的行为和下面的不同就自行比较一下然后将最后决定的行为在GasPump中实现。
A、显示加油总量。
B、显示总加油量所应付的总费用。
C、显示每单位油量的费用,单位可以是加仑、升或者其他任何你所在地方通常所使用的容量单位。
D、在下次加油前,油泵应该将加油总量和总费用清零。
E、一旦开始加油,随着油量持续的输出,加油总量和总费用应该随之同时变化,直到加油停止。
F、在某些情况下,还需要控制停止加油。
将上面的行为声明为GasPump类的成员函数,并编写这些成员函数的具体实现代码,同时决定该类的数据成员是否可以被此类的使用者访问。
将那些不能被访问的数据成员设置为私有。
4、
5、
6、
7、
8、