C++ Primer Part I, 语言基础,2-7章

前言

使用类,需要知道:类名,在哪里定义,支持的操作。定义的地方我没有想过。
一门语言的语法特征:内置类型、变量、表达式和语句、控制流、函数。
基本特征的补充:自定义数据、封装成库函数

章节

2- Variable and Basic Type

基本内置类型
  1. 数据类型:数据的意义和能执行的操作
  2. sizeof(int) sizeof(long) 我电脑上都是4,longlong是8,这个一直有点懵
  3. 类型转换:浮点数->int,保留整数部分,不近似
  4. 类型转换:无符号类型->超过范围的值,取模后的余数,例(-1赋给unsign char[0,255],结果256)
  5. 类型转换:无符号类型->超过范围的值,无定义
  6. 指定字面值的类型:加前后缀。prefix(u U L u8),suffix(u/U l/L ll/LL f/F l/L)
变量
  1. 变量提供一个可具名、可供程序 操作的存储空间。平时说明变量是什么总是模模糊糊的不够具体。用“可供程序操作”“存储空间”感觉很形象
  2. 对象:能存储数据并具有某种数据类型的内存空间
  3. 初始化 VS 赋值:创建时赋值;擦除当前值,用新值代替
  4. 声明 VS 定义:多次定义,一次声明;声明规定类型和名字(使用别处的定义的名字),定义创建实体;声明而不定义使用extern,不要初始化extern标记的变量;给extern初始化则抵消了extern的作用
  5. 不太了解的关键字:alignas alignof decltype reinterpret_cast typeid mutable explicit volatile thread_local
  6. sizeof 是关键字不是函数!!! 函数和关键字,如何区别?
  7. C++ 操作符替代名and bitand compl not_eq or_eq xor_eq and_eq bitor not or xor
复合类型
  1. 基于其他类型定义的类型,介绍引用和指针
  2. 引用一般指左值引用,C++11定义了右值引用
  3. 引用必须初始化的原因:定义时与初始值绑定在一起,初始化完成后也一直绑定在一起,无法重新绑定到另外一个对象。[编译器如何实现?]
  4. 指针 VS 引用:指针是指向另外一种类型的复合类型,存放某个对象的地址,使用时用取地址符(&),解引用符(*)得到指向的对象。
    1. 本身是变量,可复制 拷贝 先后指向多个对象
    2. 无须在定义时赋初值
  5. 指针初始化 (NULL) (C++11 字面值nullptr )
  6. 指针指向引用可以有;但是引用不是对象,所以不存在指向引用的指针
const 限定符
  1. 默认状态下,const对象仅在文件内有效:编译过程会替换成对应值;如果要在文件间共享,则声明/定义都要添加extern
  2. 引用类型必须与其所引用对象的类型一致,有两个例外
    a. 初始化常量时可以用任意表达式做为初始值,只要改表达式结果能转化所引用的类型。
    —-编译器会创建临时变量tmp进行类型转换,const是绑定到这个临时变量上的
    b. 对const的引用可能引用一个并非const的对象
  3. 指向常量的指针不能改变所指对象的值,指针能不能修改其所指对象的值取决于所指对象的类型
  4. 只有指向常量的指针才能存放常量对象的地址
  5. const double *const pip = &pi 从右到左阅读,离pip最近的是const,则pip是常量指针,double左边是const,则pip指向的是double常量对象
  6. 顶层const(top-level)指指针本身是常量(int const pi),底层const(low-level)指所指对象是常量(const int pi)
  7. 拷贝操作,拷入拷出的对象必须具有相同的底层const资格,或者可以转换,一般非cosnt可以转换成const,反之不可
  8. constexpr修饰常量表达式则编译过程发现初始值不是常量表达式则报错
  9. constexpr修饰指针,仅对指针有效,对其所指对象无效
