Myintelex

  • 主页
  • 所有文章
  • 标签云
  • 个人简历

Myintelex

Myintelex

  • 主页
  • 所有文章
  • 标签云
  • 个人简历

C++学习笔记(一)——基础知识

2017-02-21

因为 C++ 的很多东西还是从 C 语言中来的,所以可能这个地方相对总结的比较简单。第一篇是基础知识。

C++的总体知识大致分为五类:

  1. 算术类型
  2. 复合类型
  3. 函数使用
  4. 逻辑关系
  5. 内存空间
  6. 标准类库

一、算术类型

C++ 的基本类型只有两类:整数 和 浮点数。

  • 整型有下面几类short, int, long, long long, char, wchar_t, char16_t, char32_t
  • 浮点型有下面几类float, double, long double

1.1 整形和浮点型

  1. 相应的整形宽度设置为:

    • short 至少16位
    • int 至少与 short 一样长
    • long 至少32位,且至少与 int 一样长
    • long long 至少64位,且至少与 long 一样长
  2. wchar_t 用来处理无法用8位来表示的字符集,它的长度由系统的选择决定。

  3. char16_t 和 char32_t 和 wchar_t 一样是用来处理无法用8位来表示的字符集的。
  4. bool是一种新的类型,任何非零数值可以被隐式转换为true,0被隐式转换为false。

1.2 算术运算符

算术运算符包含我们常用的加减乘除,另外还有一个取模。其中需要注意的知识点有:

  1. 自动转换,C++ 会自动执行很多的自动转换:

    • 将一种算术类型的值赋给另一种算数类型时,C++将对值进行转换
    • 表达式中包含不同类型的时候,C++将对值进行转换
    • 将参数传递给函数的时候,C++将对值进行转换
    • 较大的浮点型转换为较小的浮点型或整形的时候,如果超出目标类型的取值范围,结果是不确定的
    • 较大的整形转换为较小的整形,超出目标类型的取值范围,通常只复制右边的字节
  2. 使用{}进行初始化称为列表初始化(list-initialization),列表初始化不允许缩窄,如将 int 型赋值给 char 型

  3. 在计算表达式时,C++自动将 bool, char, short 的值转换为 int。
  4. 强制类型转换可以使用两种方式,还有四个强制类型转换符 dynamic_cast, const_cast, static_cast, reinterpret_cast,具体的介绍在这里不详细描述。
    • (typeName) value
    • typeName (value)

二、复合类型

C++中的复合类型既包括 C 中的数组、字符串、结构体、共用体、枚举、指针,又包含新的类等。

2.1 数组

数组的初始化有以下规则

  • 只有在定义数组的时候才可以使用初始化
  • 初始化数组的时候,提供的值可以小于数组的元素数目
  • 如果只对数组的一部分进行初始化,则其他部分初始化为0
  • 如果初始化的时候没有标明数组的元素个数,则自动计算提供的值的数目为数组元素个数
  • 可以使用列表初始化来初始化数组,此时可以省略等号,当列表为空时,自动把所有元素设为0

2.2 字符串

C++中的字符串有两种:C-风格字符串和 string 类。

  • C-风格字符串以\0结尾
  • 任何两个由空白分割的字符串会自动拼接成一个
  • C-风格字符串和 string 对象都可以使用列表初始化
  • string 可以使用 + += 等运算符,并可以直接将一个 string 对象赋给另一个 string 对象。
  • 进行行读取的时候,C-风格字符串使用 cin.getline(str, 20),而 string 类使用 getling(cin, str);

字符串的输入:

  • cin使用空白(空格、制表符和换行符)来确定字符串结束的位置。
  • getline()通过回车键来确定输入结尾但不保存并丢弃回车符。
  • get()带参数通过回车键来确定输入结尾,但将回车符留在输入队列中。
  • get()不带参数读取一个字符。
  • 混合输入数字和字符的时候,<<读取数字后会把回车留在输入队列中。

2.3 结构、共用体、枚举

  • C++中结构声明定义了一种新的类型,使用时可以省略 struct,但 C 中不行。
  • C++允许指定占用特定位数的结构成员,可以使用没有名称的字段来提供间距。
  • 可以将一个结构赋给另一个结构
  • 枚举提供了一种创建符号常量的方式,可以替代const。
  • 枚举没有算术运算符
  • 枚举默认情况下第一个元素为0,后续累加

2.4 指针

  • 使用 new 来分配内存
  • 只能使用 delete 来释放使用 new 分配的内存
  • 使用 new 创建动态数组,需要使用 delete[] 来释放
  • 指针的其他使用方式和C指针一致

三、逻辑关系

和C一样,C++的逻辑关系也有循环和分支两种,其中的注意点有:

  • C++允许在循环中定义变量,且变量只在循环内有效。
  • 递增和递减使用前缀格式的效率更高

四、函数使用

创建自己的函数,需要处理三个方面:

  • 提供函数定义
  • 提供函数原型
  • 调用函数

4.1 函数参数

  • 数组(当且仅当)作为参数使用,和指针含义一样
  • const 尽可能多的使用
  • 使用数组名和超尾作为参数,来表示一个数组

4.2 函数指针

对于一个函数double pam(int)
相应的函数指针定义为 double (*pf)(int)
使用函数指针调用函数为 double ret = (*pf)(5) 或 double ret pf(5)

4.3 内联函数

