回 帖 发 新 帖 刷新版面

主题:写了2年的初学者C++基础教程,今天终于出版了《易学C++》

[size=3][color=FF0000]本书已交由人民邮电出版社出版发行。[/color]

[b][size=4][color=0000FF]购买《易学C++》网址:[url]http://www.china-pub.com/39862[/url],欢迎大家捧场![/color] [/size][/b]

完整版含附录,其中包括C++常用关键字及含义、所有练习的参考答案等。[/size]
编写的主旨就是不要一下子把什么都说出来,而是一点一点循序渐进地增长读者的能力。
摒弃直接使用专业的术语,而是以形象地比喻来介绍程序设计中的内容,比如把变量比作箱子,把分支语句比作开关等等。对没有程序设计基础的朋友来说,也能够轻松地看懂。
同时也注重提高读者的实际能力,在书中穿插讲述一些常用的小算法和小技巧,尽量避免看得懂书却写不来程序的情况。
[color=FF0000][size=4]下载[/size]请到[url]http://www.tomatostudio.net.cn[/url]
e-mail:[email]tomatostudio@126.com[/email][/color]

回复列表 (共59个回复)

41 楼

楼主真是认真!放心!我会把这些全部看完
我也会及时来此看新的内容的!

42 楼

你的文章很好真的很形象我很支持!希望你继续努力写了这么久的程序看了很多C++的书你的文章即是入门映象的好文章更是老程序员值得回味的好文章!我可以转载到我的QQ上么?!

43 楼


44 楼

继续啊
写的很好
我也是出学者看了后懂了很多
什么时候能够写写  QUEUE 的文章啊  我们学了很久了可是我还不是很懂
[em10]

45 楼

这一章主要是讲构造函数和析构函数。因为我在学的时候就认为拷贝构造函数就是构造函数的一种重载,所以把它也拉到这个章节里面来了。至于什么无名对象,至少在大学阶段用的机会不会很多,所以干脆就不说了。这段时间又有好多老师、出版社和我联系出版事宜,我想等到下一章写完,差不多也就剩2-3章左右,到那时候可以好好考虑一下出版的问题。

本次内容节选:

既然init函数担负着初始化对象的重任,那么它就必须和对象的声明“出双入对”了。万一忘记对对象进行初始化,程序就可能会出错。这就像在病毒肆虐的今天,保证电脑安全的病毒防火墙必须在开机之后立刻运行一样。万一哪天开了电脑忘记运行病毒防火墙,那么后果可能很严重。不过,你使用的病毒防火墙是你每次开机以后自己去点击运行的么?那样岂不是很麻烦?你是否知道,我们使用的病毒防火墙往往是随系统一起启动的?这给了我们一些启示:有的程序能够随着系统的启动而自动运行,那么会不会有一种函数,随着对象的创建而自动被调用呢?有!那就是构造函数(Constructor)。

根据程序的运行结果,我们发现头结点的构造函数比链表的构造函数优先运行。这也不难理解:构造函数的目的是要初始化成员数据,初始化成员数据的时候这个成员数据是必须存在的。所以当一个成员数据是一个对象的时候,应当先产生这个子对象,于是就先调用了子对象的构造函数。

我们看到,现在即使运行a.Destroy()之后,链表b里面的数据仍然能够正常显示。这是因为深拷贝构造函数是真正意义上的复制了链表a,并且使得链表a和链表b各自独立,互不干扰。这才是自定义拷贝构造函数存在的重要意义。

在学习链表的时候,我们知道结点是动态生成的,如果在程序结束之前不释放内存,就会造成内存泄漏。虽然我们已经编写了成员函数Destroy来删除所有动态生成的结点,但是如果我们不知道这个链表对象何时不再使用,那么调用Destroy的时机对我们来说就是个麻烦了。如果过早地调用,则后面的程序可能会出错。既然有构造函数能随着对象的创建而自动被调用,那么有没有一种函数能随着对象的消亡而自动被调用呢?有!那就是析构函数(Destructor)。

46 楼

