【经典书籍】C++ Primer 第1到6章详细讲解

C++ Primer前六章核心解析

C++ Primer 第1到6章详细讲解

第1章 开始

1.1 编写一个简单的C++程序

  • 程序结构:每个C++程序都包含一个或多个函数,其中必须有一个名为main的函数

  • 基本形式

    #include <iostream>
    int main() {
        std::cout << "Hello, World!" << std::endl;
        return 0;
    }
    
  • 关键点

    • #include是预处理指令,用于包含头文件

    • int main()是程序入口点

    • std::cout是标准输出流

    • <<是流插入运算符

    • std::endl是行结束符,会刷新输出缓冲区

    • return 0;表示程序正常结束

1.2 初识输入输出

  • 标准输入输出对象

    • std::cin:标准输入(通常是键盘)

    • std::cout:标准输出(通常是显示器)

    • std::cerr:标准错误(无缓冲)

    • std::clog:标准日志(有缓冲)

  • 输入操作

    int v1 = 0, v2 = 0;
    std::cout << "Enter two numbers: " << std::endl;
    std::cin >> v1 >> v2;
    std::cout << "The sum of " << v1 << " and " << v2 
              << " is " << v1 + v2 << std::endl;
    
  • 命名空间std是标准库的命名空间,使用::作用域运算符访问其中的名称

1.3 注释简介

  • 单行注释:以//开始,到行尾结束

  • 多行注释:以/*开始,以*/结束,可以跨越多行

1.4 控制流

  • while循环

    int sum = 0, val = 1;
    while (val <= 10) {
        sum += val; // 等价于 sum = sum + val
        ++val;      // 前置递增运算符
    }
    
  • for循环

    int sum = 0;
    for (int i = 1; i <= 10; ++i) {
        sum += i;
    }
    
  • if语句

    if (condition) {
        // 条件为真时执行
    } else {
        // 条件为假时执行
    }
    

1.5 类简介

  • Sales_item类:表示C++程序设计中书籍销售的数据

  • 使用类

    #include <iostream>
    #include "Sales_item.h"
    int main() {
        Sales_item book;
        std::cin >> book;
        std::cout << book << std::endl;
        return 0;
    }
    
  • 关键点

    • 类定义了数据成员和成员函数

    • 使用类需要包含相应的头文件

    • 类对象可以像内置类型一样使用输入输出运算符

第2章 变量和基本类型

2.1 基本内置类型

  • 算术类型

    • 整型

      • bool:布尔类型(true/false)

      • char:字符(1字节)

      • wchar_t:宽字符

      • char16_t/char32_t:Unicode字符

      • short:短整型(至少16位)

      • int:整型(至少16位)

      • long:长整型(至少32位)

      • long long:长长整型(至少64位,C++11引入)

    • 浮点型

      • float:单精度浮点数(通常32位)

      • double:双精度浮点数(通常64位)

      • long double:扩展精度浮点数

  • 类型大小:使用sizeof运算符获取类型占用的字节数

    std::cout << "int size: " << sizeof(int) << " bytes" << std::endl;
    
  • 带符号与无符号类型

    • signedunsigned可以修饰整型

    • unsigned只能表示非负值,范围是0到正数最大值

    • 默认情况下,intshortlonglong long是带符号的

2.2 变量

  • 变量定义:类型说明符 + 一个或多个变量名(用逗号分隔)+ 分号

    int sum = 0, value;
    
  • 初始化:变量在创建时获得一个初始值

    • 列表初始化(C++11):使用花括号

      int units_sold{0};
      int units_sold = {0};
      
    • 直接初始化:使用圆括号

      int units_sold(0);
      
    • 拷贝初始化:使用等号

      int units_sold = 0;
      
  • 变量声明与定义

    • 定义:为变量分配存储空间,可能初始化

    • 声明:使名字为程序所知,使用extern关键字且不分配存储空间

      extern int i;     // 声明i但不定义i
      int j;            // 声明并定义j
      
  • 标识符:变量、函数和其他实体的名称

    • 只能由字母、数字和下划线组成

    • 必须以字母或下划线开头

    • 区分大小写

    • 不能使用关键字作为标识符