内联函数运行速度稍快,但是占用内存较多
使用内联函数:

  • 在函数声明前加 inline
  • 在函数定义前加 inline

4.4 引用变量

引用变量是已定义变量的别名。

使用引用参数的原因:

  • 能够修改函数中的数据对象
  • 能够提高程序的运行速度

使用时需要注意以下要点:

  • 必须在声明引用的同时初始化
  • 使用 const 进行常量引用,避免在函数中修改原有信息
  • 引用变量不能使用表达式传参
  • 引用参数是 const 的时候,在下面的两种情况下,将生成临时变量
    • 实参的类型正确,但不是左值
    • 实参的类型不正确,但可以转换成正确的类型
  • 返回引用类型能够提高效率
  • 不能返回指向临时变量的引用
  • 引用返回值可以作为左值,而常规返回值不能作为左值
  • C++11允许右值引用(&&)
    常见的函数参数的传递指导原则如下:

  • 使用传递的值,不修改数据对象的函数:

    • 数据对象很小,使用值传递
    • 对象是数组,使用指针,并声明为 const
    • 对象较大,使用 const 引用或 const 指针
  • 对于修改数据对象的函数:

    • 对象是常规数据,使用指针
    • 对象是数组,使用指针
    • 对象是结构,使用指针或引用
    • 对象是类对象,使用引用

4.5 默认参数

默认参数是指当函数调用中省略了实参时自动使用的一个值。需要注意的点为:

  • 必须在原型中将可能的默认参数告知程序
  • 必须从右向左添加默认值

4.6 函数重载

函数重载指可以有多个同名的函数,可以通过函数重载设计一系列的函数,他们完成相同的工作,但是使用不同的参数列表。

  • 重载引用参数时的最佳匹配:
    • void function(double & arg) 匹配:
      可修改的左值参数(如 double变量),同时也是最优匹配
    • void function(const double & arg) 匹配:
      • 可修改的左值参数(如 double变量),
      • 不可修改的左值参数(如const double常量),最佳匹配
      • 右值参数(如 double + double),
    • coid function(double && arg)匹配:
      右值参数(如 double + double),同时也是最优匹配

4.7 函数模板

函数模板是通用的函数描述,它们使用泛型来定义函数,其中的泛型可以使用具体的类型替换。
建立函数模板的方式为:

1
2
template <typename AnyType>
void function(AnyType a, AnyType b)

  • 显式具体化
    • 对于给定的函数名,可以有非模板函数、模板函数、和显式具体化函数以及它们的重载版本
    • 显式具体化的原型和定义应以 template<> 开头,并通过名称来指定类型
    • 具体化优先于常规模板。
  • 显式实例化:
    • 显式实例化命令编译器创建特定的实例
    • 显式实例化不能和显式具体化共存
    • 显式实例化可以将参数强制转换为相应的类型

相应的代码示例为:

1
2
3
4
5
6
7
8
9
//非模板函数:
void function(type a);
//模板函数:
template <typename T>
void function(T a);
//显式具体化函数
template<> function<type>(type a);
//显式实例化
template function<type>(type a)

编译器选择函数版本的流程为:

  1. 创建候选列表
    所有函数名相同的模板和函数
  2. 创建可行函数列表
    所有参数匹配的函数
  3. 选择最佳函数
    • 完全匹配 常规函数优先于模板
    • 提升转换 char -> int float -> double
    • 标准转换 int -> char double -> float
    • 定义转换

针对无法确定的参数类型,C++11定义了关键字 decltype

  • 使用方法为: decltype (ecpression) var
    • ecpression 为标识符
      var类型为标识符类型
    • ecpression 为函数调用
      var类型为函数返回值类型
    • ecpression 为左值
      var类型为指向类型的引用类型
    • ecpression 为什么都不是
      var类型为experssion的类型

同时针对返回值的类型,C++新增了后置返回类型
auto function(int a) ->double;

五、内存空间

5.1 文件结构

程序可以分为三个部分:

  • 头文件:包含结构声明和使用这些结构的函数的原型,主要包括:
    • 函数原型
    • 符号常量
    • 结构声明
    • 类声明
    • 模板声明
    • 内联函数
  • 源代码文件:包含与结构相关的函数的代码
    • 实现相关函数代码
  • 源代码文件:包含调用与结构相关的函数的代码
    • 业务逻辑调用相关函数代码

5.2 存储持续性

C++使用三种不同的方式来存储数据:

  • 自动存储
    • 存储时间:函数存在时
    • 作用域为:局部
    • 链接性为:无
    • 内存区域:栈(后进先出)
  • 静态存储
    • 存储时间:整个程序运行时间
    • 作用域为:局部或全局
    • 链接性为:三种
      • 外部链接性——全局变量,可以在一个文件中定义全局变量,其他文件使用extern声明
      • 内部链接性——使用static修饰的全局变量
      • 无链接性——使用static修饰的局部变量
    • 内存区域:静态区域
  • 动态存储
    • 存储时间:new 分配的内存持续存在直至使用delete删除
    • 作用域为:使用地址均可以访问
    • 链接性为:使用地址访问
    • 内存区域:堆
  • 线程存储(C++11)
    • 存储时间为线程周期
  • C++
  • 函数重载
  • 模板
C++学习笔记

扫一扫,分享到微信

微信分享二维码
C++学习笔记(二)——面向对象
《程序员的修炼之道》读书笔记
© 2020 Myintelex
Hexo Theme Yilia by Litten