C++ Primer Plus 读书笔记(第1, 2章)
前言
在C++ Primer Plus和C++ Primer 这两本书之间选择了很久, 最后还是敲定了前者, 原因是许多人反应前者更基础, 有的人推荐有过C语言的基础的话适合后者. 而我觉得自己在编程方面仅仅局限于解决竞赛中的题目, 而并没有一个软件设计的思想在里面, 这在平时做的一些课程设计中自己也能够感受到, 两者不能说没有关系, 许多解题的想法和编程技巧能够很好的应用到项目中来, 但是自我感觉语言中的很大一部分还是被忽略了, 因为那些在解题中几乎是用不到的. 因此选择了这本C++ Primer Plus, 能够让我从0基础来认识C++, 因此也要花费更多的时间来读这一本书.
第一章:预备知识
不得不说, 预备知识和书中前言所说的不需要任何基础相去甚远, 基本一股脑概括了整本书该学习的内容, 如果真的从来没接触过一点编程, 这一章绝对能够摧毁一个人的自信心. 似乎看过的计算机方面的书, 这个预备知识一直以来的都特别让人厌烦. 下面就这一章我学习到了什么东西进行一下分享.
C,C++简介
首先提出一个概念, 并且这个概念在后面会被多次提到, 那就是
C++ = C代表的过程性语言 + 类代表的面向对象语言 + C++模板支持的泛型编程
学习的终极目标就是将这三者有机结合, 最后发挥出无穷的威力, 而不是陷入那种方法更好的争辩中.
C语言和C++语言都诞生与贝尔实验室, 两种语言的提出都有相应的时代背景, 就被创造出来的当时而言, 他们都是了不起的进步, C++并没有摒弃C, 而是在其基础上加以完善和补充, 习惯C编程的人分析问题时总是直奔主题的, 采用一种称作为自顶向下的分析方式, 即首先将一个巨大的任务划分成小的任务, 然后再划分, 知道能够被很好的实现, 最后再将它们组合起来. 而面向对象的编程想法给人的感觉是不紧不慢, 首先从概念上分析出问题出现的对象有哪些, 那后着力去写好从对象中抽象出来的类, 完成这些类后, 再考虑它们是如何来协调完成这个任务的. 换句话说, 你不需要对整个任务有充分的了解你也同样能够参与到一个项目的开发中来, 只要你能够完成你的那一部分, 处理好接口, 等待别人来调用.
泛型编程能够很到程度上减少一些通用代码的重复编写, 书中以一个排序函数打了比方, 如果要为每一个数据类型都写一个排序函数, 并且这些代码基本无异, 那么这将是一件很无聊的事情, 而且增加了出错的概率, 因此一个通用的类型类代替各种类型就使得这个问题得到了很好的解决.
后面讲到了一个标准的指定问题, 为的就是解决各大平台上代码的移植性问题, 所以硬性给出了一些关于语言的规定, 谁都不能够违背. 最后得出一个结论, C++标准中初期延续了大量的C的标准, 后期就是C标准中吸收了许多C++的特性, 非常有意思.
关于C++源文件拓展名的选择:
正式因为cpp和cxx这两个拓展名都非常常用, 因此当时在制定头文件后缀的时候不知是用哪一个, 因此就干脆不使用后缀了. 看来制定标准有时候就是怎么简单. 呵呵.
最后书中告诉我们. 咱们平时用来编写C++程序的都是一个集成的开发环境(IDE), 而早期的程序员是要每个文件在记事本中单独写好, 然后将他们统计使用命令行进行编译. 要完成其他的例如调试或者是项目管理就得依靠其他的工具来协同实现. 可见神马VS****还是非常厉害的.
第二章:开始学习C++
从这一章真的可以看出整本书写的确实是非常详尽, 有时候可以用不厌其烦来表示, 本以为谭老的那本够详尽了, 可惜我还是图样图森破.
回车, 空格的关系以及续行符
C++在编译处理源文件的时候, 一般空格, 制表符, 回车看做同一个东西, 所以一下代码依然可行:
#include <iostream>
int
main
() {
using
namespace
std; cout <<
"hello world."
<<
endl;
return
0;
}
但是这样写代码, 谁能有个好心情看下去呢?其实书中讲到这个特性的时候, 我想到了不是还有一个叫做续行符的东西吗, 既然有这个特性, 那么为什么还要有续行符这种东西呢, 后面在书中找到了答案.
其实上述代码之所以编译器能够识别就是因为C++的每一条语句都是以” ; ”来结束的, 所以在没有发现” ; ”之前, 编译器不会认为该条语句已经结束, 也就是空格和回车基本是可以互换的. 虽说如此, 但是还是要求一条语句满足一定的要求, 这样做也是为了防止二义性的发生. 具体来说就是不能把空格或者,制表符,或回车放在元素(比如名称)中间, 也不把回车放在字符串中间. 例如:
#include <iostream>
int ma // main 是一个整体
in()
{
usi ng namespace std; // using 也同样不能拆开
cout << "hello // 字符串之间不能够用回车分开
world." << endl;
return 0;
}
此时续行符就能够发挥作用了, 上述代码可以转化为:
#include <iostream>
int ma\
in()
{
using namespace std;
cout << "hello\
world." << endl;
return 0;
}
其大概作用就是忽略掉这一个回车吧.
endl 和 \n 的区别
书中对cout又是一大堆的表扬, 称赞其非常的智能化, 不需要想printf那样每次使用精确的格式控制符来. 确实, 强大的cout从来不惧怕任何敌人, 他还允许我们重载运算符来输出我们自己定义的类型. 这里有一个地方值得注意的就是当我们想要输出一个回车的时候, 有两种选择, 一种是cout << endl; 而另外一种则是cout << “\n”; 写惯了C语言的无证程序员肯定会选择后者了, 因为他们不明白endl是什么东西, 无法达到精确控制. 确实我到现在也是不知道endl到底是个什么玩意儿, 不管这些, 如果不适用std命名空间的话, 无法使用endl,而使用endl还可以使用这样一个语句 using std::endl; 足以说明其有多神秘.
书中对这两者一个很明显的区别还是提了一句话,那就是endl能够确保程序继续运行前刷新输出(将其立即显示在屏幕上), 而”\n”只认为是一个简单的字符串, 不能够作这样的保证. 之所以有这样的区别, 也是因为cout带了一个输出缓冲区, 当输出的内容达到一定之后再统一输出, 而printf每次都是即时输出. 所以混合使用这两者的话, 先cout的可能在后printf的内容之后输出.
定义声明和引用声明
这两者不一样, 也就是说我们声明一个变量不一定是对他的定义.
int a; 和 extern int a; 就不一样. 后者本意是引用一个外部声明的a, 欲将其作用域扩大到本处.
代码风格及其他一些建议
1.每条语句占一行.
2.每个函数都有一个开始花括号和一个结束花括号, 这两个花括号各占一行.
3.函数中的语句都相对于花括号进行缩进.
4.与函数名称相关的圆括号周围没有空白.
前三条规则旨在确保代码清晰易读; 第四条规则帮助区分函数和一些也是使用圆括号的C++内置结构(如循环).
尽量这函数中说明该函数要使用到哪些命名空间.
尽可能在首次使用变量前声明它.