2.3 复合类型

  • 引用:对象的别名(C++中引用必须初始化且不能改变绑定的对象)

    int ival = 1024;
    int &refVal = ival;  // refVal指向ival
    int &refVal2;        // 错误:引用必须初始化
    
  • 指针:存储内存地址的变量

    int ival = 42;
    int *p = &ival;  // p指向ival,&是取地址运算符
    cout << *p;      // *是解引用运算符,输出42
    
  • 指针和引用的区别

    • 引用必须初始化且不能重新绑定

    • 指针可以不初始化(但不推荐),可以改变指向的对象

    • 引用本身不是对象,没有引用的引用

    • 指针是一个对象,可以有指向指针的指针

  • 空指针

    int *p1 = nullptr;  // C++11引入
    int *p2 = 0;
    int *p3 = NULL;     // 传统方式,实际上是预处理宏
    
  • void指针*:可以指向任意类型对象,但不能直接操作它指向的对象

2.4 const限定符

  • const对象:值不能被修改的变量

    const int bufSize = 512;
    
  • const的特性

    • 必须初始化

    • 默认情况下,const对象仅在文件内有效

    • 要在多个文件中共享const对象,需要在定义和声明前加extern

  • constexpr和常量表达式(C++11):

    • 常量表达式是编译时就能计算出结果的表达式

    • constexpr变量是常量表达式

  • 指针和const

    • 指向常量的指针:const double *cptr

    • 常量指针:double *const ptr

    • 指向常量的常量指针:const double *const ptr

2.5 处理类型

  • 类型别名

    • 使用typedeftypedef double wages;

    • 使用using(C++11):using SI = Sales_item;

  • auto类型说明符(C++11):让编译器根据初始值推断变量类型

    auto item = val1 + val2;  // item的类型是val1和val2相加结果的类型
    
  • decltype类型指示符(C++11):选择并返回操作数的数据类型

    decltype(f()) sum = x;  // sum的类型就是函数f的返回类型
    

2.6 自定义数据结构

  • struct定义

    struct Sales_data {
        std::string bookNo;
        unsigned units_sold = 0;
        double revenue = 0.0;
    };
    
  • 类的定义:在C++中,struct和class基本相同,主要区别在于默认访问权限

第3章 字符串、向量和数组

3.1 命名空间的using声明

  • using声明:使特定标识符可用而不需要加命名空间前缀

    using std::cin;
    using std::cout;
    using std::endl;
    
  • using指示(不推荐过度使用):使命名空间中所有名字都可用

    using namespace std;
    

3.2 标准库类型string

  • 定义和初始化string对象

    string s1;          // 默认初始化,s1是一个空字符串
    string s2(s1);      // s2是s1的副本
    string s3 = s1;     // 等价于s3(s1),s3是s1的副本
    string s4("value"); // s4是字面值"value"的副本,不包括末尾的空字符
    string s5 = "value";// 等价于s5("value")
    string s6(10, 'c'); // s6的内容是cccccccccc
    
  • string对象上的操作

    • os << s:将s写到输出流os当中,返回os

    • is >> s:从is中读取字符串赋给s,字符串以空白分隔,返回is

    • getline(is, s):从is中读取一行赋给s,返回is

    • s.empty():s为空返回true,否则返回false

    • s.size():返回s中字符的个数

    • s[n]:返回s中第n个字符的引用

    • s1 + s2:返回s1和s2连接后的结果

    • s1 = s2:用s2的副本代替s1中原来的字符

    • s1 == s2:如果s1和s2中所含的字符完全一样,则它们相等

    • s1 != s2:比较两个string对象是否不相等

    • <, <=, >, >=:利用字符在字典中的顺序进行比较

  • 处理string对象中的字符

    • 使用基于范围的for循环遍历字符串中的每个字符

    • 使用cctype头文件中的函数处理字符(如isalpha(), isdigit(), tolower()等)

