VC内部培训资料第2章 掌握c++.docx

上传人:b****2 文档编号:22998663 上传时间:2023-04-30 格式:DOCX 页数:23 大小:28.20KB
下载 相关 举报
VC内部培训资料第2章 掌握c++.docx_第1页
第1页 / 共23页
VC内部培训资料第2章 掌握c++.docx_第2页
第2页 / 共23页
VC内部培训资料第2章 掌握c++.docx_第3页
第3页 / 共23页
VC内部培训资料第2章 掌握c++.docx_第4页
第4页 / 共23页
VC内部培训资料第2章 掌握c++.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

VC内部培训资料第2章 掌握c++.docx

《VC内部培训资料第2章 掌握c++.docx》由会员分享,可在线阅读,更多相关《VC内部培训资料第2章 掌握c++.docx(23页珍藏版)》请在冰豆网上搜索。

VC内部培训资料第2章 掌握c++.docx

VC内部培训资料第内部培训资料第2章章掌握掌握c+第1章掌握C+在学习VisualC+6.0编程之前,有必要复习一下C+中面向对象的一些基本概念。

我们知道C+比C有许多优点,主要体现在封装性(Encapsulation)、继承性(Inheritance)和多态性(Polymorphism)。

封装把数据与操作数据的函数衔接在一起,不仅使程序结构更加紧凑,并且提高了类内部数据的安全性;继承性增加了软件的可扩充性及代码重用性;多态性使设计人员在设计程序时可以对问题进行更好的抽象,利于代码的维护和可重用。

VisualC+不仅仅是一个编译器,更是一个全面的应用程序开发环境,使用它你充分利用具有面向对象特性的C+来开发出专业级的Windows应用程序。

因此,熟练掌握本章内容,以便为后继章节打下良好的基础。

1.1类的定义与应用在C语言中,我们学过结构体,用于将描述某一对象的若干变量包装成一个整体使用,就像是一个集合,在这个集合里的变量,可以是相同、部分相同,或完全不同的数据类型。

但该集合中没有将与该对象相关的函数包含进来。

C语言中的结构体只能描述一个对象的特征(属性),不能描述一个对象的动作(方法)。

在C+中,我们是通过类的定义来解决这个问题的,在类的定义中,不仅可以包含变量,还可以包含函数。

1.1.1结构的定义定义结构(struct)的语法如下:

struct结构数据类型名称成员数据类型成员名称;注意定义结尾的分号。

在C+中分号代表一段程序的结尾,因此,在类和结构定义完后,在大括号后面一定要用;号结尾,忘记;是许多人常犯的错误。

下面就是一个简单结构的定义,用来描述一个学生的共同属性:

structstudentintnumber;charname10;intage;;定义了该结构,我们就多了一个“student”数据类型,这时候就可以象使用C语言中的其他标准数据类型那样来声明一个结构变量。

例如:

structstudentstu;这样我们就定义了一个名为stu的student结构类型的变量。

1.1.2类的定义与应用1.1.2.1类与结构下面让我们来看一个简单的类(class)的定义:

classstudentpublic:

intnumber;charname10;intage;看起来是不是和结构的定义很类似?

在C+语言中,类和结构的定义除了使用关键字“class”和“struct”不同之外,更重要的是在成员的访问控制方面有所差异。

另外,类兼具有封装、继承、数据隐藏等特性。

1.1.2.2类的使用下面,我们将通过清单1-00中的代码来讲解类的使用。

完整的例程请参见光盘中的例子代码EX01-00。

清单1-00类的使用1#includeiostream.h2classCPoint34public:

5intx1;6inty1;7voidOutput();8CPoint();9CPoint(intx2,inty2);10CPoint();11private:

12intx2;13inty2;14int*pCount;15;16voidCPoint:

Output()1718if(pCount)19(*pCount)+;20else2122pCount=newint;23*pCount=1;2425coutthefirstpointis(x1,y1)endl;26coutthesecondpointis(x2,y2)endl;2728CPoint:

CPoint()2930pCount=0;31coutthefirstconstructoriscallingx2=x2;36this-y2=y2;37pCount=0;38coutthesecondconstructoriscallingendl;3940CPoint:

CPoint()4142if(pCount)4344cout你调用了Output成员函数共*pCount次endl;45deletepCount;4647else48cout你还没有调用过Output成员函数endl;49coutthedeconstructoriscallingendl;5051voidOutput(CPointpt)5253coutthefirstpointis(pt.x1,pt.y1)endl;54/coutthesecondpointis(pt.x2,pt.y2)endl;55/上面被注释的语句会造成编译错误,因为不能从类的外部访问类中的私有成员。

5657voidmain()5859if(1=1)/限定pt变量的有效范围6061CPointpt;62coutpt.x1pt.y1;64/pt.x2=10;65/pt.y2=10;66/上面被注释的语句会造成编译错误,因为不能从类的外部访问类中的私有成员。

67pt.Output();68pt.Output();69pt.Output();/故意演示Output被调用多次的情况。

70Output(pt);7172CPointpt(10,10);73pt.Output();74注意,在c+中,/.用于注释一行,/*.*/可以注释多行。

215行代码定义了一个类CPoint,其中包含有变量,称之为成员变量,也包含有函数的声明,称之为成员函数。

在类定义之外,我们必须对成员函数进行实现,成员函数的实现格式为:

返回类型类名:

函数名(参数列表)函数体代码5156行代码编写了一个名为Output的全局函数,注意与1627行代码编写的类CPoint中的Output成员函数区别。

5774行代码还编写了一个main主函数,代码中演示了如何使用CPoint类。

C+中提供了一套输入输出流方法的对象,它们是cin、cout和cerr,对应c语言中的三个文件指针stdin、stdout、stderr,分别指向终端输入、终端输出和标准出错输出(也从终端输出)。

cin与一起完成输入操作,cout、cerr与一起完成输出与标准错误输出。

例如程序main函数中第63行代码使用cin为pt.x1,pt.y1输入两个整数,Output函数中第53行使用cout连续输出字符串、整数、字符、换行。

在输出中使用endl(endofline)表示换行,相当于n。

利用cin和cout比scanf和printf要方便得多,cin和cout可以自动判别输入输出数据类型而自动调整输入输出格式,不必像scanf和printf那样一个个由用户指定。

使用cin,cout不仅方便,而且减少了出错的可能性。

从1627行类CPoint的Output成员函数的实现中,我们可以看到类中的成员函数可以直接访问同类中的成员变量,如:

x1,y1,x2,y2。

说明:

如果成员函数中的局部变量与成员变量同名,则在局部变量的作用范围内,成员变量不起作用。

如果有全局变量与成员变量同名,则在成员变量的作用范围内(所有同类成员函数中),全局变量不起作用。

main函数中5971行的if(1=1)语句部分,主要是为了说明局部变量的有效范围。

局部变量的有效范围位于定义它的复合语句之中,一对中所定义的语句即一个复合语句。

也就是说,局部变量的有效范围并不是在定义它的函数体当中,而是在外层最靠近它定义的那对中,main()函数中第61行定义的第一个CPoint对象pt在if语句的处被系统释放。

在类中使用的private和public访问修饰符,它们限定成员被访问的范围。

从一个修饰符的定义处,直到下一个修饰符定义之间的所有成员都属于第一个修饰符所定义的访问类型。

以public定义的成员,能够被同类中的成员函数及类定义之外的所有其他函数访问,如CPoint类中的x1,y1,Output等成员变量与函数。

但要注意的是,在类之外的函数中访问类成员,必须是下列语法格式:

对象.成员变量;以private定义的成员,只能被同类中的成员函数访问,不能在其他函数中访问(即使是对象.成员的格式),如类CPoint中的成员变量x2,y2能被成员函数Output访问,但不能在main函数及全局Output函数中访问。

说明:

如果在类定义中的开始处没有使用任何修饰符,则在类定义的开始处使用private作为其默认修饰符。

在C+中定义struct结构体也可以包含成员函数,除了开始处使用的默认修饰符为public外,其余之处与class类基本相同。

1.2函数的重载在C语言中,如果同一程序中有两个函数名一样,不管其参数类型或个数是否一样时,编译就会出错。

例如,程序中有两个名为Add的函数定义:

intAdd(intx,inty);intAdd(intx,inty,intz);在C语言中编译时,将提示函数名重复错误,而在C+中上述定义是合法的,这就是C+新增的函数重载(Overload)的概念。

C+能够根据函数调用时所传递的参数个数及数据类型的不同而选择适当的函数。

1.2.1重载参数个数不同的函数例如,下面的清单1-01中的程序拥有两个函数名相同,但参数个数不同的函数,让我们看看他们在C+编译器中运行的结果是怎样的。

完整例程请参见光盘中例子代码EX01-01。

清单1-01函数重载(参数个数不同)1#include2voidadd(intx,inty)34coutfunctionhavetwoparameters:

endl;5coutthesumis:

x+yendl;67voidadd(intx,inty,intz)89coutfunctionhavethreeparameters:

endl;10coutthesumis:

x+y+zendl;1112voidmain()1314add(1,2);15add(1,2,3);1626行代码定义了一个带有两个参数的add函数,711行代码定义了带有三个参数的add函数,执行清单1-01的程序会发现,不仅不报错而且分别打印出3和6两个结果。

可见,C+编译器可以根据参数个数的不同来选择执行相应的函数。

1.2.2重载参数数据类型不同的函数请看清单1-02的程序拥有两个函数名相同、参数个数相同,但参数数据类型不同的函数,让我们看看他们在C+编译器中运行的结果是怎样的。

完整例程请参见光盘中例子代码EX01-02。

清单1-02函数重载(参数类型不同)1#include2voidoutput(intx)34coutthisisanumber:

;5coutxendl;67voidoutput(char*c)89coutthisisastring:

c成员的方式访问其它的成员,如CPoint(intx2,inty2)函数中用this-x2访问成员变量x2。

在成员函数中,我们通常可以省略this-,直接访问类中的成员变量。

在CPoint(intx2,inty2)函数中,由于函数参数变量x2,y2与成员CPoint中的成员变量x2,y2同名,要在该函数中访问成员变量x2,y2,可用this-x2,this-y2与参数变量x2,y2区分。

小技巧:

在以后的MFC编程中,如果在成员函数中想调用同类中的某个成员,可以使用VC+提供的自动列出成员函数功能,使用this-,VC+将列出该类中的所有成员,我们可以从列表中选择我们想调用的成员。

自动列出成员函数功能,可以提高编写速度,减少拼写错误。

特别是我们不能完全记住某个函数的完整拼写,但却能够从列表中辨别出该函数时,自动列出成员函数功能更是有用。

事实上,在各种IDE编程环境中,我们通常都没有完全记住某些函数的完整拼写,只是记住其大概写法和功能,要调用该函数时都是从自动列出成员函数中选取的。

这样能够大大节省我们的学习时间,我们没有花大量的时间去死记硬背许多函数,利用自动列出成员函数功能和帮助系统,却也能够在编程时顺利使用这些函数,等用的次数多了,也就在不知不觉中完全掌握了这些函数。

注意比较Output全局函数与Output成员函数的差别。

对Output全局函数的调用,可以理解成“输出某个pt点的坐标”,是一种谓宾关系,是面向过程(或函数)Output的。

对Output成员函数的调用,可以理解成“pt这个点对象执行输出动作”,是面向对象pt的。

希望通过这样的比较,能够有助于读者理解c+中关于面向对象的概念。

1.5类的继承与protected访问修饰符类是可以继承(Inherit)的,就是基于现有的类再创建新类。

