Skip to content

第一章 预备知识

面向对象编程OOP

面向过程编程(OPP)中,如果是狗吃屎,会写成“eat(狗, 屎)”,eat()函数中会有大量的if-else。

在C++中,类是一种规范。就拿上面的例子,吃是共性,抽象出类,然后继承——狗->eat(屎)。

OOP程序设计方法首先设计类,它们准确地表示了程序要处理的东西。从低级组织(如类)到高级组织(如程序)的处理过程叫作自下向上的编程。

可移植性和标准

ISO C++标准还吸收了ANSI C语言标准。这意味着在理想情况下,任何有效的C程序都应是有效的C++程序。

第二章 开始学习C++

进入C++

程序段:

#include <iostream>
int main()
{
  using namespace std;
  cout << "Come up and C++ me some time.";
  cout << endl;
  cout << "You won't regret it!" << endl;
  return 0;
}

很多现有的程序都使用经典C函数头:

main()

在C语言中,省略返回类型int相对于说函数的类型为int。然而,C++逐步淘汰了这种用法。

也可以使用下面这种变体:

int main(void)

括号中使用void明确函数不接受任何参数。在C++中,让括号空着=填入void。但是在C中,让括号空着意味着对是否接受参数保持沉默。

有些程序员还会使用这种函数头并省略返回语句:

void main()

但是由于这种写法不是当前标准强制的选项,因此在某些系统上不能工作。因此应当尽量避免这种格式。

iostream文件

iostream中的io指的是输入(进入程序的信息)和输出(从程序中发送出去的信息)。使用cin和cout进行输入输出的程序必须包含文件iostream。

头文件名

C语言的传统是,头文件使用扩展名h。而C++头文件则没有扩展名。

头文件类型约定示例说明
C++旧式风格以.h结尾iostream.hC++程序可以使用
C旧式风格以.h结尾math.hC、C++程序可以使用
C++新式风格没有扩展名iostreamC++程序可以使用,使用namespace std
转换后的C加上前缀c,没有扩展名cmathC++程序可以使用,可以使用不是C的特性,如namespace std

名称空间

如果使用iostream,而不是iostream.h,则应使用下面的名称空间编译指令来使iostream中的定义对程序可用:

using namespace std;

这叫作using编译指令。

名称空间的支持是C++的一项特性。想象一下,当有两个已经封装好的产品,它们都包含一个名为wanda()的函数,这样,使用wanda()函数的时候编译器就不知道指的是哪个版本。名称空间就可以用来指出想使用哪个厂商的产品。

Microflop::wanda("go dacing?");
Piscine::wanda("a fish named Desire");

这意味着在iostream中定义的用于输出的cout变量实际上是std::cout,而endl实际上是std::endl。

所以不偷懒的写法应该是:

#include <iostream>
int main()
{
  // using namespace std;
  std::cout << "Come up and C++ me some time.";
  std::cout << std::endl;
  std::cout << "You won't regret it!" << std::endl;
  return 0;
}

使用cout进行C++输出

cout << string;

<<符号表示该语句将把这个字符串发送给cout。该符号指出了信息流动的路径。

控制符endl

在C++中,std::endl是一个被定义为换行符并刷新输出缓冲区的流插入器。当程序在输出流中使用std::endl时,它会在输出流中插入一个换行符,然后刷新输出缓冲区,确保输出立即显示在屏幕上。

相比之下,使用\n(换行符)只是简单地在输出流中插入一个换行符,但不会强制刷新输出缓冲区。这意味着在某些情况下,输出可能仍然存在于缓冲区中,直到程序继续执行或缓冲区满时才输出到屏幕上,这可能会导致用户在输入信息后才看到提示。

因此,在需要确保输出立即显示在屏幕上的情况下,建议使用std::endl而不是\n。

C++源代码的格式化

在C++中,分号标示了语句的结尾。因此,在C++中,回车的作用和空格或制表符相同。

不能把空格、制表符或者回车放在元素(比如名称)中间,也不能把回车放在字符串中间。

一行代码中不可分割的元素叫作标记(token)。

基本要求:

  • 每条语句占一行

  • 每个函数都有一个开始花括号和一个结束花括号,这两个花括号各占一行

  • 函数中的语句都相对于花括号进行缩进

  • 与函数名称相关的圆括号周围没有空白

C++语句

声明语句和变量

int carrots;

声明通常指出了要存储的数据类型和程序对存储在这里的数据使用的名称。

上面这种声明语句也叫做定义声明语句,简称定义。但是声明不一定是定义。

在C++中,尽可能在首次使用变量前声明它。

其他C++语句

类是C++中面向对象编程(OOP)的核心概念之一。

类之于对象就像类型之于变量。也就是说,类定义描述的是数据格式及其用法,而对象则是根据数据格式规范创建的实体。换句话说,如果说类就好比所有著名的演员,则对象就好比某个著名的演员。

第三章 处理数据

命名方案

很多程序员可能会在变量名中加入其他的信息,即描述变量类型或内容的前缀。例如,nMyWeright,前缀n用来表示整数值。还有str或s表示以空字符结束的字符串、b表示布尔值、p表示指针、c表示单个字符、m_表示一个类的成员值。