3.3 标准库类型vector

  • 定义和初始化vector对象

    vector<T> v1;                // v1是一个空vector,它潜在的元素是T类型的,执行默认初始化
    vector<T> v2(v1);            // v2中包含有v1所有元素的副本
    vector<T> v2 = v1;           // 等价于v2(v1)
    vector<T> v3(n, val);        // v3包含了n个重复的元素,每个元素的值都是val
    vector<T> v4(n);             // v4包含了n个重复地执行了值初始化的对象
    vector<T> v5{a, b, c...};    // v5包含了初始值数量的元素,每个元素被赋予相应的初始值
    vector<T> v5 = {a, b, c...}; // 等价于v5{a, b, c...}
    
  • 向vector对象中添加元素

    vector<int> v;
    for (int i = 0; i != 100; ++i) {
        v.push_back(i);  // 依次把整数值放到v的末尾
    }
    
  • 其他vector操作

    • v.empty():如果v不含有任何元素,返回真;否则返回假

    • v.size():返回v中元素的个数

    • v.push_back(t):向v的尾端添加一个值为t的元素

    • v[n]:返回v中第n个位置上元素的引用

    • v1 = v2:用v2中的元素拷贝替换v1中的元素

    • v1 = {a, b, c...}:用列表中的元素拷贝替换v1中的元素

    • v1 == v2:v1和v2相等当且仅当它们的元素数量相同且对应位置的元素值都相同

    • !=, <, <=, >, >=:保持这些操作符惯有的含义

3.4 迭代器介绍

  • 使用迭代器

    • beginend运算符:begin成员负责返回指向第一个元素(或第一个字符)的迭代器,end成员负责返回指向容器(或string对象)"尾元素的下一位置"的迭代器

    • 迭代器类型:如vector<int>::iterator it;

    • const_iterator:只能读元素,不能写元素

  • 迭代器运算

    • *iter:返回迭代器iter所指元素的引用

    • iter->mem:解引用iter并获取该元素的名为mem的成员,等价于(*iter).mem

    • ++iter:令iter指示容器中的下一个元素

    • --iter:令iter指示容器中的前一个元素

    • iter1 == iter2:判断两个迭代器是否相等(不相等)

    • iter1 != iter2:判断两个迭代器是否不相等(相等)

3.5 数组

  • 定义和初始化内置数组

    int arr[10];                  // 10个未初始化的int
    int arr[10] = {0,1,2,3,4,5,6,7,8,9}; // 列表初始化
    int arr[] = {0,1,2,3,4,5,6,7,8,9};  // 维度是10的数组
    int arr[5] = {0,1,2};         // 等价于{0,1,2,0,0}
    int arr[4] = {0};             // 所有元素初始化为0
    char arr1[] = {'C', '+', '+'}; // 列表初始化,没有空字符
    char arr2[] = {'C', '+', '+', '\0'}; // 列表初始化,含有显式的空字符
    char arr3[] = "C++";          // 自动添加表示字符串结束的空字符
    const unsigned sz = 3;
    int arr[sz];                  // 错误:不能用变量定义数组维度(C++11之前)
    
  • 访问数组元素:通过下标运算符[]访问

  • 指针和数组

    • 使用数组的时候编译器一般会把它转换成指针

    • 指针也是迭代器:支持递增、递减、解引用等操作

    • 标准库函数beginend(C++11,定义在<iterator>头文件中)可以获取数组的首元素指针和尾后指针

  • C风格字符串

    • C风格字符串存放在字符数组中并以空字符结束('\0')

    • 相关函数定义在<cstring>头文件中:strlen(p)strcmp(p1, p2)strcat(p1, p2)strcpy(p1, p2)

  • 与旧代码的接口

    • 混用string对象和C风格字符串

    • 使用数组初始化vector对象

第4章 表达式