这一章是面向对象初级部分的大杂烩,什么静态成员、友元、操作符重载都在。在钱能的书里面,操作符重载独立成章的。但是我觉得操作符重载和友元隔开的话,友元容易被忘记。至于输入输出流是否独立成章,这个到时候再看。下一章将介绍继承和多态,主要围绕一个文字RPG游戏。相信这个游戏能比较好地解释类与类之间的继承关系,也能引起大家的学习兴趣。为了配合出版工作,下一章将会是网上发布的最后一章。如果某些读者有特殊的需要,可以和我联系索取之后章节的电子版。

本次内容节选:

该程序中出现了两种调用静态成员函数的方法,一种是类名::静态成员函数名(参数表),另一种是对象名.静态成员函数名(参数表),这两种调用方法的效果是相同的。由于静态成员函数是属于类的,不是属于某一个具体对象,所以它分不清到底是访问哪个对象的非静态成员数据,故而不能访问非静态成员数据。

类似于链表类和链表结点类的问题,我们可以用友元类来解决。即链表类是链表结点类的“朋友”,可以直接访问链表结点类的私有成员数据或私有成员函数。显然,要做链表结点类的“朋友”,必须要得到链表结点类的认可。所以我们必须在链表结点类的声明中告诉电脑,链表类是它认可的“朋友”,可以访问它的私有成员。

在声明和定义操作符重载时需要注意以下几点:
(1)操作符只能是C++中存在的一些操作符,自己编造的操作符是不能参与操作符重载的。另外,“::”(域解析操作符)、“.”(成员操作符)、“……?……:……”(条件操作符)和sizeof等操作符不允许重载。
(2)参数表中罗列的是操作符的各个操作数。重载后操作数的个数应该与原来相同。不过如果操作符作为成员函数,则调用者本身是一个操作数,故而参数表中会减少一个操作数。
(3)各个操作数至少要有一个是自定义类型的数据,如结构或类。
(4)尽量不要混乱操作符的含义。如果把加号用在减法上,会使程序的可读性大大下降。

前增量操作符是“先增后赋”,在操作符重载中我们理解为先做自增,然后把操作数本身返回。后增量操作符是“先赋后增”,在这里我们理解为先把操作数的值返回,然后操作数自增。所以,前增量操作返回的是操作数本身,而后增量操作返回的只是一个临时的值。

47 楼

支持

48 楼



[fly]对我们初学者很有用啊 谢谢[/fly]

49 楼

终于将第17章写完了。这一章是整本书中内容最多的一章。虽然C++在继承这块的内容很多,但是我还是做了删减。比如多重继承这种常常被人批判的内容,我只简要介绍了一下概念。对于本科生来说,这些内容应该已经够用。特别是在企业面试的时候,常常是问一些很基础的概念。面向对象的精髓并不是靠看几本书就能了解的,而是要在实际的工程中才能领悟的。

看到众多网友来信与我交流,肯定我的写作风格、向我提出众多宝贵的建议,我感到非常高兴。本章将会是我公布在网上的最后一个章节。之后的2-3章或许大家以后可以在书店里看到。近期我会和各大出版社联系,讨论出版事宜,以便更多的读者能够快速踏入C++程序设计的大门。如果您有在出版社工作的朋友,并且看好我的作品,也欢迎您主动来和我联系!我的邮箱地址为tomatostudio@126.com。

本次内容节选:

如果有一个类,我们可以将其实例化,成为若干个对象。另外,如果我们希望对这个类加以升级改造,我们可以将这个类继承,形成子类(或者称为派生类),被继承的类则称为父类(或者称为基类)。实例化和继承是一个类的两种发展方向。继承能够减少我们开发程序的工作量,提高类的重用性。
如果我们把编写一个类看作是一次生产,那么产品(即编写出来的类)可以有两种用途:一种是将产品直接使用,相当于将类实例化;另一种是将产品用于再生产,相当于将类继承。类在这种不断的“再生产”中变得更为强大、健全。