这里假定类B继承了类A,那么,我们称A为基类(BaseClass,也叫父类),B为派生类(DerivedClass,也叫子类)。

派生类不但拥有自己新的成员变量和成员函数,还可以拥有基类的成员变量和成员函数。

一个派生类可以只继承一个类,也可以继承多个类,我们称这种情况为多重继承。

1.5.1单一继承在“单一继承”这种最普通的形式中,派生类仅有一个基类,定义方法是:

class派生类名:

访问权限基类名称.;要实现类B与类A的继承关系,我们在定义类B之前必须已定义了类A,并用如下的格式定义类B。

classB:

public或privateA.;讲到类的继承后,我们再讲解另一种成员访问权限修饰符,protected。

public,protected,private三种访问权限的比较:

public定义的成员可以被在任何地方访问。

protected定义的成员只能在该类及其子类中访问。

private定义的成员只能在该类自身中访问。

派生类可以用public和private两种访问权限继承基类中的成员,如果在定义派生类时没有指定如何继承访问权限,则默认为private。

如果派生类以private继承基类的访问权限,基类中的成员在派生类中都变成private类型的访问权限。

如果派生类以public继承基类的访问权限,基类中的成员在派生类中仍以原来的访问权限在派生类中出现。

注意:

基类中的private成员不能被子类访问,所以private成员不能被子类所继承。

我们分析清单1-03中的代码,完整例程请参见光盘中例子代码EX01-03。

清单1-03类的继承1classCAnimal23public:

4voideat();5voidbreathe();6;7voidCAnimal:

eat()89couteatingendl;1011voidCAnimal:

breathe()1213coutbreathingendl;1415classCFish:

publicCAnimal1617public:

18voidswim();19voidbreathe();20;21voidCFish:

swim()2223coutswimmingendl;2425voidCFish:

breathe()2627CAnimal:

breathe();28coutbreathingbreathe();40第15行代码由于CFish以public修饰符继承了CAnimal,所以在main函数中3234行用CFish定义的对象f可以将CAnimal中定义的eat()成员函数当作自己的成员函数调用。

f还调用了CFish中新定义的成员函数swim()。

第35行代码,对象f还调用了breathe()函数,大家发现在基类CAnimal和派生类CFish中都定义了breathe函数,在这种情况下调用的到底是哪个类中定义的函数呢?

在这里,调用的是子类CFish中定义的函数。

如果在子类与父类中都定义了同样的函数,当用子类定义的对象调用这个函数时,调用的是子类定义的函数,这就是函数的覆盖。

函数的覆盖,我们可以用生活中的例子来比喻,儿子继承了父亲的许多方法,包括“结婚”这一行为,但父亲“结婚”用的是花轿,而儿子“结婚”用的却是汽车,儿子不能使用父亲“结婚”的方式。

如果儿子结婚时,即要花轿,也要汽车,也就是在子类的成员函数定义中,要调用父类中定义的那个被覆盖的成员函数,其语法为,父类名:

函数名(参数)。

如CFish定义的breathe函数中第27行代码使用的CAnimal:

breathe()语句,就是调用CAnimal中的breathe函数。

在程序中main函数的结尾处的3739行代码:

CAnimal*pA;pA=&f;pA-breathe();上述代码定义了一个CAnimal类型的指针pA,pA指向CFish定义的对象f的地址,用指针pA去调用breathe函数,在这种情况下调用的到底是哪个类中定义的函数呢?

简单的死记硬背只能管一时,不能管一世。

我们还是从类型转换的原理上寻找答案。

将鱼CFish对象的首地址直接赋值给动物CAnimal类型的指针变量,是不用强制类型转换的,编译器能够自动完成这种转换,子类对象指针能够隐式转换成父类指针。

这个过程好比现实生活中将一条鱼当作一个动物是没有什么问题的,但要将一个动物当作鱼来对待是存在问题的。

如果某一动物确实是一条鱼,我们就可以将这个动物强制类型转换成鱼。

