0%

C++基础简明总结

基础语法

编译

  • 预处理 Preprocessing cpp test.cpp -> test.i
  • 编译 Compilation g++ -g -S test.i
  • 汇编 assembly as -o test.o test.s gcc -g -c test.c;
  • 链接 linker ld -o …

表达式

左值右值

lvalue, rvalue

In C: 左值可以放在赋值语句左边,右值则不行。

左值利用的主要是对象的身份,右值则利用的是对象的值

  • decltype 作用左值时自动变成引用
  • 取地址符作用于一个左值,返回一个右值(指针)
  • 赋值运算符左侧作为左值运算对象

类型转换

一般来说是占用空间小的向占用空间大的方向转换,如果相同则无符号转换。

  • 数组转换为指针:赋值时
  • 指针转换
  • 转换为bool
  • non-const 指针或引用 向const 指针或引用转换
  • 类的类型转换 如 while (cin >> str) IO库中定义了istream转换规则。

显示转换:

  • 强制类型转换
  • 命名的强制类型转换
    • static_cast double db = static_cast<double>(j) /i; 大转小也可以(精度损失)
    • dynamic_cast 支持运行时类型识别
    • const_cast 改变运算对象的底层const,去掉const,只能改变const属性,无法改动类型

异常

  • throw,结束程序执行,回到函数调用处,抛出一个异常,并做资源清理
  • try-catch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyException : public exception {
public:
string msg() const {
return "my exception";
}
}

try{
throw MyException();
} catch (MyException& e) {
cout << "MyException\n";
cout << e.msg();
}

STL

IO

头文件

  • iostream
  • fstream
  • sstream

状态查看

  • s.bad()
  • s.good()
  • s.fail() 数据错误
  • s.bad() IO流错误
  • s.clear() 状态位复位
  • s.eof() 文件结束符

为什么要有Stream ?

Stream 是输入输出的抽象,提供了String类型和别的类型数据的相互转换

Stream分类:

  • 输入流 InputStream
  • 输出流 OutputStream

输出流

只能用 << 符号接受数据,将数据转换为String并发送给Stream
举例:

  • std::cout
  • std::ofstream :file stream是一种type
  • ostringstring :把String当成Stream

fstream 文件的例子

1
2
//You should include fstream
ofstream myStream("File.txt");
  • 打开文件 void open(const char *filename), ios::openmode mode);
    • ios::app 追加到文件末尾
    • ios::ate 定位到文件末尾
    • ios::in 用于读取
    • ios::out 写入文件
    • ios::trunc 截断模式,覆盖掉原有
    • e.g. ofstm.open("file.dat", ios::out|ios::trunc);
  • 关闭 void close();

ostringstream 的例子(stringstream可以读入读出):字符串的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <sstream>


using namespace std;

int main(int argc, char const *argv[])
{
ostringstream oss("Ito En Green Tea");
cout << oss.str() << endl;

oss << 16.9 << "Oh";

cout << oss.str() << endl;
return 0;
}
1
2
Ito En Green Tea
16.9Oh Green Tea

输入流

  • std::cin
  • ifstream

fstream 的例子

1
2
3
4
5
6
7
//You should include fstream
ifstream myFileStream("file.txt");
int integer;
myFileStream >> integer;
// Or:
ifstream myFileStream2;
myFileStream2.open("file.txt");

mystream.fail()可以检测stream是否fail,例如

  • 读文件读到结束
  • 文件不存在
  • 读入的类型错误

注意的问题

cin 一直读到空格,换行符等,如果输入单词可能有问题

但是要用getline要注意下面的问题

1
2
cin >> val;
cin >> val2;// ok
1
2
cin >> val;
getline(cin, val2); // read \n

第二次读入的就是第一次的\n,因为cin 并不会处理后面的\n,只将前面的 \n 空格略去,等于说此时getline在streambuffer里读入的是第一次结尾的\n。

string

  • size(), 返回string::size_type
  • empty()
  • [] 以string::size_type为索引,注意类型是unsigned 的
  • 字符串相关操作:
    • str1 + str2
    • str1 + “字面量”
    • os << str, is >> s
    • getline(cin, str),读取一行,丢弃换行符
    • == 按字符序比大小,如果前面相同比长度,长者大
  • cctype 头文件
    • isupper(), toupper() 大写
    • islower(), tolower() 小写
    • isdigit(), isalpha() 数字和字幕
    • ispunct() 标点
    • isspace() 空白

顺序容器

顺序容器的元素排列顺序与其值无关,而仅仅由元素添加到容器里的次序决定。

vector

功能:

  • 创建
    • vector<int> a(v2); vector<int> a = v2;
    • vector<int> a{0, 1, 2, 3, 4};
    • vector<int> a = {0, 1, 2, 3, 4};
    • vector<int> a(n): 初始化为0
    • vector<int> a(n, val): n个以val为值的vector元素
  • 增加
    • push_back(val):在最后增加
    • insert(index, val):在index处(或理解为index前面)增加
  • 删除
    • erase(v.begin()+i):按地址删除
    • pop_back();
    • clear():清除所有
  • 修改
    • v[i] = val:没有边界检查
    • v.at(i) = val
  • 查找
    • v.at(i)
    • v[i] :没有边界检查
    • v.front();
    • v.back();
  • 其他
    • v.empty();
    • v.reserve(size): 预留size个地方