处理类型
  1. 类型别名(type alias)
    1. typedef double base , * p; // base是double别名,p是double * 别名
    2. using SI = Sales_item; // SI是Sales_item的别名
    3. 声明后成为基本数据类型,包含复合类型(常量 指针)时,直接替换后理解容易出错
typedef char *pstring;         // pstring 成基本数据类型
const pstring cstr = 0 ;       // cstr是 指向char的常量指针

// 因为pstring是基本数据类型,所以const修饰是pstring(指针)
// 如果替换成const char* 则const char是基本数据类型,两种意义截然不同
  1. (C++11) auto类型说明符,编译器根据初始值判断类型。底层const不会被忽略,而顶层const会被忽略,如需保持则const auto
  2. (C++11) decltype 类型指示符,返回数据类型。 decltype(f()) sum = x;sum的类型时函数的返回类型,顶层const不会被忽略。引用从来都是作为其同义词出现,只有这里是例外(引用对象返回的就是引用类型)
  3. 加括号是表达式,得到引用decltype((i)) a 得到int&类型
自定义数据结构

3- String, Vector, and Array

Primer第四版没有vector,头文件不应该包含using,因为头文件会被拷贝到引用它的文件中,会不经意包含了一些名字

string vector
  1. 不常用的初始化: string s(n,'c') 连续n个c字符
  2. getline(is, s):从输入流读一行给s,换行符也读进去了,但是存到s中时没有存换行符。
  3. ?返回值?。segmentfault有回答过一个读一行的方法,连接
  4. string::size_type :size()方法的返回类型,为什么不是int呢?
  5. cctype 中的函数
迭代器
数组
  1. 复杂的定义从内向外阅读
int (* Parray) [10] = &arr;  // Parray指向一个含有10个整数的指针
int (& arrRef) [10] = arr;   // arrRef引用一个含有10个整数的指针

// 由内向外,首先arry是一个引用,
// 由右边:arry引用的对象是大小为10的数组
// 由左边:数组元素是指向int的指针
  1. 使用数组下标通常定义为size_t,与机器相关的无符号类型,能存放内存中任意对象的大小。定义在<cstddef>
  2. 像迭代器一样使用数组指针,获得尾后迭代器
    1. int *end = &arr[n] arr[n]是不存在的元素,但是可以获取地址,计算方式是arr右移n位
    2. C++11<iterator>定义了begin() end()函数,参数是数组指针
多维数组

4- Expressions

  1. *pbeg++ 等价于 *(pbeg++)解引用是原先pbeg指的值,pbeg右移一位后,返回初始值的副本。
  2. sizeof 运算符返回表达式或类型名字所占字节数。
sizeof (type)
sizeof expr     // 返回表达式结果类型的大小,但并不计算其运算对象的值 
  1. 隐式类型转换,算法表达式中,unsigned intintint会转化成unsigned int
  2. 显示转换:static_cast dynamic_cast const_cast reinterpret_cast

5- Statements 语句

1 C++11 引用范围for语句(range for statement),

for (declaration : expression)
    statement

// expression 是序列或者容器,declaration是变量,序列中每个元素都可以转化成declaration
// 用auto确保类型相容,最简单
// 如果要对元素进行读写,引用

vection<int> v={0,1,2,3}
for (auto &r : v){
    r *= 2;
}

2 异常处理包括throw表达式、try语句块、一套异常类(用于传递throw和try子句信息)

6- Functions

  • 函数定义和声明、参数传递和结果返回;
  • 函数重载
  • 特殊用途语言特性(inline、默认参数、constexpre函数)
  • 函数匹配
  • 函数指针
参数传递
  1. 传值参数
    1. 拷贝一份副本,不会影响原来实参的值
    2. 指针形参,拷贝的是指针的值,两个指针不同,但所指的对象相同,可以间接访问修改它所指的对象
  2. 传引用参数
    1. 引用实际上是作用在引用所引的对象上,引用形参类似,可以让函数修改实参的值
    2. 避免拷贝,变量不修改形参值时最好用常量引用
    3. 返回额外信息,把要返回的信息作为参数
  3. const形参和实参:顶层const在实参初始化时被忽略,所以 …
