读书笔记----《C++编程经典》---(持续更新)

   第一章:
使用“组装方法”创建程序,尽量不重复别人已经做过的工作,尽可能利用现有的构件单元---这正是“软件重用”的主旨,也是面向对象编程的精髓所在。
   进行C++编程时,通常使用以下基本构件单元:来自C++标准库的类和函数,你自行创建的类和函数以及由一些知名的第三方库所提供的类和函数。
   C++程序通常要经历6个执行阶段。包括:编辑,预处理,编译,连接,装入和执行。C++预处理程序(又称预处理器)将遵循一些名为预处理程序指令的特殊命令,他们指示在编译开始之前,应先采取一些特定的行动。这些行动通常包括:将其他文本文件包括到要编译的文件中,以及执行特定的文字替换等等。
   C++程序应以简单和直接的方式编写。这有时称为KIS(keep it simple)尽量简单的编程方法。千万不要去尝试一些古怪的用法,滥用这种语言。
   #include <iostream>是一条预处理程序指令;换言之,是发送给C++预处理器的一条消息。以# 开头的行会在程序编译之前由预处理器进行处理。
   避免使用以下划线和双下划线开头的标识符,因为C++编译器可能采用这种形式的名称为其内部的某些用途提供服务。这样,有助于避免你选择的名称同编译器选择的名称混淆。
   面向对象其实就是思考这个世界以及编写计算机程序的一种颇为自然的方式。
   UML(统一建模语言),它是一种图形化语言,允许系统构件人员(软件结构设计师,系统工程师,程序员等)采用一种标准的记号法,对他们的面向对象设计进行呈现。
   面向对象编程(OOP)以软件的形式,对现实世界的对象进行建模。
   面向对象的编程还为我们提供了一种更加自然和直观的方式来看待编程过程。换言之,编程过程就是对现实对象及其属性/行为进行建模的一种过程,OOP还可以为对象之间的通信进行建模,如同人们向同伴发送消息一样,对象之间也通过消息进行沟通!
   我们认为会对软件开发的未来产生影响的3大因素是“重用重用还是重用”。
   有经验的程序员知道,一个系统开发方案事先没有计划好,往往会半途而废,浪费大量时间。相反的,表面上似乎很复杂的问题,只要事先进行精心的分析和设计,便可事半功倍!
伪代码对小问题来说也许已足够,但随着问题以及解决这些问题的人数的增加,OOAD的方法会显得更加有效。目前有多种不同的OOAD过程可供选择;但是,可对任意OOAD过程的结果进行沟通的一种图形化语言正在得到人们的广泛使用。这一语言便是UML(统一建模语言)。
UML:
针对面向对象系统的建模,UML目前是应用得最广的图形化表示方案。它实现了当初设计者的目标,真的将20世纪80年代末流行的各种记号方案统一起来了---凡是设计系统的人,都可以使用这一语言(采用示意图的形式)对系统进行建模。
对象本质上一种可重复使用的软件组件,用于对现实世界中的各种物件进行建模。对象是根据名为“类”的一种蓝图而构建起来的。
第二章:
无论过去还是未来,我们的所有C++程序都可基于前述7类控制结构(顺序,if,if/else,switch,while,do/while和for)进行构建。不同控制结构只需要通过控制结构堆叠和嵌套这两种方法即可合并到一起!
在程序设计阶段,通常是先用伪代码来思考一个程序,再将伪代码程序转换成为真正的C++程序!
(从第二章开始,作者开始针对一个项目而进行面向对象设计,这样的方式很好!当我粗略地看完他对于那个实例的设计时,我暗暗叹服~这才是真正的面向对象,感觉上设计程序已经完全变成~~~一种认识世界的方法~~你去认识这个世界~那你就已经在编写程序了~~你不需要考虑语言考虑计算机~这个时候我才明白~~面向对象是如此的魅力四射!我想起在我的游戏程序里用的那些所谓的面向对象编程是多么的粗糙!多么的垃圾啊!)
解决问题时,具体过程即为“要采取的行动”;采取的顺序即为“算法”。

//

开发流程:

1.分析和设计系统

2.用例图

   对于分析阶段的输出来说,它的意图是清楚地指出系统应如何构建才能完成需要它做的工作。UML提供了用例图,以便简化进行需求分析的过程。用例图的目标是展现用户同系统之间的各种交互,但不必提供交互的细节!

3.标识系统中的类。

4.类图

   UML允许我们通过类图对电梯系统中的“类”及其“关系”进行建模。