deque

双端队列,跟vector类似,用的比较少,好处在于大量插入删除操作时速度快

有和vector一样的函数,还有front操作

  • push_front(val)
  • pop_front()

list

插入删除开销少,但是不能根据index进行快速定位
front操作

  • push_front(val)
  • pop_front()

使用技巧

  • 可以先reserve一定大小
1
2
3
4
vec.reserve(1000000);
for (size_t i = 0; i < 1000000; ++i) {
vec.push_back(i);
}

关联容器

set

multiset

map

multimap

基于hash table的容器

unordered_map

unordered_set

iterator

迭代器

  • begin(), end() 返回首尾迭代器,是否为const由元素决定
  • cbegin(),cend()返回const_iterator
  • 算术运算+-

泛型算法

参考C++Primer第10章

智能指针

<memory>

  • unique_ptr : move 语意, 资源只有一个指向它
  • shared_ptr : copy 语意, 资源可以有多个指向它,要知道最后一个用的,没有人指向我,那就delete
  • weak_ptr
1
2
3
4
5
6
unique_ptr<classA> r1 { std::make_unique<classA>()};
shared_ptr<classA> r2 { std::shared_unique<classA>()};
weak_ptr<classA> wr(r2);
if (wr.expired()) return; //过期

auto resource = wr.lock();

常用:

1
2
3
4
5
6
7
8
9
10
unique_ptr<X> make_X(int i) {
// etc.
return unique_ptr<X>{new X{i}};
}

void user(const string& name, ios_base::openmode mode) {
shared_ptr<fstream> fp {new fstream(name, mode)};
if(!*p) // 确定文件打开
throw No_file{};
}

RAII

RAII: Resource acquisition Is Initialization
资源获取即初始化

lambda 表达式

  • 匿名函数
  • capture list 外部变量访问方式说明符
    • = 只读
    • & 可修改
    • 空的,不用到外面的变量
    • [=, &x, &y],x,y 可改,其余变量不能修改
    • [&, x, y]除了x,y以外的外部变量都可以修改
  • ->可以省略,让编译器自己推导
1
2
3
4
5
6
7
8
9
10
11
12
13
[capture list] (parameter list) -> int {
//...
}

//e.g.

string name = "lambda function";
auto square = [=, &name](const int& value) {
cout << name << std::endl;
name = "inda";
return value*value;
};

  • C++14 generic lambda

类型转换

显式

  • C style: (type) expression
  • const_cast<type> (expr): 修改类型的const属性
  • dynamic_cast<type> (expr): runtime 执行转换,若失败,expr被认定为nullptr,若引用失败catch std::bad_cast
  • static_cast<type>: 非动态转换,没有运行时类检查来保证转换的安全性,例如int到size_t
  • reinterpret_cast<type> (expr) : 最好不用

隐式类型转换

  • 注意类的隐式类型转换
    • 例如有函数combine(const Sale_data &sd),且有构造函数可以接受string, 则combine(string(“str”))则会默认生成一个Sale_data类
    • 拷贝形式: Sales_data item = string(“str”);
    • 可以使用explicit 关键字避免不期望的隐式类型转换

命名空间

  • 定义一个范围
  • 类本身就是一个特殊的命名空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace My_code {
class complex {
//...
}
complex sqrt(complex);
//...
int main();
}

//使用干的时候加上命名空间
int My_code::main() {
complex z{1,2};
//...
}
// 全局
int main() {
return My_code::main():
}
  • 不要在头文件里使用命名空间(using namespace …)

OOP

C struct:

  • 没有封装
  • 没有操作

类Class

  • 数据抽象
  • 封装
    • private
    • public
    • protected (子类)
  • 动态绑定(运行时绑定)

函数

1
2
3
4
5
6
7
8
9
10
class X {
public:
X(Sometype); // 构造函数
X();// 默认构造函数
X(const X&); // 复制构造函数
X(const X&&); // 移动构造函数,用std::move()调用
X& operator=(const X&); // 复制操作符
X& operator=(X&&); // 移动操作符
~X(); // 析构
}

friend 函数

  • 定义在类外部

  • 有权访问累的所有private 成员和protected 成员

  • friend 函数并不是成员函数

    相同Class的各个objects互为friends

const

  • 常量成员函数
  • 常量对象 -> 只能调用 const 函数

const & constexpr

  • 修饰对象
    • const主要表示这是个常量,不会变动
    • constexpr是修饰一个常量表达式
  • 修饰函数
    • const只能用于非静态成员函数,保证函数不修改任何非静态数据
    • constexpr适用于常量表达式,通常是简单函数,只允许return语句,参数和返回值必须是字面量。

virtual

virtual 关键字

在继承时通过晚绑定和vtable来实现多态,这样就可以用基类指针来操作各种派生类。

纯虚函数

  • vitual double function() = 0;

声明一个function为接口,接口类不能被实例化,但是可以有成员变量,该类是纯虚类。

类的不可改性

  • const 成员函数
  • const 成员变量
  • class 为final: class A final {} 不能再被继承了

其他

  • 递归
    • 好处:
      • 分而治之
      • 简洁性好
  • 迭代
    • 好处
      • 效率高:编译器在同一个stack里面容易优化代码,cross-stack 优化不容易做