c++快速学习


数据类型
char 8位
short int 16位
long int 32位
int
float
double
long double
bool
wchar_t

开发环境
visual studio

标识符
A-Z 或 a-z 或 _开始 + 字母/下划线/数字
不允许数字开头和出现标点字符
区分大小写

关键字
https://en.cppreference.com/w/cpp/keyword

常量与变量
#define // 编译时出错,很难排错
const // 在编译时出错,可以排错

整数常量
前缀指定基数
后缀指定无符号还是长整型

布尔类型
true
false

字符常量
L'x' // 宽字符常量(wchar_t类型)

\是一个转义字符

注释
/*aaa*/
/*
 * bbb
 */

运算符表达式和基本语句

算术运算符
+ - * / % ++ --

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

逻辑运算符
&& || !

赋值运算符
= += -+ *= /= %=
<<= >>= &= ^= |=

位运算符
& 都为1才为1
| 有1就为1
^ 不同为1, 相同为0
<< 左移
>> 右移

杂项运算符
sizeof
Condition ? X:Y
, 逗号运算符会顺序执行一系列运算,整个表达式的值是以逗号分隔的列表中的最后一个表达式的值
. 和 -> 成员运算符用于引用类,结构和共用体的成员
Cast 强制转换运算符把一种数据类型转换为另一种数据类型
& 指针运算符返回变量的地址
* 指针运算符指向一个变量

结构体
typedef struct {
    short Sunday;
} Week;
Week week;
week.Sunday = 0;
cout << week.Sunday << endl;

运算符优先级
一般来说,一元运算符优先级高于对应的二元运算符
弄不清优先级,就加括号

补码
1,用函数B2T来表示
2,正数直接按位计算权重和,负数保留符号位,对后面每位取反+1

补码数值范围(字长)

字节序
大端法
小端法

位运算
左移(补零)
右移(逻辑右移填充0或算术右移负数填充1)
对有符号的数,尽可能不要使用右移运算

c语言常见问题及c++的解决方案和思考

c语言字符的语法陷阱
char c1 = 'test';
const char* slash1 = "/";
c++使用string类
string s1(1, 'yes');
cout << s1 << endl;
string s2(3, 'yes');
cout << s2 << endl;
string s3(1, 'y');
cout << s3 << endl;
string s4("/");
cout << s4 << endl;
string s5(1, '/');
cout << s5 << endl;
string s6("yes");
cout << s6 << endl;

c语言指针和数组的关系问题
数组退化的问题
传递数组会退化成指针
c++使用stl的容器及引用的使用
vector<int> & v
auto自动定义类型

c语言的移位问题
右移先转换成无符号的形式
移位操作位数的限制: 移位数大于0,小于位数
c++的bitset使用
bitset<10>

c语言强制类型转换问题
比较时发生了隐式的类型转换
运算时发生了隐式的类型转换
c++使用
static_cast
const_cast
dynamic_cast
reinterpret_cast

c语言的整数溢出问题
整型上限溢出
c++boost库使用
https://www.boost.org

c语言字符串的典型缺陷
c++的redis实现

c++容器的实现

序列型容器-数组
int arr[10]={1,2,3,4,5,6,7,8};
二维数组遍历先行后列有利于提供效率

vector是面向对象方式的动态数组
vec.insert(--vec.end(),4);
vec.erase(vec.end()-1);

字符串变量与常量
字符串是以空字符结束的字符数组
char str[11] = {"helloworld"};

ascii编码
utf-8编码
utf-8
1byte来表示字符,可以兼容ascii码
存储销量高,变长(不方便内部随机访问)
无字节序问题
utf-16
分为utf-16BE(big endian)和utf-16LE(little endian)
定长(方便内部随机访问)
有字节序问题
utf-32
分为utf-32BE(big endian)和utf-32LE(little endian)
定长(方便内部随机访问)
有字节序问题

编码错误的根本原因在于编码方式和解码方式的不一致

字符串的指针表示方法
& 取地址
* 定义指针变量

字符串常见操作
strlen(s) // 返回字符串s的长度
strlen_s(s) // 安全版本
strcmp(s1,s2) // 字符串比较(0,-1,1)
strcpy(s1,s2) // 将字符串s2拷贝到s1中
strcpy_s(s1,s2) // 安全版本
strncpy(s1,s2,n) // 将字符串s2中前n个字符拷贝到s1中
strcat(s1,s2) // 将字符串s2拼接到s1后面
strcat_s(s1,s2) // 安全版本
strchr(s1, ch) // 指向字符串s1中字符ch的第一次出现的位置
strstr(s1, s2) // 指向字符串s1中字符串s2的第一次出现的位置