也就是说,要将父类类型的对象转换成子类对象,在程序中必须强制类型转换,编译才能通过,但要保证内存中的对象确实是那种被转换成的类型,程序在运行时才不会有问题。

我们可以这样想象类型转换,用目标类型的内存布局,去套取要类型转换的对象的首地址开始的那一段内存块(大小为目标类型的大小),套取的内容即为转换后的结果。

见图x,&f转换成pA后,转换完后的内容包含的breathe是CAnimal中定义的那个。

关于类的继承及类的访问特性可以参照如下表1-00:

表1-00类的访问特性基类的访问特性类的继承特性子类的访问特性PublicProtectedPrivatePublicPublicProtectedNoaccess1PublicProtectedPrivateProtectedProtectedProtectedNoaccess1PublicProtectedPrivatePrivatePrivatePrivateNoaccess11.5.2多重继承如同该名字中所描述的,一个类可以从多个基类中派生出来。

在派生类由多个基类派生出来的多重继承模式中,基类是用基类表语法成份来说明的,多重继承的语法与单一继承很类似,只需要在声明继承的多个类之间加上逗号来分隔,如下定义形式:

class派生类名:

访问权限基类名称,访问权限基类名称,访问权限基类名称;例如B类是由类C和类D派生的,可按如下进行说明:

classB:

publicC,publicD基类的说明顺序一般没有重要的意义,除非在某些情况下要调用构造函数和析构函数时。

在这些情况下,基类的说明顺序会对以下所列的有影响:

由构造函数引起的初始化发生的顺序。

如果你的代码依赖于B的D部分要在C部分之前初始化,则此说明顺序将很重要。

初始化是按基类表中的说明顺序进行初始化的。

激活析构函数以作清除工作的顺序。

同样,当类的其它部分正在被清除时,如果某些特别部分要保留,则该顺序也很重要。

析构函数的调用是按基类表说明顺序的反向进行调用的。

虽然,多重继承使程序编写更具有灵活性并且更能真实的反映现实生活,但由此带来的麻烦也不小。

请看清单1-04的程序:

清单1-04类的多重继承的困扰1#include2classB134public:

5voidoutput();6;7classB289public:

10voidoutput();11;12voidB1:

output()1314coutcalltheclassB1endl;1516voidB2:

output()1718coutcalltheclassB2endl;1920classA:

publicB1,publicB22122public:

23voidshow();24;25voidA:

show()2627coutcalltheclassAbreathe();语句调用的是CFish类中定义的breathe()函数,这就是编译器对虚函数调用的编译方式,这就是虚拟函数的多态性。

如果在某个类的成员函数定义前加了virtual,这个函数就是虚函数,如果子类中有对该函数的覆盖定义,无论该覆盖定义是否有virtual关键字,都是虚拟函数。

1.7类的书写规范由于Windows程序一般很长,到最后,编程人员自己都有可能忘记所定义的变量的含义,因此,Windows中有一个约定,称之为匈牙利表示法(Hungariannotation)。

匈牙利表示法提供了一组前缀字符,如表1.1所示,这些前缀也可以组合起来使用。

关于完整的c+语法讲解,需要厚厚的一大本书,如果读者需要深入了解,请参看相关书籍。

但只要掌握了本课中介绍的关于C+的知识,基本上就能够顺利学习以后的章节了,如有特殊需求,我们将在以后章节中用到时专门讲解。

我们认为抱着问题学习的效果要比泛泛而学的效果好得多,并且学到一个新知识后马上便能看到其应用更能令人记忆深刻,举一反三。

表1.01匈牙利表示法前缀含义a数组b布尔值(int)by无符号字符(字节)c字符(字节)cb字节记数cr颜色引用值cx,cy短整型(计算x,y的长度)dw无符号长整型fn函数h句柄i整数(integer)m_类的数据成员n短整型或整型np近指针p指针l长整型lp长指针s字符串sz以零结束的字符串tm正文大小w无符号整型x,y无符号整型(表示x或y的坐标)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 从业资格考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1