符号常量——预处理器方式

#define 编译指令的工作方式与文本编辑器或字处理器中的全局搜索并替换命令相似。#define 编译指令是C语言遗留下来的。C++有一种更好的创建符号常量的方法(使用关键字const),所以不会经常使用#define。

初始化

int emus{7};  // set emus to 7

无符号类型

unsigned 本身是 unsigned int 的缩写。

选择整型类型

如果没有非常有说服力的理由来选择其他类型,则应使用int。

假设要将程序从int为16位的系统移到int为32位的系统,则用于存储int数组的内存量将加倍,但short数组不受影响。请记住,节省一点就是赢得一点。

如果只需要一个字节,可使用char。

整型字面值

C++使用前面1~2位来标识数字常量的基数。

如果第一位为1~9,则为十进制数。

如果第一位为0,则为八进制数。如 int inseam = 042;

如果前两位为0x或者0X,则为十六进制数。如:int waist = 0x42;

char 类型:字符和小整数

char类型是整型。char类型是专为存储字符(如字母和数字)而设计的。它足够长,能够表示目标计算机系统中的所有基本符号——所有的字母、数字、标点符号等。虽然char最常被用来处理字符,但也可以将它用作比short更小的整型。

bool 类型

任何数字值或指针值都可以被隐式转换(即不用显式强制转换)为bool值。任何非零值都被转换为true,而零被转换为false。

const限定符

在C++里面,不要使用#define来定义符号常量,而应使用const。

常量被初始化后,其值就被固定了,编译器就不允许再修改该常量的值。

常量的命名(不成名的规则):

  • 或一般首字母大写;

  • 或一般全字母大写;

  • 或以字母k开头。

浮点数

浮点数能够表示小数值、非常大和非常小的值。如果数字很大,无法表示为long类型,则可以使用浮点类型来表示。

有一种浮点值的表示方法,叫作E表示法。3.45E6就是3.45x10^6。8.33E-4就是8.33x10^(-4)。

d.dddE+n 指的是将小数点向右移n位,而d.dddE-n指的是将小数点向左移n位。之所以称为“浮点”,就是因为小数点可移动。

对于float,C++只保证6位有效位。

浮点类型

C++有3种浮点类型:float、double和long double。这些类型是按它们可以表示的有效数位和允许的指数最小范围来描述的。有效位是数字中有意义的位。另外,这三种类型的指数范围至少是-37到37.

auto声明

auto是一个C语言关键字,它可以让编译器能够根据初始值的类型推断变量的类型。

第四章 复合类型

字符串

C-风格字符串具有一种特殊的性质:以空字符结尾,空字符被写作\0,其ASCII码为0,用来标记字符串的结尾。

char dog[8] = { 'b', 'e', 'a', 'u', 'x', ' ', 'I', 'I'};  // not a string
char cat[8] = { 'f', 'a', 't', 'e', 's', 's', 'a', '\0'}; // a string

字符串常量:

char bird[11] = "Mr. Cheeps";   // string
char fish[] = "bubbles";        // string
char ch = 'M';                  // char
  • 用引号括起来的字符串隐式地包括结尾的空字符,因此不用显示地包括它。

  • 初始化字符串的时候应确保数组足够大,能够存储包括空字符以内的所有字符。让数组比字符串长没有什么害处,只是会浪费一些空间而已。这是因为处理字符串的函数根据空字符的位置,而不是数组长度来进行处理。C++对字符串长度没有限制。

  • 字符串常量(使用双引号)不能与字符常量(使用单引号)互换。

  • 有时候,字符串很长,无法放到一行中。C++允许拼接字符串字面值,即将两个用引号括起的字符串合并为一个。事实上,任何两个由空白(空格、制表符和换行符)分隔的字符串常量都将自动拼接成一个。因此,下面所有的输出语句都是等效的:

cout << "I'd give my right arm to be" " a great violinist.\n";

cout << "I'd give my right arm to be a great violinist.\n";

cout << "I'd give my right ar"
"m to be a great violinist.\n";

string 类

string类扩展了C++库,因此现在可以用string类型的变量,而不是字符数组来存储字符串。要使用string类,必须在程序中包含头文件string。

#include <string>
#include <iostream>

int main()
{
  string str1;
  string str2 = "jaguar";

  cin >> str1;
}
  • string对象和字符数组之间的主要区别是,可以将string对象声明为简单变量,而不是数组。类设计让程序能够自动处理string的大小。例如上面的程序中,str1的声明创建了一个长度为0的string对象,但程序将输入读取到str1中时,将自动调整str1的长度。这使得与使用数组相比,使用string对象更方便,也更安全。从理论上说,可以将char数组视为一组用于存储一个字符串的char存储单元,而string类变量是一个表示字符串的实体。

  • 使用string类时,某些操作比使用数组时更简单。例如,不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象。

char charr1[20];
char charr2[20] = "jaguar";

string str1;
string str2 = "panther";

str1 = str2;
  • string类简化了字符串合并操作。可以使用运算符+将两个string对象合并起来,还可以使用运算符+=将字符串附加到string对象的末尾。

Powered by VitePress