string
string s;
string s = "helloworld";
string s("helloworld");
string s = string("helloworld");

字符串比较: == != > >= < <=
转换成c风格的字符串
const char* c_str = s1.c_str(); 
字符串拷贝
string s1 = "hello";
string s2 = s1;
字符串连接: + +=

c++指针/引用
定义指针变量,指向对象的地址,可以获得指向对象的值

左值与右值
左值是编译器为其单独分配了一块存储空间,可以取其地址的,左值可以放在赋值运算符左边
右值是数据本身,不能取到其自身地址,右值只能赋值运算右边

一般指针,指针的数组,数组的指针
int* ap = &a;
T* t[];
T(*t)[];

const指针
char const* == const char* (指向字符)
char* const (指向指针)
char const* const == const char* const (都不允许改变)

指向指针的指针
int a = 123;
int* b = &a;
int** c = &b;

野指针
未初始化和非法的指针
NULL指针
指针操作超越了变量的作用范围

没有初始化,不用的或者超出范围的指针请把值只为NULL

指针的基本运算
取地址操作后会复制到一个新的空间,所以取地址的操作是右值的操作
&与*操作符
++与--操作符
++++与----运算符
++*++cp 等运算

存储区域划分
栈和队列
指针在栈区,指向堆区栈区或者常量区
全局变量可以不用初始化


new
delete

资源管理方案RAII
依托栈和析构函数来对所有的资源包括堆内存在内进行管理

作用域
堆区 由new malloc开始,delete,free结束

智能指针
unique_ptr
shared_ptr
weak_ptr
auto_ptr(已废除)

auto_ptr
由new 表达式获得对象,在auto_ptr对象销毁时,他所管理的对象也会自动被delete掉
多个auto_ptr指向同一个对象,原来的指针就不再拥有这个对象了

unique_ptr
专属所有权

shared_ptr
引用计数(循环引用)

weak_ptr
与shared_ptr共同工作,用一种观察者模式工作

引用(不允许修改的指针)
可以认为是指定变量的别名,使用时可以认为是变量本身

c++的引用
有了指针为什么还需要引用
为了支持函数运算符重载
有了引用为什么还需要指针
为了兼容c语言

对内置基础类型而言,在函数中传递value(值)更高效
对面向对象中自定义类型而言,在函数中传递reference(引用)更高效

c++基础句法
三种基本结构
顺序,分支和循环
if
单分支/语句双分支语句/多分支语句
判断效率
逻辑短路

switch
汇编角度(跳转表),条件多时效率更高

