C++程序结构
程序编译过程
preprocess
预处理:都是以符号#
开头的命令,C/C++ 一般包含三个方面的内容:宏定义、文件包含和条件编译compile
编译:就是把高级语言转换为计算机可以识别的二进制语言(是由编写的源程序产生目标程序的过程)link
链接
包含头文件
C 以 .h
作为扩展名,C++ 不在包含扩展名,调用库的时候让机器根据情况自动选择相应的扩展名,C++ 也支持以 C 的方式调用头文件但是不提倡
#include<stdio.h>#include<cstdio>
命名空间 namespace
- 命名空间是解决命名冲突的机制
如果自己写的代码名字和第三方库中代码的名字相同会引起冲突无法通过编译
- 将第三方库的代码置于特定的命名空间中解决命名冲突
调用时通过限制命名空间作为前缀解决了命名冲突
1
2
using namespace std;实际上就是制定了调用了
iostream
标椎库中名为std
的命名空间,所以输出输入可以省去前缀std
,并且方便的是标准模板库的大部分操作的命名空间都是std
作为前缀因此一般情况下小程序都是直接调用std
命名空间
命名空间中函数的调用
通过命名空间前缀调用指定的函数:mycode::foo()
调用了名字为 mycode
下的 foo
函数
也可以引用命名空间简化调用:
如下是调用自定义的 namespaces.h
头文件下 mycode::foo()
1 |
|
这种命名空间的作用在多人合作的工程类代码中常见,一般每个人写的代码都放在一个命名空间中如此避免了小组内的命名冲突
注意:其实不能为了少些几个代码就随意引用多个 using namespace
,那样程序就又陷入的命名冲突的困境,失去了本身命名空间的作用
引用特定的对象
using
还可以只引用特定的某个对象
1 |
|
输入操作机理
要有一个概念就是从键盘键入的数据不是直接存入对应的待存入变量中,而是先存储到缓存区内,当遇到指定的字符时开始解析给待存入的变量依次赋值
-
数值:会跳过空白字符(空格、制表符和回车符),遇到回车后开始解析数值直至遇到非法字符停止解析,即停止解析后就算缓存区还有也不会再给当前的没存入的变量赋值但是还会保留在缓存区,至于没存入的变量内容是什么由编译器而定
-
字符串:读入字符串直至回车结束
例:若是给变量 a
和 b
存值的时候输入 1 2
那么两个变量都会成功赋值,但若是输入的是 1b2 3
那么只有 a
会成功赋值了,即使后面还有数值型变量也都会未存入
因为非法字符 b
导致后面 a变量以外的其他变量都未存入成功
a变量遇到非法字符 b
停止解析赋值为 1 ,但是下一个b变量成功吃掉字符 b
所以可以继续将缓存区内的值解析,后面的变量也都赋值成功
注意:由于缓存区未利用的字符会保留的机制,对于C语言的 scanf
存入多个连续字符的时候要另外注意—— C语言存入吃回车的原因
C++ 不用注意这个问题因为 cin
从缓存区的第一个非空字符同时对于多个字符的存入时末尾回车不会存入缓存区
C++基础语法
标识符和关键字
- 标识符和关键字不要发生冲突
- 不同的集成环境对于标识符的限制长度不同,要做到”见名知义“
基础数据类型
C++11 引入了新的数据类型拓宽了使用范围
字符型:char、wchar_t(16位字符)、char16_t、char32_t
wchar_t、char16_t、char32_t的区别可以参考这篇博客
整型:short、int、long、long long
无符号型:unsigned int等
浮点型:float、double、long double
布尔型:bool
常量
整型常量
- 十进制
- 八进制:数值前面加上前缀一个前导 0
- 十六进制:数值前面加上前缀
0x
- 长整型:后缀加上
LL
,无符号整型后缀加上U
浮点型常量
- 十进制
- 指数形式:
1.2e9
- 长浮点数:后缀加上
L
修饰前缀
C++11 新规定的常量加上修饰前缀指定编码规则
- u :
unicode
16字符 - U:
unicode
32字符 - L:宽字符
- u8(修饰字符串):UFT-8
Unicode 和 UTF-8 有什么区别参考这篇博客
原始字符串
引号和斜杠不能直接当做字符串输出,而是必须用 \
进行转义,为了方便需要一次性输出很多的引号和斜杠,C++11 新增了原始字符串来标识原始字符串
1 | cout << "I print \'\\\', \"\\n\" as I like." << endl; |
表达式:R"分隔符()分隔符"
规定:在表示字符串开头的 "
和 (
之间可以添加其它字符作为分隔符,不过必须在表示字符串结尾的 )
和 "
之间添加同样的字符
模式:
- 分割符左右对称,括号不能少
- 原始字符串不会按照转义字符解码
1 | cout << R"haha(I print '\', "\n" and )" as I like.)haha" << endl; |
命名推荐
符号常量用宏定义,宏定义不用定义数据类型,在预处理时会将所有的目标替换为定义的量在进行编译
例:
#define PI 3.1415926535
命名常量用 const
定义
注意两者区别
1 |
|
变量定义与初始化
C++11 新增了用 {}
作为初始化列表来初始化,旨在对类和对象内部不同变量和数组统一的初始化
注意:初始化和赋值是两个区别,新添的的初始化列表只能用于变量声明时的初始化,但是原先的 =
和 ()
是既可以用来初始化也可以用来赋值的。另外使用初始化列表的时候遇到失精度(窄化)会直接编译报错,而 ‘=’ 和 ()
只会警告
1 | int hand[]={3,4,5,6.5};//警告 |
类型转换
显示转换
1 | bool someBool=(bool)someInt; |
隐式转换
隐式转换使用不当会导致精度损失,一般编译器会给予警告
::
运算符
遵从原则:局部优先
1 |
|
extern
关键字
一般在写项目的时候会分为多个 cpp
文件,那么怎么实现多个文件公用一个变量或者函数呢。extern
关键字可以用来解决此类问题
- 引用同一个文件下变量
1 |
|
- 引用不同文件下变量
a.cpp
1 |
|
b.cpp
1 |
|
总结
extern
关键字只需要指明类型和变量名就行了,不能再重新赋值- 初始化必须在原文件所在处进行,如果不进行初始化的话,全局变量会被编译器自动初始化为 0
- 谨记:
extern
相当于声明,变量(函数)可以声明多次,但是定义只能一次
类型别名
除了之前的 typedef
C++11 还规定可以用 using
来进行别名声明
1 | typedef long long ll; |
auto
类型推导
C++11 还引入了 auto
,在可以推测数据类型的环境先可以使用 auto
来自动遍历容器和数组
decltype
类型推导
decltype
可以推测表达式的数据类型
1 | doubel f(); |
基于 for 循环
可以结合使用 auto
通过引用修改数组内的元素
1 | for(int i:a)//只能遍历 |
函数的声明和定义
- 函数的声明也称为函数原型或者函数签名,强调函数如何被访问,而不提供函数的实现代码,其中的形参可以只写上数据类型
- 函数的定义是函数的具体代码实现
函数的调用
- 第三方库的结构:提供专门的头文件,包含函数原型声明
- 函数的调用:通常将函数的原型声明统一放在一个头文件中供程序的调用