void fun(int);
void fun(const int);  // error: 重定义
  1. 数组形参:作为指针传入,管理方式三种

    1. 数组本身包含一个标记,如C风格字符串的’\0’
    2. 使用标准库规范,传递数组首元素和尾后元素指针

      void print(const int *beg, const int *end)
    3. 显示传递数组大小的形参

      void print(const int ia[], size_t size)
    4. 数组引用形参

      void prinf(int (&arr)[10])
      {
          for (auto elem : arr)
              cout << elem << endl;
      }
  2. main:处理命令行参数,main(int argc, char **argv)(int argc, char *argv[])

  3. 可变形参
    1. 实参类型相同,传递标准库类型initializer_list
    2. 实参类型不同,可变参数模板,在16.4节介绍
  4. 不要返回局部对象的指针或引用,内存空间在函数结束用就被释放
  5. 返回数组指针,数组不能被拷贝,不能返回数组,但是可以返回数组的指针或引用。

    1. 类型别名

      typedef int arrT[10];     // 类型别名,表示的类型是含有10个整数的数组
      using arrT = int[10];     // 同上,等价
      
      arrT* func(int i);        // 函数返回一个纸箱含有10个int的数组的指针 
    2. 直接声明

      int (* func(int i)) [10];     // 由内向外阅读  
      
      func(int i)                 //  函数参数
      (*func(int i))              // 可以对函数调用的结果进行解引用操作
      (*func(int i))[10]          // 表示解引用func的调用将得到一个大小是10的数组
      int (* func(int i)) [10];   // 表示数组元素是int 
    3. 尾置返回类型 C++11

      auto func(int i) -> int(*)[10];
    4. 使用decltype
      已经确定函数返回的指针将指向哪个数组

    int odd[]={1,3,5};
    int even[]={2,4,6};
    
    decltype(odd) *arrPtr(int i){  // decltyep 返回的是数组,没有转化成指针
      return (i%2)? &odd : &even; 
    }