枚举
enum不仅能够创建符号常量,还能定义新的数据类型
枚举值不可以做左值
非枚举变量不可以赋值给枚举变量
枚举变量可以赋值给非枚举变量
enum wT {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
wT weekday;
weekday = Monday;
weekday = Tuesday;
cout << weekday << endl;
int a = Wednesday;
cout << a << endl;

结构体和联合体
union Score{
    double sc;
    char level;
}
struct Student {
    char name[6];
    int age;
    Score s;
}


结构体的内存布局
定义变量先低后高节省内存(最大元素整数倍对齐)
char x;
short y;
int z;

32位cpu
char: 任何地址
short: 偶数地址
int: 4的整数倍地址
double: 4的整数倍地址

修改默认编译选项:
Visual C++:
    #pragma pack(n)
g++:
    __attribute__(aligned(n))
    __attribute__(__packed__)

三种循环语句: while, do while 和 for
dowhile(效率高) > while > for(简便)
for 循环优化例子
void forOptimize() {
    int n = 0;
    int high, low;
    for (size_t index = 32; ; index++) {
        n = index * index;
        if (n < 1000) continue;
        if (n > 9999) break;
        high = n / 100;
        low = n % 100;
        if ((high / 10 == high % 10) && (low / 10 == low % 10))
            cout << n << endl;
    }
}

函数
返回类型
函数名称
参数

函数重载
targetver.h 可以屏蔽某些平台

int test(int a) {
    return a;
}
int(*p)(int);
p = test;
int result = (*p)(1);

指向函数的指针与返回指针的函数
指向函数入口地址的指针称为函数指针
数据类型(*指针变量名)(参数表)
int(*p)(int); // 可以作为参数进行传递
返回值是指针的函数
int* p(int);

命名空间
.h
namespace testnamespace {
    int test(int a);
}
.cpp
namespace testnamespace {
    int test(int a) {
        return a + 1;
    }
}

函数体的hack过程
入栈跳转出栈

内联函数如果一个函数是内联的,那么编译时会把该函数的代码副本放置在每个调用该函数的地方
inline 
内联函数内部不能有太复杂的逻辑,编译器有时会有自己的优化策略,所以内联不一定起作用

数学归纳与递归
递归的缺陷
空间上需要开辟大量的栈空间
时间上可能需要有大量重复运算

递归的优化
尾递归
使用循环替代
使用动态规划,空间换时间

尾递归的优化

int Fib1(int n) {
    if(n==0) {
        return 0;
    }else if(n==1) {
        return 1;
    }else {
        return Fib1(n-1) + Fib1(n-2);
    }
}

int Fib2(int n, int ret0, int ret1) {
    if(n==0) {
        return ret0;
    }else if(n==1) {
        return 1;
    }
    return Fib2(n-1, ret1, ret0 + ret1);
}

递归的动态规划思路


高级语法
struct的默认成员权限是public
class的默认成员权限是private

构造函数
析构函数

对象属性

操作符重载
Complex::operator+ (const Complex& x);
Complex& operator= (const Complex& x);

拷贝构造及临时对象的优化
拷贝构造
Complex(const Complex& x);

操作符重载对象前置与后置操作符
前置效率高

标准输入输出io重载
friend ostream& operator << (ostream &os, const Complex &x);
os << "aaa" << x._real << "bbb" << x._image;
friend istream& operator >> (istream &is, Complex &x);
is >> x._real >> x._image;

空格或者回车
cin >> e;
cout << e << endl;

io 流基础
cin.ignore(numeric_limits<std::streamsize>::max(), '\n');

文件操作基础
文本文件
二进制文件

文件操作步骤
打开文件用于读和写(open)
检查打开是否成功(fail)
读或者写(read/write)
检查是否读完(EOF)
使用完文件后关闭文件(close)
#include <fstream>

```
#include <string>
#include <fstream>
#include <iostream>

using namespace std;

static const int bufferLen = 2048;

// 二进制流复制文件
bool CopyFile(const string &src, const string &dst) {

    ifstream in(src.c_str(), ios::in | ios::binary);
    ofstream out(dst.c_str(), ios::out | ios::binary | ios::trunc);

    if (!in || !out) {
        return false;
    }

    char temp[bufferLen];

    while (!in.eof()) {
        in.read(temp, bufferLen);
        streamsize count = in.gcount();
        out.write(temp, count);
    }

    in.close();
    out.close();

    return true;
}

int main() {

    bool isCopy = CopyFile("/Users/xingyue/Downloads/test.jpeg", "/Users/xingyue/Downloads/test1.jpeg");
    cout << isCopy << endl;

    return 0;
}
```

头文件的重复包含问题
两种方式
1,
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__
使用宏来防止同一个文件被多次包含
可移植性好,无法防止宏名重复,难以排错

2,#pragma once
使用编译器防止同一个文件被多次包含
可以防止宏名重复,易排错
可移植性不好

只考虑windows系统可以用方案2,否则用方案1(注意名字不要重复)

深拷贝浅拷贝及move语义的优化
浅拷贝只拷贝指针地址
深拷贝重新分配堆内存
写时复制

抽象-抽象类型
构造函数使用全局变量参数列表初始化成员变量
多态实现的方法需要加上virtual
抽象方法 virtual double Area() const = 0;

对象模型和虚函数
虚表替换指针实现多态

面向对象特性
封装性
数据和代码捆绑在一起,避免外界干扰和不确定性访问,封装可以使得代码模块化
继承性
让某种类型对象获得另一个类型对象的属性和方法,继承可以扩展已存在的代码
多态性
同一事物表现出不同事物的能力,即向不同对象会产生不同的行为,多态的目的则是为了接口重用

编程思想
单例模式(只有一个实例)
拥有一个私有构造函数,确保用户无法通过new直接实例她
包含一个静态私有成员变量instance与静态公有方法instance
static和单例模式的实现
static const Singleton* getInstance(); // 声明获取单例对象函数
static Singleton* This; // 使用静态变量

观察者模式(发布订阅)
virtual void Update(void* pArg) = 0;
list<Observer*> _Obs;

list的使用和观察者模式的实现
观察者模式的实现
void*NULL和nullptr
c++11中,nullptr用来替代(void*)0,NULL替代0
参数直接传NULL,会变成0
传指针类型的参数就是指针

隐式类型转换
显示类型转换

const_cast
用于转换指针或引用,去掉类型的const属性

reinterpret_cast的使用
重新解释类型,既不检查指向的内容,也不检查指针类型本身,但要求转换前后的类型所占用内存大小一致,否则将引发编译时错误

satic_cast
用于基本类型转换,有继承关系类对象和类指针之间转换,由程序员来确保转换是安全的,它不会产生动态转换的类型安全检查的开销

dynamic_cast
只能用于含有虚函数的类,必须用在多态体系中,用于类层次间的向上和向下转换,向下转化时,如果是非法的对于指针返回NULL

Adapter模式和多重继承
Adapter组合方式实现

设计模式总结

泛型编程之泛型函数
泛型编程是一种静态期多态,通过编译器生成最直接的代码
泛型编程可以将算法与特定类型,结构剥离,尽可能复用代码

泛型编程之泛型函数
泛型编程的递推过程及总结

进阶编程
stl标准库介绍
stl算法是泛型,不与任何特定数据结构和对象绑定,不必在环境类似的情况下重写代码
stl算法可以量身定做,并且具有很高的效率
stl可以进行扩充,你可以编写自己的组件并且能与stl标准的组件进行很好的配合

stl标准库六大组件
空间配置器
容器
适配器
仿函数
算法
迭代器

容器
序列式容器(可排序)
vector,list,deque序列式容器
stack,queue,priority_queue容器适配器
关联式容器(k,v)
set.multiset,map,multimap

仿函数(使用对象的方式操作函数)
仿函数一般不会单独使用,主要是为了搭配stl算法使用
函数指针不能满足stl对抽象性的要求,不能满足软件积木的要求,无法和stl其他组件搭配
本质就是类重载了一个aopertor(),创建一个行为类似函数的对象

模板(泛型)
仿函数
仿函数+模板(泛型)

stl算法(<algorithm>,<numeric>, <functional>)
非可变序列算法
可变序列算法
排序算法
数值算法

最常见的算法包括
查找,排序算法,通用算法,排列组合算法,数值算法,集合算法
二分查找(binary_search)

transform算法
int ones[] = {1,2,3,4,5};
int twos[] = {10,20,30,40,50};
int results[5];
transform(ones, ones + 5, twos, results, std::plus<int>());

lambda表达式
[](int a) -> void {}

stl容器的统计与二分查找

从手写全排序到stl的实现

迭代器基本使用
正向迭代器: iterator
常量正向迭代器: const_iterator
反向迭代器: reverse_iterator
常量反向迭代器: const_reverse_iterator

手写GC与异常

自定义迭代器与手写GC

容器适配器(adapter)
stack堆栈
queue队列
priority queue优先队列

空间配置器初步(allocator)

自定义空间配置器

stl空间配置器源码剖析与stl总结

boost库
字符串和文本处理库,容器库,算法库,函数对象和高阶编程库,综合类库等

c++ 多线程(c++11)

linux c++ 编程
gcc编译需要添加标准库等
gcc -lstdc++ helloword.cpp -o helloword
g++编译
g++ -Wall helloword.cpp -o helloword

gcc命令的编译选项
-shared 生成共享目标文件,通常用在建立共享库时
-static 禁止使用共享连接
-Wall 生成所有警告信息
-IDIRECTORY 指定额外的头文件搜索路径DIRECTORY
-LDIRECTORY 指定额外的函数库搜索路径DIRECTORY
-ILIBRARY 连接时搜索指定的函数库LIBRARY

源程序.cpp -> (预处理器) -> 被修改的源程序.i -> (编译器) -> 汇编程序.s -> (汇编器) -> 可重定位目标程序.o -> (连接器) -> 可执行目标程序helloword

Makefile的使用和编写
描述了整个工程所有文件的编译顺序,编译规则
make工具就根据Makefile中的命令进行编译和链接的

Makefile的格式
TARGET = main
OBJS = reply.o.main.o
.PHONY: clean
$(TARGET):$(OBJS)
        g++ $(OBJS) -o $(TARGET)
reply.o: reply.cpp
main.o: main.cpp

clean:
        rm $(TARGET) $(OBJS)

install:
        cp /usr/local/bin/mainTest

Makefile的扩展用法
make工程的安装和卸载
make install
make uninstall

Makefile的变量
用户自定变量,变量中的变量,追加变量,多行变量,环境变量,自动变量,模式变量,自动匹配
a = $(x) // 可以读取后面初始化的x
a := $(x) // 不能读取到后面初始化的x

多行变量
define xxx
aaa
bbb $(bar)
endef
test:
        echo $(xxx)

echo $PATH
echo $LANG
echo $HOME
echo $PWD
echo $LD_LIBRARY_PATH

$(CXX) ==> g++
$(RM) ===> rm -f

Makefile 动态库编写
TARGET = main
OBJS = reply.o
LIB = libreply.so
CXXFLAGS = -c -fPIC
.PHONY: clean

$(TARGET):$(LIB) main.o
        $(CXX) main.o -o $(TARGET) -L. -lreply -Wl, -rpath ./
$(LIB):$(OBJS)
        $(CXX) -shared $(OBJS) -o $(LIB)
reply.o:reply.cpp
        $(CXX) $(CXXFLAGS) reply.cpp -o $(OBJS)
main.o:main.cpp
        $(CXX) $(CXXFLAGS) main.cpp -o main.o
clean:
        rm $(TARGET) $(OBJS)

make后
g++ -c -fPIC reply.cpp -o reply.o
g++ -shared reply.o -o libreply.so
g++ main.o -o main -L. -lreply -Wl, -rpath ./

自动变量和模式变量
编译过程中产生的变量
$< 表示第一个匹配的依赖
$@ 表示目标
$^ 所有依赖
$? 所有依赖中更新的文件
$+ 所有依赖文件不去重
$(@D) 目标文件路径
$(@F) 目标文件名称
% 表示任意字符

TARGET = main
OBJS = reply.o
LIB = libreply.so
TESTOBJ = main.o
CXXFLAGS = -c -fPIC
LDFLAGS = -L. -lreply -Wl, -rpath $(@D)
SHARED = -shared
.PHONY: clean

$(TARGET):$(TESTOBJ) $(LIB)
        $(CXX) $< -o $@ $(LDFLAGS)
$(LIB):$(OBJS)
        $(CXX) $(SHARED) $^ -o $@
%.o:%.cpp
        $(CXX) $(CXXFLAGS) $^ -o $@
clean:
        $(RM) $(TARGET) $(OBJS) $(LIB) $(TESTOBJ)

https://www.gnu.org/software/make/manual/make.html

Makefile的自动生成和部署
https://www.gnu.org/software/automake/manual/automake.html
https://cmake.org/documentation

下载解压cmake-2.8.10.2
cd cmake-2.8.10.2
./bootstrap
gmake
sudo gmake install
cmake --version

编写CMakeLists.txt
#CMakeLists.txt
# 设置cmake最低版本
cmake_minimum_required(VERSION 2.8.0)
# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
# 项目名称
project(cmake_test)
# 包含的头文件目录
include_directories(./include)
set(SRC_DIR ./src)
# 指定生成链接库
add_library(XXX ${SRC_DIR}/XXX.cpp)
add_library(YYY ${SRC_DIR}/YYY.cpp)
# 设置变量
set(LIBRARIES XXX YYY)
set(OBJECT YYY_test)
# 生成可执行文件
add_executable(${OBJECT} ${SRC_DIR}/main.cpp)
# 为可执行文件链接目标库
target_link_libraries(${OBJECT} ${LIBRARIES})

https://pan.baidu.com/s/1xtFeXEMNFbeONVX2KN8VQQ
8veq

其他技巧

头文件
- #include "xxx" : 编译器首先在当前目录中查找要包含的文件。如果没有找到,则会在编译器设置的标准文件路径中查找该文件。通常情况下,使用双引号来包含自己编写的头文件
- #include <xxx> : 编译器只在标准文件路径中查找要包含的文件。通常情况下,使用尖括号来包含系统头文件
因此,使用第一种形式#include "xxx",您可以在本地目录和/或用户定义的目录中包含特定的文件。而使用第二种形式 #include <xxx>,您只能在标准目录中包含文件

内存剖析
c/c++内存调试初步
现场分析问题
跟踪错误的根本原因
了解计算机系统底层/软件架构
例子: 相同的值异或会变成0

汇编语言的初步
从汇编语言的视角看程序
剖析一个函数栈的结构
详细分析main函数的执行流程
shellcode基本原理和案例

推荐的书本
C++ primer
C++高质量编程
Effective C++
More Effective C++
Effective STL
The C++ Programming Language
STL源码解析
COM本质论
Exceptional C++
Inside the C++ Object Model
The Design and Evolution of C++

c++开发规范
双刃剑: 内存管理/指针 模板元编程


// ==========桌面应用项目实战========== //

设计项目的架构和标准

通用组件模块

ui模块开发

音频模块开发

项目总结


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星月IWJ

曾梦想杖键走天涯,如今加班又挨

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值