private是私有继承,或称为私有的实现继承。它主要体现的是父类成员的重用。父类所有的公有、保护成员继承到子类时,类型会发生改变。父类的公有成员在子类中变成了私有成员,父类的保护成员在子类中也变成了私有成员。这时,我们可以利用从父类继承而来的成员函数来实现子类的成员函数,并且不必担心外部直接访问父类的成员函数,破坏了子类的秩序。比如我们认为栈是一种特殊的链表,它只能从链表尾部添加或删除结点,栈的压栈和退栈功能可以方便地由链表类的成员函数实现。但是,如果外部还能直接访问从链表类继承而来的成员函数,那么就可以在栈的任何位置插入结点,栈就会被破坏。

在使用继承的时候,子类必然是在父类的基础上有所改变。如果两者完全相同,这样的继承就失去了意义。同时,不同子类之间具体实现也是有所区别的,否则就出现了一个多余的类。不同的类的同名成员函数有着不同的表现形式,称为多态性。多态性是符合人的认知规律的,即称呼相同,所指不同。比如,学生类及其子类都有学习这个成员函数,但本科生、中学生、小学生的学习内容并不相同;玩家类的子类都有攻击这项技能,但剑士、弓箭手和魔法师的攻击方法不同。

多态是在程序员没有指定调用父类还是某个子类的成员函数时,电脑根据程序员的要求,揣测并选择最合适的成员函数去执行。但是当成员函数的参数格式不同时,程序员在调用成员函数的各种参数无疑就是在暗示到底调用哪个成员函数。这时电脑岂敢自作主张揣测人类的心思?因此,要使用虚函数实现多态性,至少要使各个函数的参数格式也完全相同。

C++中的确能实现多继承,但是在某些问题上并不是处理得很好。比如车和船同时具有长、宽、高等属性,要搞清水陆两用车的长、宽、高到底是从哪个类继承来的,着实要花费一些功夫。应该说,C++中多重继承的思想是优秀的,但是它的实现却是混乱的。有不少人都认为多重继承是C++的一个败笔,它把原本简单的单一继承复杂化了,使程序员很难再把思路理清。所以,即使是经验丰富的程序员,在大多数情况下也不会去使用多重继承。

50 楼

最近更新节选:

cout和cin并不是语句,而是标准输入输出流的类对象。它们分别被定义在istream.h和ostream.h头文件中。那么什么是流呢?简单地说,数据如同流水线上的物品在电脑中传输。要读取流中的数据(把输入流中的数据读到内存中),就如同取下流水线上的物品,这就是抽取;要向流中写入数据(把数据放到输出流中输出),就如同往流水线上放东西,这就是插入。

cerr和cout类似,也是输出流对象。当然,它们也有区别。cout是平时常用的普通输出,可以被重定向。而cerr正如其名,通常是异常情况下输出重要的出错信息。它只会输出到屏幕上,无法被重定向。这样,用户才不会因为信息被重定向而错过了重要的出错提示信息。

为什么不能像标准输入输出流一样有个现成的fin或者fout对象呢?这也不难理解:文件输入输出流的输入输出设备是磁盘文件,但是磁盘上有那么多文件,到底应该使用哪一个呢?所以,C++干脆就把创建对象的任务交给用户了。我们可以在创建对象自动调用构造函数时,设定输入或输出到哪个文件。

我们用形如cin >>a;的方式输入数据,就像是按“个”为单位取下流水线上的物品。因为侧重点在于单个物品,空格就犹如分隔物品的纸箱格,与其他数据一起被丢弃。我们也可以使用cin的成员函数getline来获取数据,这时候就像按“箱”为单位取下流水线上的物品。纸箱格作为取下的东西的一部分,不会被丢弃。

我们已经知道,插入操作符应该有两个操作数。前者是ostream类的对象(引用),后者是需要输出的内容,两者的次序不应该颠倒。如果把插入操作符作为成员函数,那么就会影响了操作数的次序。因此,通常情况下,我们将插入操作符作为友元函数。

我来回复

您尚未登录,请登录后再回复。点此登录或注册