在一个类图中,各类都用矩形来表示。然后,该矩形被分成3部分。顶部包含类名。

中部包含类的属性;底部包含类的操作。

通过关联,便将不同的类联系在一起。所谓关联,就是类之间的一种关系。

5.对象图

UML还定义了对象图,它同类图相似,只是它建模的是对象和链接(链接是对象之间的关系)。和类图相同,对象图也对系统的结构进行建模。对象图展示了系统运行时的一个结构“快照”,即提供了在某个特定的时刻,参与系统运作的各个对象的信息。

第三章:

   rand()生成0RAND_MAX(是<cstdlib>头文件中定义的一个符号常量)的一个无符号整数。RAND_MAX的值至少应为32767—一个两字节整数所能表达的最大值。

P191

   面向对象程序设计的第一阶段,即确定(实现电梯模拟程序)所需要的类。然后会确定每个类的属性,再确定其操作,最后确定不同对象之间的交互。

    开发和维护大型程序的最佳方式是将其分成更小的程序模块,与原始程序相比,每个小模块将更易于管理。在C++中,模块被称为类和函数。

第六章:

 面向对象的设计方法:分析典型问题语句,要求建立一个系统,确定系统中需要实现的类(标准系统所牵涉的类),确定这些类对象的属性,确定这些类对象的行为,并指定对象之间如何通过交互来完成系统的总体目标。

  

绝不要让类的public成员函数返回对该类private数据成员的非常量引用或指针。返回这种数据会破坏类的封装。(意思就是说,客户程序员可以不通过类本身的设置其数据成员的函数而在外部直接改变那个成员。这会导致意外发生!)

 

如果在类定义中定义成员函数,该成员函数将自动成为内联函数,但编译器有权决定其是否作为内联函数。

 

良好的软件工程的基本原则之一是将接口与实现分离。

 

赋值操作符(=)可以将一个对象赋给另一个类型的对象,这种赋值方式一般通过默认的按位成员复制来完成。按位成员复制不适用于所有的类!

 

变量用const修饰,其值不得被改变。任何改变此变量的代码都会产生编译错误。Const加在数据类型前后均可。

Const跟指针一起使用时有两种方法:1. const可用来限制指针不可变。也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。2. const也可用来限制指针指向的内存不可变,但指针指向的内存地址可变。

类的每个对象都有其所有数据成员的副本。某些情况下只有一个变量副本供类的所有对象共享。静态变量就是为此以及其他用途而设计的。静态变量表示整个类范围中(所有类对象而非指定的类对象)共享的信息。

  (对了,在类里定义一个静态变量,可以用它来记录这个类一共实例化了多少个对象~经典的作用,感觉上有点象COM

   最常见的类型包括容器类(也称集合类),即将类设计为保存一组对象集合。容器类通常提供插入,删除,查找,排序和测试类成员项目等操作确定该容器类是否是集合的成员。数组,堆栈,队列,树和链表都是容器类。

   容器类经常与迭代对象(简称迭代器)关联。迭代器是返回集合中下一个项目的对象(或对集合中下一个项目的某种操作)。

   代理类,就是为了隐藏一个类A的接口而定义另一个类B,让B有一个私有的A对象!

向客户代码提供代理类,代理类只能访问类的public接口,这样就可以让客户代码使用类的服务而不必访问类的实现细节。代理类唯一的private成员是隐藏该类对象的private数据的指针。P476

(来自网络:

友元函数要在一个类体内说明,形式为:
friend
类型名 友元函数名(形参表
);
然后在类体外对友元函数进行定义,定义的格式和普通函数相同,但可以通过对象作为参数直接访问对象的私有成员

友元函数说明如下
:
1)
必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括在privatepublic部分
;
2)
注意友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"::"指示属于哪个类,只有成员函数才使用"::"作用域符号
;
3)
友元函数不能直接访问类的成员,只能访问对象成员
,
4)
友元函数可以访问对象的私有成员,但普通函数不行
;
5)
调用友元函数时,在实际参数中需要指出要访问的对象,

 

 

继承是软件可重用性的一种形式,新类通过继承这一方式,从现有的类中吸收其属性和行为,并对其进行覆盖或改写,产生新类所需要的功能。软件的可重用性可节省程序开发的时间。

多态性可以使我们以常规方式写程序以操作多种现有的,且已专门化了的相关类。继承和多态性是管理软件复杂性的有效技术!

 

 友元函数不能被继承!