4.1 基础

  • 基本概念

    • 一元运算符:只作用于一个操作数(如-+*(解引用)、&(取地址)、++--

    • 二元运算符:有两个操作数(如+-*/%

    • 运算对象:运算符作用的值

    • 求值顺序:表达式中各个子表达式的计算顺序

    • 优先级:决定运算符的执行顺序

    • 结合律:决定相同优先级的运算符的执行顺序

  • 左值和右值

    • 当一个对象被用作右值的时候,用的是对象的值(内容)

    • 当对象被用作左值的时候,用的是对象的身份(在内存中的位置)

    • 大多数情况下,左值可以当作右值使用,反之则不行

4.2 算术运算符

  • 基本算术运算符+-*/%(取模/求余)

  • 一元正负运算符+-

  • 除法运算:整数相除结果仍是整数,小数部分被截断

  • 取模运算:两个操作数都必须是整数

4.3 逻辑和关系运算符

  • 关系运算符>>=<<===!=

  • 逻辑运算符&&(逻辑与)、||(逻辑或)、`!'(逻辑非)

  • 短路求值:对于&&,如果左侧表达式为假,则不会计算右侧表达式;对于||,如果左侧表达式为真,则不会计算右侧表达式

4.4 赋值运算符

  • 赋值运算符=,具有右结合性

  • 复合赋值运算符+=-=*=/=%=

  • 赋值运算符的要求:左侧运算对象必须是一个可修改的左值

4.5 递增和递减运算符

  • 前置版本++i,先递增再返回递增后的值

  • 后置版本i++,先返回当前值再递增

  • 建议:除非必须,否则不用递增递减运算符的后置版本

4.6 成员访问运算符

  • 点运算符.,用于获取类、结构体或联合体的成员

  • 箭头运算符->,相当于对指针解引用后再使用点运算符(ptr->mem等价于(*ptr).mem

4.7 条件运算符

  • 条件运算符cond ? expr1 : expr2,是C++中唯一的三元运算符

  • 嵌套条件运算符:可以嵌套使用,但可读性会变差

4.8 位运算符

  • 位运算符:作用于整数类型的运算对象,把运算对象看成是固定数量的二进制位

    • ~:位求反

    • &:位与

    • |:位或

    • ^:位异或

    • <<:左移

    • >>:右移

  • 移位运算符:左侧运算对象按右侧运算对象指定的位数移动

4.9 sizeof运算符

  • sizeof运算符:返回一条表达式或一个类型名字所占的字节数

    • sizeof(type)

    • sizeof expr

4.10 逗号运算符

  • 逗号运算符:含有两个运算对象,按照从左向右的顺序依次求值,首先对左侧的表达式求值,然后丢弃求值结果,真正的结果是右侧表达式的值

4.11 类型转换

  • 隐式类型转换

    • 算术转换:在混合类型的表达式中,较小类型的运算对象会被转换成较大的类型

    • 其他隐式转换:数组转换成指针、指针的转换、表达式转换成布尔类型等

  • 显式转换(强制类型转换):

    • static_cast:用于良性转换,如基本数据类型之间的转换

    • const_cast:用于删除const性质

    • reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释

    • dynamic_cast:支持运行时类型识别(本书不介绍)

第5章 语句

5.1 简单语句

  • 表达式语句:表达式后面跟一个分号

  • 空语句:只有一个分号,表示什么也不做

  • 复合语句(块):用花括号括起来的语句和声明的序列,也称为块

5.2 语句作用域

  • 在if、switch、while和for语句的控制结构内定义的变量,只在相应语句的内部可见

5.3 条件语句

  • if语句

    if (condition) 
        statement
    else 
        statement
    
  • switch语句

    switch (expression) {
        case value1: statement(s); break;
        case value2: statement(s); break;
        ...
        default: statement(s);
    }
    
    • break语句:用于中断switch语句的执行

    • default标签:当没有匹配的case时执行

5.4 迭代语句

  • while循环

    while (condition)
        statement
    
  • 传统的for循环

    for (init-statement; condition; expression)
        statement
    
  • 范围for循环(C++11):

    for (declaration : expression)
        statement
    
  • do while循环

    do
        statement
    while (condition);
    

5.5 跳转语句

  • break语句:终止离它最近的while、do while、for或switch语句,并从这些语句之后的第一条语句开始继续执行

  • continue语句:结束本次循环,跳过循环体中尚未执行的语句,接着执行下一次循环

  • goto语句:无条件跳转到同一函数内的另一条标号语句(不推荐使用)

5.6 try语句块和异常处理

  • throw表达式:引发异常,执行throw类似于执行了一个返回语句,但它不返回任何值而是抛出一个异常

  • try语句块

    try {
        program-statements
    } catch (exception-declaration) {
        handler-statements
    } catch (exception-declaration) {
        handler-statements
    } 
    
  • 标准异常:C++标准库定义了一组类,用于报告在标准库函数中遇到的问题

第6章 函数

6.1 函数基础

  • 函数的定义:返回类型、函数名字、由0个或多个形参组成的列表以及函数体

    返回类型 函数名(参数列表) {
        函数体
    }
    
  • 形参和实参

    • 形参:函数定义时声明的参数

    • 实参:函数调用时传递的参数

  • 函数调用:包括函数名和括号括起来的实参列表

  • 局部对象

    • 自动对象:普通局部变量,只存在于块执行期间的对象

    • 静态局部对象:使用static关键字声明,在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁

  • 函数声明:函数的三要素(返回类型、函数名、形参类型)可以单独声明,通常放在头文件中

    返回类型 函数名(参数类型1, 参数类型2, ...);
    
  • 分离式编译:允许将程序分割为多个文件

6.2 参数传递

  • 传值参数:函数对形参做的所有操作都不会影响实参

  • 传引用参数:使用引用形参可以直接操作实参,避免拷贝

    void reset(int &i) {
        i = 0;
    }
    
  • const形参和实参:顶层const不影响传入函数的对象,一个拥有底层const的形参无法使用普通实参初始化

  • 数组形参:数组的两个特殊性质(不允许拷贝数组、使用数组时会将其转换成指针)使得我们不能以值传递的方式使用数组参数,通常使用指针或引用传递数组

  • main函数的参数int main(int argc, char *argv[])int main(int argc, char **argv)

6.3 return语句

  • 无返回值函数:返回类型是void的函数

  • 有返回值函数:返回类型不为void的函数,必须使用return语句返回一个值

  • 值是如何被返回的:返回一个值的方式和初始化一个变量或形参的方式完全一样

  • 返回数组指针:可以使用类型别名、尾置返回类型或decltype简化返回数组指针的函数声明

6.4 函数重载

  • 重载函数:同一作用域内的几个函数名字相同但形参列表不同

  • 区分重载函数:编译器根据函数调用中实参的类型推断应该调用哪个函数

  • const重载:顶层const不影响传入函数的对象,底层const可以用于区分重载函数

  • 调用重载函数:名字查找发生在类型检查之前

6.5 特殊用途语言特性

  • 默认实参:为形参提供默认值,调用函数时可以省略这些形参

    string screen(sz ht = 24, sz wid = 80, char backgrnd = ' ');
    
  • 内联函数和constexpr函数

    • 内联函数:建议编译器在调用点"内联地"展开函数体,避免函数调用的开销

    • constexpr函数:可以用于常量表达式的函数,函数体中必须有且只有一条return语句(C++11起有所放松)

  • 调试帮助:使用预处理器定义NDEBUG来禁用assert宏

6.6 函数匹配

  • 函数匹配过程:确定候选函数和可行函数,然后从可行函数中选择最佳匹配,或者由于没有最佳匹配而报错

  • 实参类型转换:为了匹配候选函数,实参可能需要进行类型转换

6.7 函数指针

  • 函数指针:指向函数的指针,其类型由函数的返回类型和形参类型共同决定

    bool (*pf)(const string &, const string &); // 未初始化的函数指针
    pf = lengthCompare; // pf指向名为lengthCompare的函数
    pf = &lengthCompare; // 等价的赋值语句,取地址运算符是可选的
    bool b1 = pf("hello", "goodbye"); // 通过指针调用函数
    bool b2 = (*pf)("hello", "goodbye"); // 等价的调用
    bool b3 = lengthCompare("hello", "goodbye"); // 直接调用函数
    
  • 函数指针形参:可以用函数指针作为形参,调用这样的函数时,既可以传递函数名,也可以传递函数指针

  • 返回函数指针:函数可以返回函数指针,使用类型别名或尾置返回类型可以使声明更清晰


以上是对《C++ Primer》第1到6章的非常详细讲解。这些章节涵盖了C++编程的基础知识,包括基本语法、变量和基本类型、标准库类型、表达式、语句和函数。掌握这些内容对于进一步学习C++至关重要。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值