函数重载
  1. 名字相同,形参列表不相同(编译器根据实参类型推断使用的函数
  2. 名字和形参相同,返回类型不同的不是重载,引起重定义错误
  3. 顶层const会被忽略
  4. const_cast:有两个函数版本,一个参数是const引用,一个不是;可以在非常量引用版本里强制将参数转化成const,然后调用const函数版本

    const string &func (const string &str);           // 版本1
    
    string &func (string &str){                       // 版本2
        auto &r = func(const_cast<const string&> str)
        return const_cast<string&> (r);     
    }
  5. 调用函数重载,三种可能结果

    1. 找到一个实参最佳匹配
    2. 错误:无匹配
    3. 错误:有多于一个函数可以匹配,但都不是最佳匹配,二义性选择
      void func(int, int);
      void func(double, double);
      
      // 函数调用
      func(1, 2.1);     // 二义性错误,见函数匹配一节
  6. 重载与作用域,如果外面有一个函数名func,局部有变量int func,局部作用域内int func会覆盖掉函数;但是若在局部声明函数后,函数名func会覆盖掉变量int func
特殊用途语言特性(inline、默认参数、constexpre函数)
  1. 默认参数,不能修改已有默认参数值,但声明可以添加默认参数

    void func(int x,int y=1);      // 原来的
    void func(int x=1,int y);      // 正确
    void func(int x,y=2);          // 错误,不能添加默认实参
  2. constexpr函数:返回类型及参数都是常量,函数体只有一条return语句

    constexpr int func(int cnt) { return 3*cnt; }    // 返回值可以不是常量
    // 使用时,传进去的实参cnt要const类型
  3. 调试帮助
    要屏蔽掉调试代码,两种与处理功能:assert和NDEBUG
    1. assert(expr) expr为假则程序终止运行,用于检查不能发生的条件
    2. NDEBUG预处理变量
      如果用#define定义了NDEBUG,则assert不执行运行检查,默认是执行的
    3. C++定义的有助于调试的变量(字符串字面值)
    4. __func__ 每个函数都有,函数名
    5. __FILE__ 文件名
    6. __LINE__ 行号
    7. __TIME__ 编译时间
    8. __DATE__ 编译日期
函数匹配
  1. 步骤1:选定重载函数集,集合中的是候选函数 (函数名相同、声明在调用点可见)
  2. 步骤2:考察实参,选出可行函数 (形参数量和实参相等,类型匹配或可转换)
  3. 步骤3:寻找最佳匹配,如果没有任何一个函数脱颖而出,则引发二义性调用的错误,如上述默认参数的例子
    1. 对每个实参的匹配都不劣于其他可行函数
    2. 至少有一个实参的匹配优于其他函数
  4. 实参类型转换,优先级:

    1. 精确匹配
    2. 类型完全相同
    3. 实参从数组或函数类型转换成对应的指针类型
    4. 向实参添加或删除顶层const
    5. 通过cosnt转换
    6. 类型提升
    7. 算术类型转换或指针转换
    8. 类类型转换
    函数指针

    声明:直接用指针代替函数名即可bool (*func)(int); // 未初始化

  5. 使用
    将函数名作为一个值使用时自动转换成指针

    pf = &func;            // func() 是函数,参数和pf的参数必须精确匹配
    pf = func;
                           // 调用函数
    pf();
    (*pf)(); 
  6. 作为形参
  7. 作为函数返回值
  8. 将auto和decltype用于函数指针类型

7- Class

  • 定义抽象数据类型
    1. this 是一个常量指针,不能改变this保存的地址
    2. 成员函数参数列表后紧跟的const表示this是一个指向常量的指针,该成员函数被称作常量成员函数
    3. 常量对象、常量对象的引用或指针只能调用常量成员函数
    4. 用 =default 显示声明默认构造函数
  • 访问控制与封装
  • 其他特性

    1. mutable ,可变数据成员,即使在const对象内也能被修改
    2. 类内初始值,用=初始化
    3. 友元
    4. 类之间的友元关系
    5. 成员函数作为友元,要明确指出该成员函数属于哪个类
     class A{ friend void B::func()}
     // 先声明B,声明函数,定义函数
    1. 函数重载和友元,要把一组重载函数作为友元,每一个函数都要分别声明
    2. 友元声明和作用域
  • 作用域
  • 构造函数

    1. 初始值列表:根据定义的顺序初始化
    2. 防止构造函数隐式转换,explicit,只对一个实参的构造函数有效,只能在类内部定义;只能用于直接初始化,不支持拷贝(=)形式的初始化
    3. 聚合类(aggregate) 用户可以直接访问成员,struct,要求
      a. 所有成员public
      b. 没有定义任何构造函数
      c. 没有类内初始值
      d. 没有基类,没有virtual函数
    4. 字面值常量类
  • 静态成员

    1. 类的静态成员存在于任何对象之外,对象中也不包含任何静态成员相关数据
    2. 类似的,静态函数不与任何对象绑定,不包含this指针,不能声明为const(const是对this的修饰),函数内不能使用const;
    3. 必须在类的外部定义和初始化成员静态成员,static只在类内部声明,在外部定义不需要
    4. 可以是public或private,可以是常量、引用、指针

-如何让一段程序崩溃? 给空指针赋值
-疑问:调试时添加打印语句,打印语句应该一直保持刷新流,否则如果程序崩溃,输出还可能留在缓冲区,导致崩溃位置的错误推断??

—————————记事—————————
啊哈哈哈隔了好几天断断续续,还写完了
之前断断续续看Primer,用脑袋编译哈哈,这次准备敲代码了。
使用mingw g++编译

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值