如果派生类可以访问基类的 private成员,就会破坏基类的封装。隐藏private成员对于测试,差错,和正确地修改系统有着重要的意义。如果派生类可以访问基类的private成员,那么从该派生类派生而来的类也能访问这些数据,这种对private数据的访问能力传递下去,会削弱类的层次结构封装的优势!

  基类的初始程序可以在派生类中显示调用基类的构造 函数来实现,否则派生类的构造函数会调用基类的默认构造函数。

  public继承方式下,派生类对象也可视为基类的对象,这之所以有意义是因为派生类中有相应的成员和基类的成员一一对应,记住,派生类的成员可能比基类更多,其他方向的赋值是不允许的,因为将基类对象赋值给派生类会导致派生类独有的成员不被定义。

  用基类对象与派生类对象混合和匹配基类与派生类指针时,可采用以下4种方法之一:

1. 直接用基类指针指向基类对象

2.  直接用派生类指针指向派生类对象

3.  用基类指针指向派生类指针,这不会有危险,因为派生类对象同时也是它基类的对象。这样的代码只能指向基类成员。如果用基类的指针指向派生类才有的成员,会出现编译错误

4.  用派生类指针指向基类对象,会 语法错误。派生类指针必须先强制转换为基类指针。

 

基类指明了共性---基类的所有派生类都继承了基类的功能。在面向对象的设计中,设计者按照求同排异的方式设计基类。在继承基类功能的基础上,定制派生类。

 在面向对象的系统中,类与类常联系紧密。求同排异是将共有的属性和行为放在基类中,然后用继承来生成派生类。

  第十章:

  对不同类型的对象进行处理,一种方法是使用switch 语句。不同类型的对象,采用的操作有所不同。

  使用虚拟函数和多态性进行程序设计后,将不再需要switch逻辑。程序员可以用虚拟函数机制自动执行等价的逻辑,从而避免了switch逻辑带来的各种错误。

  使用虚拟函数和多态性以后,一个有趣的结果是,程序看上去变得很简单。程序中很少有分支逻辑,而是一些简单的顺序代码。这大大简化了程序的测试,调试和维护,避免了错误!

  如果用名称和圆点成员选择操作符引用一特定对象以调用虚拟函数,被调用的虚拟函数是在编译时确定的(即静态绑定),调用的虚拟函数就是为该特定对象的类(或继承该对象类)定义的函数。

  把一个类视为一个数据类型时,我们假定该类型的对象要被实例化。然而,很多情况下,定义程序元不想将其实例化为任何对象的类仍然大有好处。这样的类称为“抽象类abstract class.因为这些抽象类要被用作基类,所以通常也称为“抽象基类abstract base class.抽象基类不能实例化为对象。

  抽象类的唯一用途是为其他类提供合适的基类,以便它们可以从它那继承和/或实现接口。可实例化为对象的类称为“具体类concrete class.

  如果类从带有纯虚拟函数的类派生迩来,且该派生类中没有提供该纯虚拟函数的定义,那么这个纯虚拟函数在该类中仍然是纯虚的,这个派生类仍然是抽象类。

  一个类层次结构中可以不包括任何抽象类,但许多面向对象的好系统中,类层次结构的顶部便是抽象基类。某些情况下,层次结构好的顶部好几层都是抽象类!

 

   多态性是通过虚拟函数实现的 。通过基类指针(或引用)来请求使用虚拟函数时,C++会在与对象关联的派生类中选择正确的改写过的函数。

   尽管不能实例化抽象类,但是可以声明抽象基类的指针和引用。实例化具体类的对象时,这些指针和引用就可用于实现派生类对象的多态性操作。

   多态性特别适合分层的软件系统。
  
(内联函数不能是虚函数,因为内联函数是不能在运行中动态确定其位置的。即使虚函数在类的内部定义,编译时仍将其看作是非内联的!说明虚拟析构函数的目的在于:使用delete运算符删除一个对象时,能确保析构函数被正确地执行。这是因为设置虚拟析构函数后,可以利用动态联编方式选择析构函数!构造函数不能说明为虚拟函数,因为构造对象时还是一片未定型的空间。只有在构造函数完成后,对象才能作为一个类的名副其实的实例!)

 

 多态性,虚函数和动态绑定的本质

在编译一个或多个虚拟函数的类时,C++会为该类建立一个虚拟函数表(vtable)。每次执行该类的虚拟函数时,执行中的程序都会用vtable来选择恰当的实现方法。

  任何类在其vtable中都有一个或多个函数指针是0,它就是抽象类。类的vtable没有任何为0的指针,该类就可称为具体类!

P596

 

 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值