Merge pull request #1 from Light-City/master

pull request
This commit is contained in:
walterzhao 2020-09-09 22:58:04 +08:00 committed by GitHub
commit 4b8edae783
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
197 changed files with 7157 additions and 611 deletions

View File

@ -1,5 +1,7 @@
# C++ 那些事
[English version is here](./README_EN.md)
感谢各位对《C++ 那些事》的支持,现将内容也同步至网站,可以打开网站直接阅读~欢迎大家 star、转发、PR。
@ -10,6 +12,8 @@ https://light-city.club/sc/
### 关于作者
公众号已开放两大入口分别是专辑与菜单可以直接在微信公众号上阅读《C++那些事》内容,配上该仓库的代码,将会非常的爽,建议大家关注一波。
个人公众号guangcity
![](https://light-city.club/sc/assets/images/wechat.jpg)
@ -26,9 +30,13 @@ https://light-city.club/sc/
Ubuntu 18.04
- **工具**
- **编辑工具**
CLion gcc/g++
CLion
- **编译器**
> gcc/g++
尽量用g++因为一开始我用的vim写的所以纯g++后来用编译器CLion部分有CMakeLists.txt文件直接导入就行后面会更新这个文件包含整个项目持续关注~
@ -145,7 +153,7 @@ C++2.0 是一个简称,意为「现代 C++」,包括 C++11/14/17/20。
#### 3.1 [C++11 新特性](./c++2.0/c++11)
- [Variadic Templates](./c++2.0/variadic)
- [Variadic Templates](./c++2.0/c++11/variadic)
- Spaces in Template Expressions
@ -154,17 +162,17 @@ C++2.0 是一个简称,意为「现代 C++」,包括 C++11/14/17/20。
vector<list<int>> // before c++ 11 error error: >> should be > > within a nested template argument list,c++11后可以正常通过
```
- [nullptr and nullptr_t](./c++2.0/nullptr.cpp)
- [nullptr and nullptr_t](./c++2.0/c++11/nullptr.cpp)
- [Automatic Type Deduction with auto](./c++2.0/auto.cpp)
- [Automatic Type Deduction with auto](./c++2.0/c++11/auto.cpp)
- [Uniform Initialization ](./c++2.0/uniform_initialization.cpp)
- [Uniform Initialization ](./c++2.0/c++11/uniform_initialization.cpp)
- [initializer_list](./c++2.0/initializer.cpp)
- [initializer_list](./c++2.0/c++11/initializer.cpp)
- [explicit for ctors taking more than one argument](./c++2.0/explicit.cpp)
- [explicit for ctors taking more than one argument](./c++2.0/c++11/explicit.cpp)
- [range-based for statement](./c++2.0/auto.cpp)
- [range-based for statement](./c++2.0/c++11/auto.cpp)
```cpp
for(decl:col) {
@ -172,33 +180,33 @@ C++2.0 是一个简称,意为「现代 C++」,包括 C++11/14/17/20。
}
```
- [=default,=delete](./c++2.0/default_delete.cpp)
- [=default,=delete](./c++2.0/c++11/default_delete.cpp)
如果你自行定义了一个 ctor,那么编译器就不会给你一个 default ctor
如果强制加上 =default,就可以重新获得并使用 default ctor.
- Alias(化名)Template(template typedef)
- [alias.cpp](./c++2.0/alias.cpp)
- [template_template.cpp](./c++2.0/template_template.cpp)
- [alias.cpp](./c++2.0/c++11/alias.cpp)
- [template_template.cpp](./c++2.0/c++11/template_template.cpp)
- [template template parameter](./c++2.0/template_template.cpp)
- [type alias](./c++2.0/type_alias.cpp)
- [type alias](./c++2.0/c++11/type_alias.cpp)
- [noexcept](./c++2.0/noexcept.cpp)
- [noexcept](./c++2.0/c++11/noexcept.cpp)
- [override](./c++2.0/override.cpp)
- [override](./c++2.0/c++11/override.cpp)
- [final](./c++2.0/final.cpp)
- [final](./c++2.0/c++11/final.cpp)
- [decltype](./c++2.0/decltype.cpp)
- [decltype](./c++2.0/c++11/decltype.cpp)
- [lambda](./c++2.0/lambda.cpp)
- [lambda](./c++2.0/c++11/lambda.cpp)
- [Rvalue reference](./c++2.0/rvalue.cpp)
- [Rvalue reference](./c++2.0/c++11/rvalue.cpp)
- [move aware class](./c++2.0/move.cpp)
- [move aware class](./c++2.0/c++11/move.cpp)
- 容器-结构与分类
@ -206,9 +214,9 @@ C++2.0 是一个简称,意为「现代 C++」,包括 C++11/14/17/20。
- (2) 关联式容器包括:`set/multiset`,`map/multimap`
- (3) 无序容器(C++2.0 新引入,更换原先 `hash_xxx``unordered_xxx`)包括:`unordered_map/unordered_multimap,unordered_set/unordered_multiset`
- [Hash Function](./c++2.0/hash.cpp)
- [Hash Function](./c++2.0/c++11/hash.cpp)
- [tuple](./c++2.0/tuple.cpp)
- [tuple](./c++2.0c++11//tuple.cpp)
学习资料https://www.bilibili.com/video/av51863195?from=search&seid=3610634846288253061
@ -219,6 +227,7 @@ C++2.0 是一个简称,意为「现代 C++」,包括 C++11/14/17/20。
### 4.设计模式
- [单例模式](./design_pattern/singleton)
- [生产消费者模式](./design_pattern/producer_consumer)
### 5. [STL 源码剖析](./src_analysis/stl)
@ -344,24 +353,15 @@ map<int, int> mp{
### 11.贡献者
<table>
<tbody>
<tr>
<th align="center" style="width: 80px;">
<a href="https://github.com/Light-City">
<img src="https://avatars2.githubusercontent.com/u/25699850?s=50&v=4" style="width: 50px;"><br>
<sub>Francis</sub>
</a><br>
</th>
<th align="center" style="width: 80px;">
<a href="https://github.com/ChungZH">
<img src="https://avatars1.githubusercontent.com/u/42088872?s=50&v=4" style="width: 50px;"><br>
<sub>ChungZH</sub>
</a><br>
</th>
</tr>
</tbody>
</table>
| 贡献人 | 地址 |
| ------- | ----------------------------- |
| 光城 | https://github.com/Light-City |
| ChungZH | https://github.com/ChungZH |
| xliu79 | https://github.com/xliu79 |
### 12.赞助我

View File

@ -1,357 +0,0 @@
# C++ 那些事
感谢各位对《C++ 那些事》的支持,现将内容也同步至网站,可以打开网站直接阅读~欢迎大家 star、转发、PR。
[直通点](https://light-city.club/sc/)
-----------------------
### 0.项目概要
- 中文名:**C++ 那些事**
- 英文名:**Stories About C Plus Plus**
这是一个适合初学者从<u>**入门到进阶**</u>的仓库,解决了<u>**面试者与学习者**</u>想要<u>**深入 C++**</u>及如何<u>**入坑 C++**</u>的问题。除此之外,本仓库拓展了更加深入的源码分析,多线程并发等的知识,是一个比较全面的 C++ 学习从入门到进阶提升的仓库。
### 1.基础进阶
- [const 那些事](./basic_content/const)
- [static 那些事](./basic_content/static)
- [this 那些事](./basic_content/this)
- [inline 那些事](./basic_content/inline)
- [sizeof 那些事](./basic_content/sizeof)
- [函数指针那些事](./basic_content/func_pointer)
- [纯虚函数和抽象类那些事](./basic_content/abstract)
- [vptr_vtable 那些事](./basic_content/vptr_vtable)
- [virtual 那些事](./basic_content/virtual)
- [volatile 那些事](./basic_content/volatile)
- [assert 那些事](./basic_content/assert)
- [位域那些事](./basic_content/bit)
- [extern 那些事](./basic_content/extern)
- [struct 那些事](./basic_content/struct)
- [struct 与 class 那些事](./basic_content/struct_class)
- [union 那些事](./basic_content/union)
- [c 实现 c++ 多态那些事](./basic_content/c_poly)
- [explicit 那些事](./basic_content/explicit)
- [friend 那些事](./basic_content/friend)
- [using 那些事](./basic_content/using)
- [:: 那些事](./basic_content/maohao)
- [enum 那些事](./basic_content/enum)
- [decltype 那些事](./basic_content/decltype)
- [引用与指针那些事](./basic_content/pointer_refer)
- [宏那些事](./basic_content/macro)
### 2.实战系列
#### 2.1 10日狂练
- [x] day1
基本c++语法
- [x] day2
递归、结构体、枚举、静态变量等
- [x] day3
函数
- [x] day4
函数深入
- [x] day5
继承多态
- [x] day6
虚函数、抽象类
- [x] day7
运算符重载
- [x] day8
模板与STL
- [x] day9
异常
- [x] day10
文件与流
#### 2.2 重点实战练习
├── [中括号重载.cpp](./practical_exercises/key_exercises/中括号重载.cpp)
├── [时钟++运算符重载.cpp](./practical_exercises/key_exercises/时钟++运算符重载.cpp)
├── [运算符重载之强制转换.cpp](./practical_exercises/key_exercises/运算符重载之强制转换.cpp)
└── [重载圆括号的时钟.cpp](./practical_exercises/key_exercises/重载圆括号的时钟.cpp)
├── [函数模板.cpp](./practical_exercises/key_exercises/函数模板.cpp)
├── [动态数组.cpp](./practical_exercises/key_exercises/动态数组.cpp)
├── [字典插入与查找.cpp](./practical_exercises/key_exercises/字典插入与查找.cpp)
├── [异常捕获.cpp](./practical_exercises/key_exercises/异常捕获.cpp)
├── [类模板之栈.cpp](./practical_exercises/key_exercises/类模板之栈.cpp)
├── [类模板特化之数组.cpp](./practical_exercises/key_exercises/类模板特化之数组.cpp)
├── [继承与封装.cpp](./practical_exercises/key_exercises/继承与封装.cpp)
├── [读写文件综合题.cpp](./practical_exercises/key_exercises/读写文件综合题.cpp)
├── [输入输出运算符重载.cpp](./practical_exercises/key_exercises/输入输出运算符重载.cpp)
├── [输入输出重载.cpp](./practical_exercises/key_exercises/输入输出重载.cpp)
├── [输出格式.cpp](./practical_exercises/key_exercises/输出格式.cpp)
### 2.[C++2.0 新特性](./c++2.0)
#### 2.0 概况
C++2.0 是一个简称,意为「现代 C++」,包括 C++11/14/17/20。
#### 2.1 [C++11 新特性](./c++2.0/c++11)
- [Variadic Templates](./c++2.0/variadic)
- Spaces in Template Expressions
```cpp
vector<list<int> > //ok in each C++ version
vector<list<int>> // before c++ 11 error error: >> should be > > within a nested template argument list,c++11后可以正常通过
```
- [nullptr and nullptr_t](./c++2.0/nullptr.cpp)
- [Automatic Type Deduction with auto](./c++2.0/auto.cpp)
- [Uniform Initialization ](./c++2.0/uniform_initialization.cpp)
- [initializer_list](./c++2.0/initializer.cpp)
- [explicit for ctors taking more than one argument](./c++2.0/explicit.cpp)
- [range-based for statement](./c++2.0/auto.cpp)
```cpp
for(decl:col) {
statement
}
```
- [=default,=delete](./c++2.0/default_delete.cpp)
如果你自行定义了一个 ctor,那么编译器就不会给你一个 default ctor
如果强制加上 =default,就可以重新获得并使用 default ctor.
- Alias(化名)Template(template typedef)
- [alias.cpp](./c++2.0/alias.cpp)
- [template_template.cpp](./c++2.0/template_template.cpp)
- [template template parameter](./c++2.0/template_template.cpp)
- [type alias](./c++2.0/type_alias.cpp)
- [noexcept](./c++2.0/noexcept.cpp)
- [override](./c++2.0/override.cpp)
- [final](./c++2.0/final.cpp)
- [decltype](./c++2.0/decltype.cpp)
- [lambda](./c++2.0/lambda.cpp)
- [Rvalue reference](./c++2.0/rvalue.cpp)
- [move aware class](./c++2.0/move.cpp)
- 容器-结构与分类
- (1) 序列式容器包括:`array`(C++2.0 新引入),`vector`,`deque`,`list`,`forward_list`(C++2.0 新引入)
- (2) 关联式容器包括:`set/multiset`,`map/multimap`
- (3) 无序容器(C++2.0 新引入,更换原先 `hash_xxx``unordered_xxx`)包括:`unordered_map/unordered_multimap,unordered_set/unordered_multiset`
- [Hash Function](./c++2.0/hash.cpp)
- [tuple](./c++2.0/tuple.cpp)
学习资料https://www.bilibili.com/video/av51863195?from=search&seid=3610634846288253061
### 2.2 C++14/17/20
待更新...
### 3.设计模式
- [单例模式](./design_pattern/singleton)
### 4. [STL 源码剖析](./src_analysis/stl)
**STL 源码剖析gcc 4.9.1**
- [array](./src_analysis/stl/array.md)
- [deque](./src_analysis/stl/deque.md)
- [queue and stack](./src_analysis/stl/queue_stack.md)
- [list](./src_analysis/stl/list.md)
- [vector](./src_analysis/stl/vector.md)
- [typename](./src_analysis/stl/typename.md)
- [traits](./src_analysis/stl/traits.md)
- [iterator](./src_analysis/stl/iterator.md)
- [谈谈 STL 设计之 EBO 优化](./src_analysis/stl/谈谈STL设计之EBO优化.md)
- [rb_tree](./src_analysis/stl/rb_tree.md)
- [set and multiset](set_multiset.md)
- [map and multimap](./src_analysis/stl/map_multimap.md)
- [hashtable](./src_analysis/stl/hashtable.md)
- [myhashtable](./src_analysis/stl/myhashtable.md)
- [unordered_map](./src_analysis/stl/unordered_map.md)
### 4. [并发编程](./concurrency)
#### 4.1 C++ Concurrency in Action
- [第一章](./concurrency/concurrency_v1/chapter1)
- [第二章](./concurrency/concurrency_v1/chapter2)
学习资料https://chenxiaowei.gitbook.io/cpp_concurrency_in_action/
#### 4.2 多线程与多进程
##### 4.2.1 Threading In C++
- [介绍](./concurrency/Threading_In_CPlusPlus/1.thread)
- [创建线程的五种类型](./concurrency/Threading_In_CPlusPlus/2.create_type)
- [Join 与 Detachs](./concurrency/Threading_In_CPlusPlus/3.join_detach)
- [mutex in C++ Threading](./concurrency/Threading_In_CPlusPlus/4.mutex)
> 学习自:
>
> https://www.youtube.com/watch?v=eZ8yKZo-PGw&list=PLk6CEY9XxSIAeK-EAh3hB4fgNvYkYmghp&index=4
### 5. [C++ 惯用法](./codingStyleIdioms)
##### 你最喜欢的 c++ 编程风格惯用法是什么?
- [1.类初始化列表](./codingStyleIdioms/1_classInitializers)
- [2.枚举类替换命名空间](./codingStyleIdioms/2_enumclass_namespace)
- [3.RAII(资源获取即初始化)](./codingStyleIdioms/3_RAII)
- [4.copy and swap](./codingStyleIdioms/4_copy-swap)
- [5.pImpl(指针指向具体实现)](./codingStyleIdioms/5_pImpl)
### 6.学习课程
#### 6.1 [极客时间《现代 C++ 实战 30 讲》](https://time.geekbang.org/channel/home)
- [堆、栈、RAIIC++ 里该如何管理资源?](./learn_class/modern_C++_30/RAII)
- [](./modern_++_30/RAII/heap.cpp)
- [](./learn_class/modern_C++_30/RAII/stack.cpp)
- [RAII](./learn_class/modern_C++_30/RAII/RAII.cpp)
- [自己动手,实现 C++ 的智能指针](./learn_class/modern_C++_30/smart_ptr)
- [auto_ptr、scope_ptr](./learn_class/modern_C++_30/smart_ptr/auto_scope.cpp)
- [unique_ptr](./learn_class/modern_C++_30/smart_ptr/unique_ptr.cpp)
- [shared_ptr](./learn_class/modern_C++_30/smart_ptr/shared_ptr.cpp)
- [右值和移动究竟解决了什么问题?](./learn_class/modern_C++_30/reference)
- [左值与右值](./learn_class/modern_C++_30/reference/reference.cpp)
- [延长声明周期](./learn_class/modern_C++_30/reference/lifetime.cpp)
- [引用折叠](./learn_class/modern_C++_30/reference/collapses.cpp)
- [完美转发](./learn_class/modern_C++_30/reference/forward.cpp)
- [不要返回本地变量的引用](./learn_class/modern_C++_30/reference/don'treturnReference.cpp)
- [容器 1](./learn_class/modern_C++_30/container1)
- [容器 2](./learn_class/modern_C++_30/container2)
- [异常](./learn_class/modern_C++_30/exception)
- [字面量、静态断言和成员函数说明符](./learn_class/modern_C++_30/literalAssert)
- [是不是应该返回对象?](./learn_class/modern_C++_30/returnObj)
- [编译期多态:泛型编程和模板入门](./learn_class/modern_C++_30/compilerpoly)
- [译期能做些什么?一个完整的计算世界](./learn_class/modern_C++_30/compilercompute)
- [SFINAE不是错误的替换失败是怎么回事?](./learn_class/modern_C++_30/SFINAE)
- [constexpr一个常态的世界](./learn_class/modern_C++_30/constexpr)
- [函数对象和 lambda进入函数式编程](./learn_class/modern_C++_30/functionLambda)
- [内存模型和 atomic理解并发的复杂性](./learn_class/modern_C++_30/memorymodel_atomic)
### 7.工具篇
#### 7.1 [容器快捷输出工具](./tool/output)
对吴老师的代码进行了修改,[点击此处直通代码](./tool/output/output_container.h)
输入:
```cpp
map<int, int> mp{
{1, 1},
{2, 4},
{3, 9}};
cout << mp << endl;
```
输出结果显示:
```cpp
{ 1 => 1, 2 => 4, 3 => 9 }
```
#### 7.2 像 Python 一样简单输出Jupyter Notebook
- [像 Python 一样玩 C/C++](./tool/像Python一样玩CC++.md)
#### 7.3 观察编译过程变化
- [https://cppinsights.io](https://cppinsights.io/)
#### 7.4 C++ 的 Debug 工具 dbg-macro
- [C++ 的 Debug 工具 dbg-macro](./tool/C++的Debug工具dbg-macro.md)
### 8.拓展部分
#### 8.1 一些问题
- [C++ 中如何将 string 类型转换为 int 类型?](./extension/some_problem/string_int.md)
### 9.代码运行
- **代码环境**
Ubuntu 18.04
- **工具**
CLion gcc/g++
### 10.贡献者
<table>
<tbody>
<tr>
<th align="center" style="width: 80px;">
<a href="https://github.com/Light-City">
<img src="https://avatars2.githubusercontent.com/u/25699850?s=50&v=4" style="width: 50px;"><br>
<sub>Francis</sub>
</a><br>
</th>
<th align="center" style="width: 80px;">
<a href="https://github.com/ChungZH">
<img src="https://avatars1.githubusercontent.com/u/42088872?s=50&v=4" style="width: 50px;"><br>
<sub>ChungZH</sub>
</a><br>
</th>
</tr>
</tbody>
</table>
### 11.关于作者
个人公众号:
![](./img/wechat.jpg)

347
README_EN.md Normal file
View File

@ -0,0 +1,347 @@
# Stories About C Plus Plus
Thanks for all the support about << Stories About C ++ >>, right now you could open this link(https://light-city.club/sc/) to read this article.
Any star, retweet or pr will be weclomed.
-----------------------
### 0. Directory
- Chinese version**C++ 那些事**
- English version**Stories About C Plus Plus**
This repository meets the need of people who wants to really know about C++, and may help you in the interview. Besides, it also provides
other details,such as in-depth source code analysis and multi-threaded concurrency. It is a comprehensive C ++ repository from entry to advanced improvement
### 1.Foundation
- [Stories About const](./basic_content/const)
- [Stories About static](./basic_content/static)
- [Stories about this](./basic_content/this)
- [Stories About inline](./basic_content/inline)
- [Stories About sizeof](./basic_content/sizeof)
- [Stories About pointer of function](./basic_content/func_pointer)
- [Stories About pure virtual function and abstract](./basic_content/abstract)
- [Stories About vptr_vtable](./basic_content/vptr_vtable)
- [Stories About virtual](./basic_content/virtual)
- [Stories About volatile](./basic_content/volatile)
- [Stories About assert](./basic_content/assert)
- [Stories About bit](./basic_content/bit)
- [Stories About extern](./basic_content/extern)
- [Stories About struct](./basic_content/struct)
- [Stories About struct and class](./basic_content/struct_class)
- [Stories About union](./basic_content/union)
- [Stories About polymorphism](./basic_content/c_poly)
- [Stories About explicit](./basic_content/explicit)
- [Stories About friend](./basic_content/friend)
- [Stories About using](./basic_content/using)
- [Stories About :: ](./basic_content/maohao)
- [Stories About enum](./basic_content/enum)
- [Stories About decltype](./basic_content/decltype)
- [Stories About pointer_refer](./basic_content/pointer_refer)
- [Stories About macro](./basic_content/macro)
### 2.Code Samples
#### 2.1 10 Days Practice
- [x] day1
Basic Grammar About C ++
- [x] day2
Recursive、Structor、Enumerate、Static Variable
- [x] day3
Function
- [x] day4
Thorough About Function
- [x] day5
Inheritance and Polymorphism
- [x] day6
Vitrual Function、Abstruct
- [x] day7
Operator overloading
- [x] day8
Template And STL
- [x] day9
Exception
- [x] day10
File And Stream
#### 2.2 Practical Exercises
├── [Square brackets overload .cpp](./practical_exercises/key_exercises/中括号重载.cpp)
├── [Clock++operator overloading.cpp](./practical_exercises/key_exercises/时钟++运算符重载.cpp)
├── [Mandatory conversion of operator overloading.cpp](./practical_exercises/key_exercises/运算符重载之强制转换.cpp)
└── [Clock with overloaded parenthesis.cpp](./practical_exercises/key_exercises/重载圆括号的时钟.cpp)
├── [Template of Function.cpp](./practical_exercises/key_exercises/函数模板.cpp)
├── [Dynamic array.cpp](./practical_exercises/key_exercises/动态数组.cpp)
├── [Dictionary insertion and search.cpp](./practical_exercises/key_exercises/字典插入与查找.cpp)
├── [Catch Exception.cpp](./practical_exercises/key_exercises/异常捕获.cpp)
├── [Template of Stack.cpp](./practical_exercises/key_exercises/类模板之栈.cpp)
├── [Template of Array.cpp](./practical_exercises/key_exercises/类模板特化之数组.cpp)
├── [Inheritance And Package.cpp](./practical_exercises/key_exercises/继承与封装.cpp)
├── [Read And Write files.cpp](./practical_exercises/key_exercises/读写文件综合题.cpp)
├── [Operator Overloading About Input and Output.cpp](./practical_exercises/key_exercises/输入输出运算符重载.cpp)
├── [Input And Output Overloading.cpp](./practical_exercises/key_exercises/输入输出重载.cpp)
├── [Input Format.cpp](./practical_exercises/key_exercises/输出格式.cpp)
### 2.[C++2.0 New Features](./c++2.0)
#### 2.0 Overview
C++2.0 is an Abbreviation, meaning「modern C++」including C++11/14/17/20.
#### 2.1 [C++11 New Features](./c++2.0/c++11)
- [Variadic Templates](./c++2.0/variadic)
- Spaces in Template Expressions
```cpp
vector<list<int> > //ok in each C++ version
vector<list<int>> // before c++ 11 error error: >> should be > > within a nested template argument list,version beyond c++ 11 could compile successfully
```
- [nullptr and nullptr_t](./c++2.0/nullptr.cpp)
- [Automatic Type Deduction with auto](./c++2.0/auto.cpp)
- [Uniform Initialization ](./c++2.0/uniform_initialization.cpp)
- [initializer_list](./c++2.0/initializer.cpp)
- [explicit for ctors taking more than one argument](./c++2.0/explicit.cpp)
- [range-based for statement](./c++2.0/auto.cpp)
```cpp
for(decl:col) {
statement
}
```
- [=default,=delete](./c++2.0/default_delete.cpp)
If you define a ctor by yourself, compiler won't compile the default ctor.
If you add =default, you could recatch and use default ctor.
- Alias(化名)Template(template typedef)
- [alias.cpp](./c++2.0/alias.cpp)
- [template_template.cpp](./c++2.0/template_template.cpp)
- [template template parameter](./c++2.0/template_template.cpp)
- [type alias](./c++2.0/type_alias.cpp)
- [noexcept](./c++2.0/noexcept.cpp)
- [override](./c++2.0/override.cpp)
- [final](./c++2.0/final.cpp)
- [decltype](./c++2.0/decltype.cpp)
- [lambda](./c++2.0/lambda.cpp)
- [Rvalue reference](./c++2.0/rvalue.cpp)
- [move aware class](./c++2.0/move.cpp)
- Container-Struct And Classify
- (1) Serial containers include`array`(C++2.0 Newly Introduced),`vector`,`deque`,`list`,`forward_list`(C++2.0 Newly Introduced)
- (2) Associated containers include`set/multiset`,`map/multimap`
- (3) Unordered container(C++2.0 Newly Introduced,replace `hash_xxx` to `unordered_xxx`) include`unordered_map/unordered_multimap,unordered_set/unordered_multiset`
- [Hash Function](./c++2.0/hash.cpp)
- [tuple](./c++2.0/tuple.cpp)
Learning Materialhttps://www.bilibili.com/video/av51863195?from=search&seid=3610634846288253061
### 2.2 C++14/17/20
To Be Continued ...
### 3.Design Pattern
- [Singleton pattern](./design_pattern/singleton)
### 4. [STL Source Code Analysis](./src_analysis/stl)
**STL Source Code Analysisgcc 4.9.1**
- [array](./src_analysis/stl/array.md)
- [deque](./src_analysis/stl/deque.md)
- [queue and stack](./src_analysis/stl/queue_stack.md)
- [list](./src_analysis/stl/list.md)
- [vector](./src_analysis/stl/vector.md)
- [typename](./src_analysis/stl/typename.md)
- [traits](./src_analysis/stl/traits.md)
- [iterator](./src_analysis/stl/iterator.md)
- [Talking about STL design and EBO optimization](./src_analysis/stl/谈谈STL设计之EBO优化.md)
- [rb_tree](./src_analysis/stl/rb_tree.md)
- [set and multiset](set_multiset.md)
- [map and multimap](./src_analysis/stl/map_multimap.md)
- [hashtable](./src_analysis/stl/hashtable.md)
- [myhashtable](./src_analysis/stl/myPhashtable.md)
- [unordered_map](./src_analysis/stl/unordered_map.md)
### 4. [Concurrent Programming](./concurrency)
#### 4.1 C++ Concurrency in Action
- [Chapter One](./concurrency/concurrency_v1/chapter1)
- [Chapter Two](./concurrency/concurrency_v1/chapter2)
Learning materials: https://chenxiaowei.gitbook.io/cpp_concurrency_in_action/
#### 4.2 Multithreading And Multiprocess
##### 4.2.1 Threading In C++
- [Introduction](./concurrency/Threading_In_CPlusPlus/1.thread)
- [Five Types of Thread Creation](./concurrency/Threading_In_CPlusPlus/2.create_type)
- [Join And Detachs](./concurrency/Threading_In_CPlusPlus/3.join_detach)
- [mutex in C++ Threading](./concurrency/Threading_In_CPlusPlus/4.mutex)
> From
>
> https://www.youtube.com/watch?v=eZ8yKZo-PGw&list=PLk6CEY9XxSIAeK-EAh3hB4fgNvYkYmghp&index=4
### 5. [C++ Conventional method](./codingStyleIdioms)
##### What is your favorite custom for c ++ programming style?
- [1.ClassInitializers](./codingStyleIdioms/1_classInitializers)
- [2.Replace Enumclass with Namespace](./codingStyleIdioms/2_enumclass_namespace)
- [3.RAII(Resource Acquisition Initialization)](./codingStyleIdioms/3_RAII)
- [4.Copy and Swap](./codingStyleIdioms/4_copy-swap)
- [5.pImpl(Pointer Implement)](./codingStyleIdioms/5_pImpl)
### 6.Learning Courses
#### 6.1 [Chinese Name:极客时间《现代 C++ 实战 30 讲》](https://time.geekbang.org/channel/home)
- [heap、stack、RAIIHow to manage resources for C ++ ?](./learn_class/modern_C++_30/RAII)
- [heap](./modern_++_30/RAII/heap.cpp)
- [stack](./learn_class/modern_C++_30/RAII/stack.cpp)
- [RAII](./learn_class/modern_C++_30/RAII/RAII.cpp)
- [Implementing smart pointers for C ++](./learn_class/modern_C++_30/smart_ptr)
- [auto_ptr、scope_ptr](./learn_class/modern_C++_30/smart_ptr/auto_scope.cpp)
- [unique_ptr](./learn_class/modern_C++_30/smart_ptr/unique_ptr.cpp)
- [shared_ptr](./learn_class/modern_C++_30/smart_ptr/shared_ptr.cpp)
- [What exactly does r value and move solve](./learn_class/modern_C++_30/reference)
- [L value and R value](./learn_class/modern_C++_30/reference/reference.cpp)
- [Extend the declaration cycle](./learn_class/modern_C++_30/reference/lifetime.cpp)
- [Reference folding](./learn_class/modern_C++_30/reference/collapses.cpp)
- [Perfect forward](./learn_class/modern_C++_30/reference/forward.cpp)
- [Do not return Reference](./learn_class/modern_C++_30/reference/don'treturnReference.cpp)
- [Container 1](./learn_class/modern_C++_30/container1)
- [Container 2](./learn_class/modern_C++_30/container2)
- [Exception](./learn_class/modern_C++_30/exception)
- [Literal、Static Assertion And Member Function Specifier](./learn_class/modern_C++_30/literalAssert)
- [Return Object](./learn_class/modern_C++_30/returnObj)c
- [Getting started with generic programming and templates](./learn_class/modern_C++_30/compilerpoly)
- [A whole Compiler Compute World](./learn_class/modern_C++_30/compilercompute)
- [SFINAEWhat is it if it is not replace error?](./learn_class/modern_C++_30/SFINAE)
- [constexprA Normal World](./learn_class/modern_C++_30/constexpr)
- [Function object and LambdafunctionLambda](./learn_class/modern_C++_30/functionLambda)
- [Memory Model and AtomicUnderstangding the complexity of concurrency](./learn_class/modern_C++_30/memorymodel_atomic)
### 7.Tools
#### 7.1 [Container shortcut output tool](./tool/output)
Modified the code, [Click here for the code](./tool/output/output_container.h)
Input
```cpp
map<int, int> mp{
{1, 1},
{2, 4},
{3, 9}};
cout << mp << endl;
```
Output
```cpp
{ 1 => 1, 2 => 4, 3 => 9 }
```
#### 7.2 Output Like PythonJupyter Notebook
- [How to output like python in C/C++](./tool/像Python一样玩CC++.md)
#### 7.3 Observe the changes in the compilation process
- [https://cppinsights.io](https://cppinsights.io/)
#### 7.4 Debug Tools For C ++dbg-macro
- [Debug Tool: dbg-macro](./tool/C++的Debug工具dbg-macro.md)
### 8.Expansion
#### 8.1 Other Problems
- [How to convert string to in C ++](./extension/some_problem/string_int.md)
### 9.Circumstance
- **Running Circumstance**
Ubuntu 18.04
- **IDE**
CLion gcc/g++
### 10.Contributor
| 贡献人 | 地址 |
| ------- | ----------------------------- |
| 光城 | https://github.com/Light-City |
| ChungZH | https://github.com/ChungZH |
| xliu79 | https://github.com/xliu79 |
### 11.About The Writer
个人公众号:
![](./img/wechat.jpg)

View File

@ -8,51 +8,133 @@
## 1.纯虚函数与抽象类
C++中的纯虚函数(或抽象函数)是我们没有实现的虚函数!我们只需声明它!通过声明中赋值0来声明纯虚函数
C++中的纯虚函数(或抽象函数)是我们没有实现的虚函数!我们只需声明它! 通过声明中赋值0来声明纯虚函数
```cpp
// 抽象类
Class A {
public:
virtual void show() = 0; // 纯虚函数
/* Other members */
};
```
对应的代码:[test.cpp](./test.cpp)
* 纯虚函数:没有函数体的虚函数
* 纯虚函数:没有函数体的虚函数
* 抽象类:包含纯虚函数的类
对应的代码:[pure_virtual.cpp](./pure_virtual.cpp)
抽象类只能作为基类来派生新类使用,不能创建抽象类的对象,抽象类的指针和引用->由抽象类派生出来的类的对象!
> 代码样例:[test.cpp](./test.cpp)、[pure_virtual.cpp](./pure_virtual.cpp)
## 2.实现抽象类
抽象类中:在成员函数内可以调用纯虚函数,在构造函数/析构函数内部不能使用纯虚函数。
如果一个类从抽象类派生而来,它必须实现了基类中的所有纯虚函数,才能成为非抽象类。
```cpp
// A为抽象类
class A {
public:
virtual void f() = 0; // 纯虚函数
void g(){ this->f(); }
A(){} // 构造函数
};
对应的代码:[abstract.cpp](./abstract.cpp)
class B : public A{
public:
void f(){ cout<<"B:f()"<<endl;} // 实现了抽象类的纯虚函数
};
```
> 代码样例:[abstract.cpp](./abstract.cpp)
## 3.重要点
- 纯虚函数使一个类变成抽象类
- [纯虚函数使一个类变成抽象类](./interesting_facts1.cpp)
```cpp
// 抽象类至少包含一个纯虚函数
class Base{
public:
virtual void show() = 0; // 纯虚函数
int getX() { return x; } // 普通成员函数
对应的代码:[interesting_facts1.cpp](./interesting_facts1.cpp)
private:
int x;
};
```
- 抽象类类型的指针和引用
- [抽象类类型的指针和引用](./interesting_facts2.cpp)
```cpp
class Derived : public Base {
public:
void show() { cout << "In Derived \n"; } // 实现抽象类的纯虚函数
Derived(){} // 构造函数
};
对应的代码:[interesting_facts2.cpp](./interesting_facts2.cpp)
int main(void)
{
//Base b; // error! 不能创建抽象类的对象
//Base *b = new Base(); error!
Base *bp = new Derived(); // 抽象类的指针和引用 -> 由抽象类派生出来的类的对象
bp->show();
return 0;
}
```
- 如果我们不在派生类中覆盖纯虚函数,那么派生类也会变成抽象类。
- [如果我们不在派生类中覆盖纯虚函数,那么派生类也会变成抽象类](./interesting_facts3.cpp)
```cpp
// Derived为抽象类
class Derived: public Base
{
public:
// void show() {}
};
```
对应的代码:[interesting_facts3.cpp](./interesting_facts3.cpp)
- [抽象类可以有构造函数](./interesting_facts4.cpp)
```cpp
// 抽象类
class Base {
protected:
int x;
public:
virtual void fun() = 0;
Base(int i) { x = i; } // 构造函数
};
// 派生类
class Derived: public Base
{
int y;
public:
Derived(int i, int j) : Base(i) { y = j; } // 构造函数
void fun() { cout << "x = " << x << ", y = " << y; }
};
```
- 抽象类可以有构造函数
- [构造函数不能是虚函数,而析构函数可以是虚析构函数](./interesting_facts5.cpp)
```cpp
// 抽象类
class Base {
public:
Base(){ cout << "Constructor: Base" << endl; }
virtual ~Base(){ cout << "Destructor : Base" << endl; }
virtual void func() = 0;
};
对应的代码:[interesting_facts4.cpp](./interesting_facts4.cpp)
- 构造函数不能是虚函数,而析构函数可以是虚析构函数。
对应的代码:[interesting_facts5.cpp](./interesting_facts5.cpp)
当基类指针指向派生类对象并删除对象时,我们可能希望调用适当的析构函数。如果析构函数不是虚拟的,则只能调用基类析构函数。
class Derived: public Base {
public:
Derived(){ cout << "Constructor: Derived" << endl; }
~Derived(){ cout << "Destructor : Derived" << endl;}
void func(){cout << "In Derived.func()." << endl;}
};
```
>当基类指针指向派生类对象并删除对象时,我们可能希望调用适当的析构函数。
> 如果析构函数不是虚拟的,则只能调用基类析构函数。
## 4.完整实例
抽象类由派生类继承实现!
对应的代码:[derived_full.cpp](./derived_full.cpp)
> 代码样例[derived_full.cpp](./derived_full.cpp)

View File

@ -7,16 +7,12 @@
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
class A {
public:
virtual void f() = 0;
virtual void f() = 0; // 纯虚函数
void g(){ this->f(); }
A(){}
};

View File

@ -21,7 +21,7 @@ class Derived: public Base
{
int y;
public:
void fun() { cout << "fun() called"; } ///< 实现了fun()函数
void fun() { cout << "fun() called"; } // 实现了fun()函数
};
int main(void)

View File

@ -9,7 +9,6 @@
#include<iostream>
using namespace std;
/**
* @brief
*/

View File

@ -9,7 +9,6 @@
#include<iostream>
using namespace std;
class Base
{
int x;

View File

@ -16,14 +16,19 @@ class A
private:
int a;
public:
virtual void show()=0; //< 纯虚函数
virtual void show()=0; // 纯虚函数
};
int main()
{
// 抽象类只能作为基类来派生新类使用,不能创建抽象类的对象,抽象类的指针和引用->由抽象类派生出来的类的对象!
// A a; // error 抽象类,不能创建对象
/*
* 1. 使
* 2. ->
*/
A a; // error 抽象类,不能创建对象
A *a1; // ok 可以定义抽象类的指针
// A *a2 = new A; // error,A是抽象类不能创建对象
A *a2 = new A(); // error, A是抽象类不能创建对象
}

View File

@ -10,12 +10,17 @@
## 1.第一个断言案例
断言,**是宏,而非函数**。assert 宏的原型定义在 <assert.h>C<cassert>C++)中,其作用是如果它的条件返回错误,则终止程序执行。可以通过定义 NDEBUG 来关闭 assert但是需要在源代码的开头include <assert.h> 之前。
断言,**是宏,而非函数**。
assert 宏的原型定义在 <assert.h>C<cassert>C++)中。其作用是如果它的条件返回错误,则终止程序执行。
可以通过定义 `NDEBUG` 来关闭 assert**但是需要在源代码的开头include <assert.h> 之前。**
```c
void assert(int expression);
```
对应代码:[assert.c](./assert.c)
> 代码样例:[assert.c](./assert.c)
```c
#include <stdio.h>
#include <assert.h>
@ -35,22 +40,22 @@ int main()
return 0;
}
```
输出:
```c
assert: assert.c:13: main: Assertion `x==7' failed.
assert: assert.c:13: main: Assertion 'x==7' failed.
```
可以看到输出会把源码文件,行号错误位置,提示出来!
## 2.断言与正常错误处理
断言主要用于检查逻辑上不可能的情况。例如,它们可用于检查代码在开始运行之前所期望的状态,或者在运行完成后检查状态。与正常的错误处理不同,断言通常在运行时被禁用。
+ 断言主要用于检查逻辑上不可能的情况。
忽略断言:
>例如,它们可用于检查代码在开始运行之前所期望的状态,或者在运行完成后检查状态。与正常的错误处理不同,断言通常在运行时被禁用。
在代码开头加上:
+ 忽略断言,在代码开头加上:
```c++
#define NDEBUG // 加上这行,则 assert 不可用
```
对应学习的代码:[ignore_assert.c](./ignore_assert.c)
> 样例代码:[ignore_assert.c](./ignore_assert.c)

Binary file not shown.

Binary file not shown.

View File

@ -6,12 +6,10 @@
* @date 2019-07-25
*/
# define NDEBUG
# define NDEBUG // 忽略断言
#include<assert.h>
int main(){
int x=7;
assert(x==5);

View File

@ -10,47 +10,45 @@
## 2.const作用
1可以定义常量
+ 可以定义常量
```c++
```cpp
const int a=100;
```
2类型检查
+ 类型检查
const常量与#define宏定义常量的区别~~<u>**const常量具有类型编译器可以进行安全检查#define宏定义没有数据类型只是简单的字符串替换不能进行安全检查。**</u>~~感谢两位大佬指出这里问题,见:
+ const常量与`#define`宏定义常量的区别:
> ~~<u>**const常量具有类型编译器可以进行安全检查#define宏定义没有数据类型只是简单的字符串替换不能进行安全检查。**</u>~~感谢两位大佬指出这里问题,见:[issue](https://github.com/Light-City/CPlusPlusThings/issues/5)
> https://github.com/Light-City/CPlusPlusThings/issues/5
+ const定义的变量只有类型为整数或枚举且以常量表达式初始化时才能作为常量表达式。
+ 其他情况下它只是一个 `const` 限定的变量,不要将与常量混淆。
`const` 定义的变量只有类型为整数或枚举,且以常量表达式初始化时才能作为常量表达式。其他情况下它只是一个 `const` 限定的变量,不要将与常量混淆。
+ 防止修改,起保护作用,增加程序健壮性
3防止修改起保护作用增加程序健壮性
```c++
```cpp
void f(const int i){
i++; //error!
}
```
4可以节省空间,避免不必要的内存分配
+ 可以节省空间,避免不必要的内存分配
const定义常量从汇编的角度来看只是给出了对应的内存地址而不是像#define一样给出的是立即数所以const定义的常量在程序运行过程中只有一份拷贝而#define定义的常量在内存中有若干个拷贝。
+ const定义常量从汇编的角度来看只是给出了对应的内存地址而不是像`#define`一样给出的是立即数。
+ const定义的常量在程序运行过程中只有一份拷贝而`#define`定义的常量在内存中有若干个拷贝。
## 3.const对象默认为文件局部变量
<p><font style="color:red">注意非const变量默认为extern。要使const变量能够在其他文件中访问必须在文件中显式地指定它为extern。</font></p>
> 未被const修饰的变量在不同文件的访问
```c++
```cpp
// file1.cpp
int ext
// file2.cpp
#include<iostream>
/**
* by 光城
* compile: g++ -o file file2.cpp file1.cpp
* execute: ./file
*/
extern int ext;
int main(){
std::cout<<(ext+10)<<std::endl;
@ -59,23 +57,18 @@ int main(){
> const常量在不同文件的访问
```c++
```cpp
//extern_file1.cpp
extern const int ext=12;
//extern_file2.cpp
#include<iostream>
/**
* by 光城
* compile: g++ -o file const_file2.cpp const_file1.cpp
* execute: ./file
*/
extern const int ext;
int main(){
std::cout<<ext<<std::endl;
}
```
<p><font style="color:red">小结:可以发现未被const修饰的变量不需要extern显式声明而const常量需要显式声明extern并且需要做初始化因为常量在定义后就不能被修改所以定义时必须初始化。</font></p>
> 小结:<br>可以发现未被const修饰的变量不需要extern显式声明而const常量需要显式声明extern并且需要做初始化因为常量在定义后就不能被修改所以定义时必须初始化。</font></p>
## 4.定义常量
@ -86,7 +79,9 @@ const string s = "helloworld";
const int i,j=0 // error: uninitialized const i
```
上述有两个错误第一b为常量不可更改第二i为常量必须进行初始化(因为常量在定义后就不能被修改,所以定义时必须初始化。)
上述有两个错误:
+ b 为常量,不可更改!
+ i 为常量,必须进行初始化!(因为常量在定义后就不能被修改,所以定义时必须初始化。)
## 5.指针与const
@ -99,13 +94,14 @@ char * const a; //指向类型对象的const指针。或者说常指针、const
const char * const a; //指向const对象的const指针。
```
小结:如果*const*位于`*`的左侧则const就是用来修饰指针所指向的变量即指针指向为常量如果const位于`*`的右侧,*const*就是修饰指针本身,即指针本身是常量。
> **小结:** <br>
> 如果*const*位于`*`的左侧则const就是用来修饰指针所指向的变量即指针指向为常量<br>如果const位于`*`的右侧,*const*就是修饰指针本身,即指针本身是常量。
具体使用如下:
1指向常量的指针
1 **指向常量的指针**
```c++
```cpp
const int *ptr;
*ptr = 10; //error
```
@ -140,12 +136,13 @@ int *ptr1 = &val;
cout<<*ptr<<endl;
```
<p><font style="color:red">小结:对于指向常量的指针,不能通过指针来修改对象的值。<br/>也不能使用void`*`指针保存const对象的地址必须使用const void`*`类型的指针保存const对象的地址。<br/>允许把非const对象的地址赋值给const对象的指针如果要修改指针所指向的对象值必须通过其他方式修改不能直接通过当前指针直接修改。</font></p>
2常指针
> 小结:<br>1.对于指向常量的指针,不能通过指针来修改对象的值。<br>2.不能使用void`*`指针保存const对象的地址必须使用const void`*`类型的指针保存const对象的地址。<br>3.允许把非const对象的地址赋值给const对象的指针如果要修改指针所指向的对象值必须通过其他方式修改不能直接通过当前指针直接修改。
2 **常指针**
const指针必须进行初始化且const指针的值不能修改。
```c++
```cpp
#include<iostream>
using namespace std;
int main(){
@ -162,7 +159,7 @@ int main(){
最后当把一个const常量的地址赋值给ptr时候由于ptr指向的是一个变量而不是const常量所以会报错出现const int`*` -> int `*`错误!
```c++
```cpp
#include<iostream>
using namespace std;
int main(){
@ -174,11 +171,11 @@ int main(){
上述若改为 const int `*`ptr或者改为const int `*`const ptr都可以正常
3指向常量的常指针
3**指向常量的常指针**
理解完前两种情况,下面这个情况就比较好理解了:
```c++
```cpp
const int p = 3;
const int * const ptr = &p;
```
@ -191,17 +188,17 @@ ptr是一个const指针然后指向了一个int 类型的const对象。
这个跟const修饰普通变量以及指针的含义基本相同
1const int
1**const int**
```c++
```cpp
const int func1();
```
这个本身无意义,因为参数返回本身就是赋值给其他的变量!
2const int*
2**const int***
```c++
```cpp
const int* func2();
```
@ -209,7 +206,7 @@ const int* func2();
3int *const
```c++
```cpp
int *const func2();
```
@ -219,7 +216,7 @@ int *const func2();
1传递过来的参数及指针本身在函数内不可变无意义
```c++
```cpp
void func(const int var); // 传递过来的参数不可变
void func(int *const var); // 指针本身不可变
```
@ -228,60 +225,49 @@ void func(int *const var); // 指针本身不可变
输入参数采用“值传递”由于函数将自动产生临时变量用于复制该参数该输入参数本来就无需保护所以不要加const 修饰。
2参数指针所指内容为常量不可变
2**参数指针所指内容为常量不可变**
```c++
```cpp
void StringCopy(char *dst, const char *src);
```
其中src 是输入参数dst 是输出参数。给src加上const修饰后如果函数体内的语句试图改动src的内容编译器将指出错误。这就是加了const的作用之一。
3参数为引用为了增加效率同时防止修改。
3**参数为引用,为了增加效率同时防止修改。**
```c++
```cpp
void func(const A &a)
```
对于非内部数据类型的参数而言象void func(A a) 这样声明的函数注定效率比较低。因为函数体内将产生A 类型
的临时对象用于复制参数a而临时对象的构造、复制、析构过程都将消耗时间。
对于非内部数据类型的参数而言象void func(A a) 这样声明的函数注定效率比较低。因为函数体内将产生A 类型的临时对象用于复制参数a而临时对象的构造、复制、析构过程都将消耗时间。
为了提高效率可以将函数声明改为void func(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临
时对象。
时对象。但是函数void func(A &a) 存在一个缺点:
“引用传递”有可能改变参数a这是我们不期望的。解决这个问题很容易加const修饰即可因此函数最终成为
> 但是函数void func(A &a) 存在一个缺点:<br><br>“引用传递”有可能改变参数a这是我们不期望的。解决这个问题很容易加const修饰即可因此函数最终成为
void func(const A &a)。
以此类推是否应将void func(int x) 改写为void func(const int &x),以便提高效率?完全没有必要,因为内部数
据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。
<p><font style="color:red">小结对于非内部数据类型的输入参数应该将“值传递”的方式改为“const 引用传递”目的是提高效率。例如将void func(A a) 改为void func(const A &a)。<br/>对于内部数据类型的输入参数不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的又降低了函数的可理解性。例如void func(int x) 不应该改为void func(const int &x)。</font></p>
> 小结:<br>1.对于非内部数据类型的输入参数应该将“值传递”的方式改为“const 引用传递”目的是提高效率。例如将void func(A a) 改为void func(const A &a)。<br><br>2.对于内部数据类型的输入参数不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的又降低了函数的可理解性。例如void func(int x) 不应该改为void func(const int &x)。</font></p>
以上解决了两个面试问题:
1如果函数需要传入一个指针是否需要为该指针加上const把const加在指针不同的位置有什么区别
2如果写的函数需要传入的参数是一个复杂类型的实例传入值参数或者引用参数有什么区别什么时候需要为传入的引用参数加上const。
+ 如果函数需要传入一个指针是否需要为该指针加上const把const加在指针不同的位置有什么区别
+ 如果写的函数需要传入的参数是一个复杂类型的实例传入值参数或者引用参数有什么区别什么时候需要为传入的引用参数加上const。
## 7.类中使用const
在一个类中任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时不慎修改
数据成员或者调用了其它非const成员函数编译器将指出错误这无疑会提高程序的健壮性。使用const关
字进行说明的成员函数称为常成员函数。只有常成员函数才有资格操作常量或常对象没有使用const关键字
明的成员函数不能用来操作常对象。
在一个类中任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时不慎修改 数据成员或者调用了其它非const成员函数编译器将指出错误这无疑会提高程序的健壮性。
使用const关键字进行说明的成员函数称为常成员函数。只有常成员函数才有资格操作常量或常对象没有使用const关键字进行说明的成员函数不能用来操作常对象。
对于类中的const成员变量必须通过初始化列表进行初始化如下所示
```c++
class Apple
{
```cpp
class Apple{
private:
int people[100];
public:
@ -299,7 +285,7 @@ const对象只能访问const成员函数,而非const对象可以访问任意的
例如:
```c++
```cpp
//apple.cpp
class Apple
{
@ -347,8 +333,11 @@ int main(){
b.add(100);
return 0;
}
//编译: g++ -o main main.cpp apple.cpp
//结果
```
> 编译: g++ -o main main.cpp apple.cpp<br>
结果:
```
take func 1
2
take func 10
@ -365,21 +354,21 @@ take func 100
第一将常量定义与static结合也就是
```c++
```cpp
static const int apple_number
```
第二:在外面初始化:
```c++
```cpp
const int Apple::apple_number=10;
```
当然如果你使用c++11进行编译直接可以在定义出初始化可以直接写成
```c++
```cpp
static const int apple_number=10;
或者
// 或者
const int apple_number=10;
```
@ -393,13 +382,13 @@ const int apple_number=10;
在类中声明:
```c++
```cpp
static int ap;
```
在类实现文件中使用:
```c++
```cpp
int Apple::ap=666
```

View File

@ -47,7 +47,7 @@ for (vectype i = vec.begin; i != vec.end(); i++)
struct
{
int d ;
doubel b;
double b;
}anon_s;
```

View File

@ -50,7 +50,7 @@ namespace Color
这样之后就可以用 `Color::Type c = Color::RED;` 来定义新的枚举变量了。如果 `using namespace Color` 后,前缀还可以省去,使得代码简化。不过,因为命名空间是可以随后被扩充内容的,所以它提供的作用域封闭性不高。在大项目中,还是有可能不同人给不同的东西起同样的枚举类型名。
更“有效”的办法是用一个类或结构体来限定其作用域,例如:定义新变量的方法和上面命名空间的相同。不过这样就不用担心类在别处被修改内容。这里用结构体而非类,是因为本身希望这些常量可以公开访问,二是因为它只包含数据没有成员函数
更“有效”的办法是用一个类或结构体来限定其作用域,例如:定义新变量的方法和上面命名空间的相同。不过这样就不用担心类在别处被修改内容。这里用结构体而非类,是因为本身希望这些常量可以公开访问。
```c++
struct Color1
@ -153,4 +153,4 @@ public:
枚举常量不会占用对象的存储空间,它们在编译时被全部求值。
枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点。
枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点。

View File

@ -99,6 +99,21 @@ gcc -c add.c
g++ add.cpp add.o -o main
```
而通常为了C代码能够通用即既能被C调用又能被C++调用,头文件通常会有如下写法:
```c
#ifdef __cplusplus
extern "C"{
#endif
int add(int x,int y);
#ifdef __cplusplus
}
#endif
```
即在C++调用该接口时会以C接口的方式调用。这种方式使得C++者不需要额外的extern C而标准库头文件通常也是类似的做法否则你为何不需要extern C就可以直接使用stdio.h中的C函数呢
上述案例源代码见:
- [add.h](extern_c++/add.h)
@ -191,3 +206,5 @@ int add(){
extern int add();
```
不过与C++调用C接口不同C++确实是能够调用编译好的C函数而这里C调用C++不过是把C++代码当成C代码编译后调用而已。也就是说C并不能直接调用C++库函数。

View File

@ -90,7 +90,7 @@ int main()
## 2.虚函数virtual可以是内联函数inline
- 虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。
- 内联是在编译建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。
- 内联是在编译建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。
- `inline virtual` 唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 `Base::who()`),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。
```c++

View File

@ -21,7 +21,7 @@ class Base {
Base():value(20) {}
virtual ~Base() {}
void test1() { cout << "Base test1..." << endl; }
protected: //私有
private: //私有
int value;
};

View File

@ -38,7 +38,7 @@ static成员函数不属于任何类对象或类实例所以即使给此函
2**构造函数可以为虚函数吗?**
构造函数不可以声明为虚函数。同时除了inline之外构造函数不允许使用其它任何关键字。
构造函数不可以声明为虚函数。同时除了inline|explicit之外,构造函数不允许使用其它任何关键字。
为什么构造函数不可以为虚函数?
@ -86,7 +86,7 @@ static成员函数不属于任何类对象或类实例所以即使给此函
- [inline_virtual.cpp](./set3/inline_virtual.cpp)
## 5.RTTI与dynamic_cast
## 5.RTTI与dynamic_cast
RTTIRun-Time Type Identification),通过运行时类型信息程序能够使用[基类](https://baike.baidu.com/item/%E5%9F%BA%E7%B1%BB/9589663)的[指针](https://baike.baidu.com/item/%E6%8C%87%E9%92%88/2878304)或引用来检查这些指针或引用所指的对象的实际[派生类](https://baike.baidu.com/item/%E6%B4%BE%E7%94%9F%E7%B1%BB)型。
@ -99,4 +99,4 @@ RTTIRun-Time Type Identification),通过运行时类型信息程序能够
## 6.纯虚函数和抽象类
见[纯虚函数和抽象类那些事](../abstract)
见[纯虚函数和抽象类那些事](../abstract)

View File

@ -114,9 +114,9 @@ int main(void)
Base &p = d; // 基类引用指向派生类实例
cout<<"基类对象直接调用"<<endl;
ptr.fun1();
cout<<"基类引用指向派生类实例"<<endl;
cout<<"基类对象调用基类实例"<<endl;
pp.fun1();
cout<<"基类指针指向派生类实例并调用虚函数"<<endl;
cout<<"基类指针指向类实例并调用虚函数"<<endl;
pt->fun1();
cout<<"基类引用指向基类实例并调用虚函数"<<endl;
p.fun1();

View File

@ -27,8 +27,12 @@ void some_core_part_of_algorithm() {
}
int main() {
std::cout << std::this_thread::get_id() << endl;
master_thread = std::this_thread::get_id();
std::cout << "master_thread: " << master_thread << endl;
cout << "master_thread 中运行:" << endl;
some_core_part_of_algorithm();
cout << "thread 中运行:" << endl;
thread t(some_core_part_of_algorithm);
t.join();
return 0;
}
}

View File

@ -0,0 +1,104 @@
#include <iostream>
#include <vector>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <unistd.h>
using namespace std;
const int MAX_NUM = 10000;
class BoundedBuffer
{
public:
BoundedBuffer(size_t n) {
array_.resize(n);
start_pos_ = 0;
end_pos_ = 0;
pos_ = 0;
}
void Produce(int n) {
{
std::unique_lock<std::mutex> lock(mtx_);
//wait for not full
not_full_.wait(lock, [=] { return pos_ < array_.size(); });
usleep(1000 * 400);
array_[end_pos_] = n;
end_pos_ = (end_pos_ + 1) % array_.size();
++pos_;
cout << "Produce pos:" << pos_ << endl;
} //auto unlock
not_empty_.notify_one();
}
int Consume() {
std::unique_lock<std::mutex> lock(mtx_);
//wait for not empty
not_empty_.wait(lock, [=] { return pos_ > 0; });
usleep(1000 * 400);
int n = array_[start_pos_];
start_pos_ = (start_pos_ + 1) % array_.size();
--pos_;
cout << "Consume pos:" << pos_ << endl;
lock.unlock();
not_full_.notify_one();
return n;
}
private:
std::vector<int> array_;
size_t start_pos_;
size_t end_pos_;
size_t pos_;
std::mutex mtx_;
std::condition_variable not_full_;
std::condition_variable not_empty_;
};
BoundedBuffer bb(10);
std::mutex g_mtx;
void Producer()
{
int n = 0;
while(n < 100) {
bb.Produce(n);
cout << "Producer:" << n << endl;
n++;
}
bb.Produce(-1);
}
void Consumer()
{
std::thread::id thread_id = std::this_thread::get_id();
int n = 0;
do {
n = bb.Consume();
cout << "Consumer thread:" << thread_id << "=====> " << n << endl;
} while(-1 != n);
bb.Produce(-1);
}
int main()
{
std::vector<std::thread> t;
t.push_back(std::thread(&Producer));
t.push_back(std::thread(&Consumer));
t.push_back(std::thread(&Consumer));
t.push_back(std::thread(&Consumer));
for (auto& one : t) {
one.join();
}
return 0;
}

View File

@ -164,7 +164,7 @@ p = new singleton;
- 线程A调用instance执行第一次p的测试获得锁按照1,3,执行然后被挂起。此时p是非空的但是p指向的内存中还没有Singleton对象被构造。
- 线程B调用instance判定p非空 将其返回给instance的调用者。调用者对指针解引用以获得singleton一个还没有被构造出的对象。bug就出现了。
DCLP能够良好的工作仅当步骤一和二在步骤三之前被执行但是并没有并没有方法在C或C++中表达这种限制。这就像是插在DCLP心脏上的一把匕首我们需要在相对指令顺序上定义限制但是我们的语言没有给出表达这种限制的方法。
DCLP能够良好的工作仅当步骤一和二在步骤三之前被执行但是并没有方法在C或C++中表达这种限制。这就像是插在DCLP心脏上的一把匕首我们需要在相对指令顺序上定义限制但是我们的语言没有给出表达这种限制的方法。
## 5.memory barrier指令
@ -324,4 +324,4 @@ public:
> https://www.cnblogs.com/liyuan989/p/4264889.html
> https://segmentfault.com/a/1190000015950693
> https://segmentfault.com/a/1190000015950693

View File

@ -0,0 +1,142 @@
# Pure virtual functions and abstract classes
## About Author
![](../img/wechat.jpg)
## 1.Pure virtual function and abstract class
Pure virtual functions (or abstract functions) in C + + are virtual functions that we have not implemented!We just need to state it!
example:
```cpp
// abstract class
Class A {
public:
virtual void show() = 0; // pure virtual function
/* Other members */
};
```
* Pure virtual function: virtual function without function body
* Abstract classes: classes containing pure virtual functions
Abstract classes can only be used as base classes to derive new classes. Objects, pointers and references of abstract classes cannot be created->An object of a class derived from an abstract class!
> Code example[test.cpp](./test.cpp)、[pure_virtual.cpp](./pure_virtual.cpp)
## 2.Implement abstract classes
Abstract classPure virtual functions can be called within member functions.Pure virtual functions cannot be used inside constructors / destructors.
If a class derives from an abstract class, it must implement all pure virtual functions in the base class to become a non abstract class.
```cpp
// A is abstract class
class A {
public:
virtual void f() = 0; // pure virtual function
void g(){ this->f(); }
A(){} // 构造函数
};
class B : public A{
public:
void f(){ cout<<"B:f()"<<endl;} // 实现了抽象类的纯虚函数
};
```
> Code Example[abstract.cpp](./abstract.cpp)
## 3.Key point
- [Pure virtual functions make a class abstract](./interesting_facts1.cpp)
```cpp
// Abstract class contains at least one pure virtual function
class Base{
public:
virtual void show() = 0; // 纯虚函数
int getX() { return x; } // 普通成员函数
private:
int x;
};
```
- [Pointers and references to abstract class types](./interesting_facts2.cpp)
```cpp
class Derived : public Base {
public:
void show() { cout << "In Derived \n"; } // 实现抽象类的纯虚函数
Derived(){} // 构造函数
};
int main(void)
{
//Base b; // error! 不能创建抽象类的对象
//Base *b = new Base(); error!
Base *bp = new Derived(); // 抽象类的指针和引用 -> 由抽象类派生出来的类的对象
bp->show();
return 0;
}
```
- [If we do not override pure virtual functions in the derived class, the derived class will also become an abstract class](./interesting_facts3.cpp)
```cpp
// Derived为抽象类
class Derived: public Base
{
public:
// void show() {}
};
```
- [Abstract classes can have constructors](./interesting_facts4.cpp)
```cpp
// abstract class
class Base {
protected:
int x;
public:
virtual void fun() = 0;
Base(int i) { x = i; } // constructor function
};
// 派生类
class Derived: public Base
{
int y;
public:
Derived(int i, int j) : Base(i) { y = j; } // constructor function
void fun() { cout << "x = " << x << ", y = " << y; }
};
```
- [A constructor cannot be a virtual function, and a destructor can be a virtual destructor](./interesting_facts5.cpp)
```cpp
// 抽象类
class Base {
public:
Base(){ cout << "Constructor: Base" << endl; }
virtual ~Base(){ cout << "Destructor : Base" << endl; }
virtual void func() = 0;
};
class Derived: public Base {
public:
Derived(){ cout << "Constructor: Derived" << endl; }
~Derived(){ cout << "Destructor : Derived" << endl;}
void func(){cout << "In Derived.func()." << endl;}
};
```
>When the base class pointer points to a derived class object and removes the object, we may want to call the appropriate destructor.
>The destructor can only be called if it is not a virtual destructor.
## 4.Complete example
Abstract classes are inherited and implemented by derived classes!
> Code Example[derived_full.cpp](./derived_full.cpp)

View File

@ -0,0 +1,27 @@
/**
* @file abstract.cpp
* @brief /使
*
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
class A {
public:
virtual void f() = 0; // 纯虚函数
void g(){ this->f(); }
A(){}
};
class B:public A{
public:
void f(){ cout<<"B:f()"<<endl;}
};
int main(){
B b;
b.g();
return 0;
}

View File

@ -0,0 +1,32 @@
/**
* @file derived_full.cpp
* @brief
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
class Base
{
int x;
public:
virtual void fun() = 0;
int getX() { return x; }
};
class Derived: public Base
{
int y;
public:
void fun() { cout << "fun() called"; } // 实现了fun()函数
};
int main(void)
{
Derived d;
d.fun();
return 0;
}

View File

@ -0,0 +1,28 @@
/**
* @file interesting_facts1.cpp
* @brief 使
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
/**
* @brief
*/
class Test
{
int x;
public:
virtual void show() = 0;
int getX() { return x; }
};
int main(void)
{
Test t; //error! 不能创建抽象类的对象
return 0;
}

View File

@ -0,0 +1,38 @@
/**
* @file interesting_facts2.cpp
* @brief
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
/**
* @brief
*/
class Base
{
int x;
public:
virtual void show() = 0;
int getX() { return x; }
};
class Derived: public Base
{
public:
void show() { cout << "In Derived \n"; }
Derived(){}
};
int main(void)
{
//Base b; //error! 不能创建抽象类的对象
//Base *b = new Base(); error!
Base *bp = new Derived(); // 抽象类的指针和引用 -> 由抽象类派生出来的类的对象
bp->show();
return 0;
}

View File

@ -0,0 +1,29 @@
/**
* @file interesting_facts3.cpp
* @brief
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
class Base
{
int x;
public:
virtual void show() = 0;
int getX() { return x; }
};
class Derived: public Base
{
public:
// void show() { }
};
int main(void)
{
Derived d; //error! 派生类没有实现纯虚函数,那么派生类也会变为抽象类,不能创建抽象类的对象
return 0;
}

View File

@ -0,0 +1,35 @@
/**
* @file interesting_facts4.cpp
* @brief
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
// An abstract class with constructor
class Base
{
protected:
int x;
public:
virtual void fun() = 0;
Base(int i) { x = i; }
};
class Derived: public Base
{
int y;
public:
Derived(int i, int j):Base(i) { y = j; }
void fun() { cout << "x = " << x << ", y = " << y; }
};
int main(void)
{
Derived d(4, 5);
d.fun();
return 0;
}

View File

@ -0,0 +1,30 @@
/**
* @file interesting_facts5.cpp
* @brief
*
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
class Base {
public:
Base() { cout << "Constructor: Base" << endl; }
virtual ~Base() { cout << "Destructor : Base" << endl; }
};
class Derived: public Base {
public:
Derived() { cout << "Constructor: Derived" << endl; }
~Derived() { cout << "Destructor : Derived" << endl; }
};
int main() {
Base *Var = new Derived();
delete Var;
return 0;
}

View File

@ -0,0 +1,34 @@
/**
* @file pure_virtual.cpp
* @brief
*
*
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
class A
{
private:
int a;
public:
virtual void show()=0; // 纯虚函数
};
int main()
{
/*
* 1. 使
* 2. ->
*/
A a; // error 抽象类,不能创建对象
A *a1; // ok 可以定义抽象类的指针
A *a2 = new A(); // error, A是抽象类不能创建对象
}

View File

@ -0,0 +1,23 @@
/**
* @file test.cpp
* @brief C++()!0
*
* @author
* @version v1
* @date 2019-07-20
*/
/**
* @brief
*/
class Test
{
// Data members of class
public:
// Pure Virtual Function
virtual void show() = 0;
/* Other members */
};

View File

@ -0,0 +1,59 @@
# Things about assert
## About Author
![](../img/wechat.jpg)
## 1.First assertion case
assert**is macrorather than function**。
assert The prototype of a macro is defined in <assert.h>C<cassert>C++.If its condition returns an errorProgram execution is terminated.
You can close assert by defining 'ndebug', **But it needs to be at the beginning of the source codebefore include <assert.h>.**
```c
void assert(int expression);
```
> Code Example[assert.c](./assert.c)
```c
#include <stdio.h>
#include <assert.h>
int main()
{
int x = 7;
/* Some big code in between and let's say x
is accidentally changed to 9 */
x = 9;
// Programmer assumes x to be 7 in rest of the code
assert(x==7);
/* Rest of the code */
return 0;
}
```
Output
```c
assert: assert.c:13: main: Assertion 'x==7' failed.
```
## 2.Assertion and normal error handling
+ Assertions are mainly used to check for logically impossible situations.
>For example, they can be used to check the state that code expects before it starts to run, or after the run is complete. Unlike normal error handling, assertions are usually disabled at run time.
+ Ignore the assertion and add at the beginning of the code
```c++
#define NDEBUG // Adding this linethen you do not need the assert
```
> Code Example[ignore_assert.c](./ignore_assert.c)

View File

@ -0,0 +1,18 @@
#include <stdio.h>
#include <assert.h>
int main()
{
int x = 7;
/* Some big code in between and let's say x
* is accidentally changed to 9 */
x = 9;
// Programmer assumes x to be 7 in rest of the code
assert(x==7);
/* Rest of the code */
return 0;
}

View File

@ -0,0 +1,17 @@
/**
* @file ignore_assert.c
* @brief
* @author
* @version v1
* @date 2019-07-25
*/
# define NDEBUG // 忽略断言
#include<assert.h>
int main(){
int x=7;
assert(x==5);
return 0;
}

View File

@ -0,0 +1,177 @@
## About Author
![](../img/wechat.jpg)
## What is Bit field
“ Bit field is a kind of data structure.Data can be stored compactly in bits, And allows the programmer to operate on the bits of this structure. One of the advantages of this data structure is that it can save storage space in data units, which is particularly important when programs need thousands of data units. The second advantage is that bit segments can easily access part of the contents of an integer value, which can simplify the program source code. The disadvantage of this data structure is that bit segment implementation depends on specific machines and systems, and different results may be obtained in different platforms, which leads to the fact that bit segments are not portable in nature
- The layout of bit fields in memory is machine dependent
- The type of bit field must be integer or enumeration type. The behavior of bit field in signed type depends on the implementation
- The addressing operator (&) cannot be applied to a bit field, and no pointer can point to a bit field of a class
## Bit field usage
Bit fields usually use struct declarations, which set the name of each bit field member and determine its width:
```
struct bit_field_name
{
type member_name : width;
};
```
| Elements | Description |
| -------------- | ------------------------------------------------------------ |
| bit_field_name | Bit field structure name |
| type | must be int、signed int or unsigned int type |
| member_name | |
| width | |
For example, declare the following bit field:
```
struct _PRCODE
{
unsigned int code1: 2;
unsigned int cdde2: 2;
unsigned int code3: 8;
};
struct _PRCODE prcode;
```
This definition makes' prcode 'contain two 2-bit fields and one 8-bit field. We can use the member operator of the structure to assign values to it
```
prcode.code1 = 0;
prcode.code2 = 3;
procde.code3 = 102;
```
When assigning a value, it should be noted that the size of the value should not exceed the capacity of the bit field memberFor example prcode.code3 Is a bit domain member of 8 bits. Its capacity is 2^8 = 256Assignment range should be [0,255]。
## Size and alignment of bit fields
### Size of bit field
For example, the following bit field
```
struct box
{
unsigned int a: 1;
unsigned int : 3;
unsigned int b: 4;
};
```
There is an unnamed bit field in the middle of the bit field structure, which occupies 3 bits and only plays a filling role and has no practical significance. The padding makes the structure use 8 bits in total. But C language uses unsigned int as the basic unit of bit fieldEven if the only member of a structure is a bit field of 1 bit, the size of the structure is the same as that of an unsigned int.In some systems, the unsigned int is 16 bits, and in x86 systems it is 32 bits.For the following articles, the default value of unsigned int is 32 bits.
### Alignment of bit fields
A bit field member is not allowed to cross the boundary of two unsigned ints. If the total number of bits declared by a member exceeds the size of an unsigned int, the editor will automatically shift the bit field members to align them according to the boundary of the unsigned int
For example
```
struct stuff
{
unsigned int field1: 30;
unsigned int field2: 4;
unsigned int field3: 3;
};
```
`field1` + `field2` = 34 Bitsbeyond 32 Bits, Complier`field2` move to the next unsigned int unit. stuff.field1 and stuff.field2 will leave the 2 Bits space stuff.field3 follow closely stuff.field2.The structure is now of size 2 * 32 = 64 Bits。
This hole can be filled with the unnamed bit field member mentioned earlier, or we can use an unnamed bit field member with a width of 0 to align the next field member with the next integer.
For example:
```
struct stuff
{
unsigned int field1: 30;
unsigned int : 2;
unsigned int field2: 4;
unsigned int : 0;
unsigned int field3: 3;
};
```
Between stuff.field1 and stuff.field2 there is a 2 Bits space. Stuff.field3 will be stored in the next unsigned in. The size of this structure is 3 * 32 = 96 Bits。
Code[learn.cpp](learn.cpp)
## Initialization of bit field and remapping of bit
### Initialization
The initialization method of bit field is the same as that of ordinary structure. Here, two methods are listed as follows:
```
struct stuff s1= {20,8,6};
```
Or directly assign values to the bit field members:
```
struct stuff s1;
s1.field1 = 20;
s1.field2 = 8;
s1.field3 = 4;
```
### Re-mapping of bit field
Declare a bit field with a size of 32 bits
```
struct box {
unsigned int ready: 2;
unsigned int error: 2;
unsigned int command: 4;
unsigned int sector_no: 24;
}b1;
```
#### Zeroing bit field by remapping
```
int* p = (int *) &b1; // 将 "位域结构体的地址" 映射至 "整形int*) 的地址"
*p = 0; // clear s1, set all members to zero
```
#### The 32 bits bit field is remapped to the unsigned int type by union
Let's briefly introduce the alliance
> "Union" is a special class and a data structure of construction type.Many different data types can be defined in a "union". Any kind of data defined by the "union" can be loaded into a variable described as the "union" type. These data share the same memory to save space
>
> There are some similarities between "union" and "structure". But there are essential differences between them.In a structure, each member has its own memory space. The total length of a structure variable is the sum of the length of each member (except for empty structure, and boundary adjustment is not considered).In Union, members share a certain amount of memory space, and the length of a union variable is equal to the longest length of each member.It should be noted that the so-called sharing does not mean that multiple members are loaded into a joint variable at the same time, but that the joint variable can be assigned any member value, but only one value can be assigned at a time.
We can declare the following Union:
```
union u_box {
struct box st_box;
unsigned int ui_box;
};
```
In x86 system, unsigned int and box are 32 Bits, Through this combination, St_ Box and UI_ Box shares a piece of memory.Which bit in the specific bit field corresponds to which bit of the unsigned int depends on the compiler and hardware.Use union to return the bit field to zero. The code is as follows:
```
union u_box u;
u.ui_box = 0;
```
> From<http://www.yuan-ji.me/C-C-%E4%BD%8D%E5%9F%9F-Bit-fields-%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/>

View File

@ -0,0 +1,19 @@
#include<iostream>
using namespace std;
struct stuff
{
unsigned int field1: 30;
unsigned int : 2;
unsigned int field2: 4;
unsigned int : 0;
unsigned int field3: 3;
};
int main(){
struct stuff s={1,3,5};
cout<<s.field1<<endl;
cout<<s.field2<<endl;
cout<<s.field3<<endl;
cout<<sizeof(s)<<endl;
return 0;
}

View File

@ -0,0 +1,46 @@
# Object oriented features of C + + implemented by C
## About Author
![](../img/wechat.jpg)
## 1.C++
Polymorphism in C ++ :In C++, we usually maintain a virtual function table. According to the assignment compatibility rule, we know that the pointer or reference of the parent class can point to the child class object
If the pointer or reference of a parent class calls the virtual function of the parent class, the pointer of the parent class will look up its function address in its own virtual function table.If the pointer or reference of the parent object points to an object of a subclass, and the subclass has overridden the virtual function of the parent class, the pointer will call the overridden virtual function of the subclass.
Code Example:[c++_examp.cpp](./c++_examp.cpp)
## 2.C Implement
- Encapsulation
There is no concept of class class in C language. But with struct structure, we can use struct to simulate
Encapsulating properties and methods into structures using function pointers.
- Inherit
Structure nesting
- Polymorphic
Class and subclass methods have different function pointers
There is no member function in the structure of C language. How to realize the common function of parent structure and child structure? We can consider using function pointers to simulate. But there is a flaw in this approachThe function pointer between the parent and child does not point to the virtual function table maintained in C ++, but a piece of physical memory. If there are too many simulated functions, it will not be easy to maintain.
In order to simulate polymorphism, function pointer variables must be aligned(They are completely consistent in content and alignment of variables).Otherwise, the parent class pointer points to the child class object, and the operation crashes!
Code example :[c_examp.c](./c_examp.c)

Binary file not shown.

View File

@ -0,0 +1,43 @@
/**
* @file c++_examp.cpp
* @brief c++
* @author
* @version v1
* @date 2019-08-06
*/
#include <iostream>
using namespace std;
class A
{
public:
virtual void f()//Implement a virtual function
{
cout << "Base A::f() " << endl;
}
};
class B:public A // 必须为共有继承否则后面调用不到class默认为私有继承
{
public:
virtual void f()//Virtual function implementation, virtual keyword in subclass can not be appearence
{
cout << "Derived B::f() " << endl;
}
};
int main()
{
A a;//Base class object
B b;//an object of derived type
A* pa = &a;//The parent class pointer points to the parent object
pa->f();//Call the function of the parent class
pa = &b; //The parent class pointer points to the subclass object, which is implemented in polymorphism
pa->f();//Call the function with the same name of the derived class
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,55 @@
/**
* @file c_examp.c
* @brief C实现多态
* @author
* @version v1
* @date 2019-08-06
*/
#include <stdio.h>
/// Define a pointer of function
typedef void (*pf) ();
/**
* @brief parent class
*/
typedef struct _A
{
pf _f;
}A;
/**
* @brief child class
*/
typedef struct _B
{
A _b; ///< The inheritance of the parent class can be realized by defining an object of the base class in the subclass
}B;
void FunA()
{
printf("%s\n","Base A::fun()");
}
void FunB()
{
printf("%s\n","Derived B::fun()");
}
int main()
{
A a;
B b;
a._f = FunA;
b._b._f = FunB;
A *pa = &a;
pa->_f();
pa = (A *)&b; /// The parent class pointer points to the object of the subclass. Because of the type mismatch, it needs to be forced
pa->_f();
return 0;
}

View File

@ -0,0 +1,382 @@
## 1.The Definition Of const
Const type is that people use type specifier **const** signiture type to demonstrateconst variables or objects can not be updated。
## 2. Effect Of Const
1define variable
```
const int a=100;
```
(2) check type
The difference between const variable and define variable: ~~<u>**Constants have types, which can be checked by the compiler; the define macro definition has no data type, it is just a simple string replacement, and cannot be checked for security
**</u>~~ Thanks for point this bug out.
> https://github.com/Light-City/CPlusPlusThings/issues/5
Only variables of type integer or enumeration are defined by `const`. In other cases, it is only a 'const' qualified variable and should not be confused with constants.
3prevent modification, protect and increase program robustness
```
void f(const int i){
i++; //error!
}
```
4Save space and avoid unnecessary memory allocation
From the compile point of view, the variables can be defined by const only give the corresponding memory address. Meanwhile the #define gives an immediate number.
## 3.const object is the file local variable by default
<p><font style="color:red">Attentionnot const will be set as extern by default.For the const variable to be accessible in other files, it must be explicitly specified as extern in the file
</font></p>
> Access of variables not modified by const in different files
```
// file1.cpp
int ext
// file2.cpp
#include<iostream>
/**
* by 光城
* compile: g++ -o file file2.cpp file1.cpp
* execute: ./file
*/
extern int ext;
int main(){
std::cout<<(ext+10)<<std::endl;
}
```
You can find that variables that are not modified by const do not need to be explicitly declared by extern! Const constants need to be explicitly declared extern and need to be initialized! Because constants cannot be modified after they are defined, they must be initialized
## 4.Define Variable
```
const int b = 10;
b = 0; // error: assignment of read-only variable b
const string s = "helloworld";
const int i,j=0 // error: uninitialized const i
```
There are two errors above. First, B is a constant and cannot be changed! Second: I is a constant and must be initialized! (since constants cannot be modified after definition, they must be initialized. )
## 5.Pointer and Const
There are four kinds of pointer related consts
```
const char * a; //A pointer to a const object, or a pointer to a constant.
char const * a; //same as above
char * const a; //Const pointer to the type object. Or constant pointer, const pointer.
const char * const a; //Const pointer to const object
```
Conclusion: If *const* is on the left of `*`, const is used to modify the variable that the pointer points to, that is, the pointer points to a constant. If *const* is on the right of `*`, then the const is used to modify the pointer itself, that is, the pointer itself is a constant.
The specific method is as follows:
(1) pointer to const:
```
const int *ptr;
*ptr = 10; //error
```
ptr is a pointer to a const object of type int. Const defines the int type, that is, the type of object PTR points to, not the PTR itself.Therefore, ptr do not need to be assigned an initial value. However, the value of the object in question cannot be modified by ptr. Besides, we can not use void `*` pointer to save the address of const object
```
const int p = 10;
const void * vp = &p;
void *vp = &p; //error
```
Another key point is: we allow the address of a non const object to be assigned to a pointer to a const object.
Example:
```
const int *ptr;
int val = 3;
ptr = &val; //ok
```
We can't change the val value through the ptr pointer, even if it points to a non const object
```
int *ptr1 = &val;
*ptr1=4;
cout<<*ptr<<endl;
```
We cannot modify the underlying object with a pointer to the const object
However, if the pointer points to a non const object, the object it refers to can be modified in other ways.
```
int *ptr1 = &val;
*ptr1=4;
cout<<*ptr<<endl;
```
Conclusion: For a pointer to a constant, the value of the object cannot be modified by the pointer. And You cannot use the void `*` pointer to save the address of the const object. You must use a pointer of type const void `*` to hold the address of the const object.
(2) Constant pointer
The const pointer must be initialized and the value of the const pointer cannot be modified.
```
#include<iostream>
using namespace std;
int main(){
int num=0;
int * const ptr=&num; //const指针必须初始化且const指针的值不能修改
int * t = &num;
*t = 1;
cout<<*ptr<<endl;
}
```
Modify the value pointed by ptr pointer, which can be modified by non const pointer
Finally, when the address of a const constant is assigned to ptr, an error will be reported because ptr points to a variable rather than const constant.
```
#include<iostream>
using namespace std;
int main(){
const int num=0;
int * const ptr=&num; //error! const int* -> int*
cout<<*ptr<<endl;
}
```
If changed to const int `*`ptr or const int `*`const ptr, no errors have occurred.
(3) Constant pointer to a constant
```
const int p = 3;
const int * const ptr = &p;
```
PTR is a const pointer and then points to a const object of type int
## 6. Using const in function
Return value of const decorated function
The meaning of const modifying ordinary variables and pointers is basically the same
1const int
```
const int func1();
```
It doesn't make sense, because the parameter return itself is assigned to other variables
2const int*
```
const int* func2();
```
The pointer points to the same content
3int *const
```
int *const func2();
```
The pointer itself is immutable
Const modifier function parameters.
The passed parameters and pointers themselves are immutable and meaningless in the function.
```
void func(const int var); // parameters are immutable
void func(int *const var); // point itself is immutable
```
(2) Parameter pointer refers to a constant and is immutable
```
void StringCopy(char *dst, const char *src);
```
SRC is the input parameter and DST is the output parameter. After adding const modifier to SRC, if the statement in the function body tries to change the contents of SRC, the compiler will point out the error
This is one of the effects of const.
(3) The parameter is a reference. In order to increase efficiency and prevent modification at the same time
```
void func(const A &a)
```
For parameters of Non internal data types, Functions such as void func (A, a) are bound to be inefficient. Because a temporary object of type A will be generated in the function body to copy parameter a, and the process of constructing, copying and destructing the temporary object will take time
To improve efficiency, you can change the function declaration to void func(A &a)Because reference passing only uses aliases for parameters, there is no need to generate temporary objects
void func(A &a) drawback:
It is possible to change the parameter a, which we do not expect.
It's easy to solve this problem by adding const modifier
Finally, it will be : void func(const A &a).
Should void func (int x) be rewritten to void func(const int &x),in order to improve efficiency? That operation was so needless.
Because the internal data type parameters do not exist in the process of construction and deconstruction, and replication is very fast.
Conclusion:For the input parameters of non internal data type, the mode of "value passing" should be changed to "const reference passing", in order to improve the efficiency.
For example, change void func (a a a) to void func (const A & A). It can not improve the efficiency and reduce the comprehensibility of the functionVoid func (int x) should not be changed to void func (const int & x).
So Two interview problems were solved:
(1)If a function needs to pass in a pointer, do you need to add const to the pointer? What is the difference between adding const at different positions of the pointer
(2)If the function to be written needs to pass in an instance of a complex type, what is the difference between the passed in value parameter or reference parameter, and when to add const to the passed reference parameter
## 7.Using const in Class
In a class, any function that does not modify data members should be declared as const type. When writing const member functions, if you accidentally modify data members or call other non const member functions, the compiler will point out errors, which will undoubtedly improve the robustness of the program.The member function described by const is called constant member function
Only constant member functions are qualified to operate constant or constant objects. Member functions without const keyword cannot be used to operate constant objects
For const member variables in a class, they must be initialized through the initialization list:
```
class Apple
{
private:
int people[100];
public:
Apple(int i);
const int apple_number;
};
Apple::Apple(int i):apple_number(i)
{
}
```
Const objects can only access const member functions, while non const objects can access any member functions, including const member functions
Such as:
```
//apple.cpp
class Apple
{
private:
int people[100];
public:
Apple(int i);
const int apple_number;
void take(int num) const;
int add(int num);
int add(int num) const;
int getCount() const;
};
//main.cpp
#include<iostream>
#include"apple.cpp"
using namespace std;
Apple::Apple(int i):apple_number(i)
{
}
int Apple::add(int num){
take(num);
}
int Apple::add(int num) const{
take(num);
}
void Apple::take(int num) const
{
cout<<"take func "<<num<<endl;
}
int Apple::getCount() const
{
take(1);
// add(); //error
return apple_number;
}
int main(){
Apple a(2);
cout<<a.getCount()<<endl;
a.add(10);
const Apple b(3);
b.add(100);
return 0;
}
//Compile g++ -o main main.cpp apple.cpp
//Result
take func 1
2
take func 10
take func 100
```
The getCount () method invokes a add method, and the add method is not const modifier, so run the wrong report. In other words, const objects can only access const member functions. Add method also calls const modified take method, which proves that non const objects can access any member function, including const member function.
In addition, we also see an overloaded function of add, which also outputs two results, indicating that const objects call const member functions by default
In addition to the above initialization const constant, we can also use the following methods:
(1)Combining the definition of constants with static, i.e:
```
static const int apple_number
```
(2)Initialize outside:
```
const int Apple::apple_number=10;
```
Of course, if you use C + + 11 to compile, you can directly define the initialization, you can write:
```
static const int apple_number=10;
or
const int apple_number=10;
```
Both are supported in C + + 11.
When compiling, just add '- STD = C + + 11'.
Let's talk about static briefly:
In C + +, static static member variables cannot be initialized inside a class.It is only declared inside the class, and the definition must be outside the class definition body, usually initialized in the class's implementation file
Declared in the class:
```
static int ap;
```
Use in class implementation file
```
int Apple::ap=666
```
For this implement, C + + 11 cannot be declared and initialized.

View File

@ -0,0 +1,15 @@
class Apple
{
private:
int people[100];
public:
Apple(int i);
//使用c++11标准编译
static const int apple_number=10;
//const int apple_number=10;
void take(int num) const;
int add(int num);
int add(int num) const;
int getCount() const;
};

Binary file not shown.

View File

@ -0,0 +1,31 @@
#include<iostream>
#include"apple.cpp"
using namespace std;
Apple::Apple(int i)
{
}
int Apple::add(int num){
take(num);
}
int Apple::add(int num) const{
take(num);
}
void Apple::take(int num) const
{
cout<<"take func "<<num<<endl;
}
int Apple::getCount() const
{
take(1);
// add(); //error
return apple_number;
}
int main(){
Apple a(2);
cout<<a.getCount()<<endl;
a.add(10);
const Apple b(3);
b.add(100);
return 0;
}

View File

@ -0,0 +1,13 @@
class Apple
{
private:
int people[100];
public:
Apple(int i);
const int apple_number;
void take(int num) const;
int add(int num);
int add(int num) const;
int getCount() const;
};

View File

@ -0,0 +1,32 @@
#include<iostream>
#include"apple.cpp"
using namespace std;
Apple::Apple(int i):apple_number(i)
{
}
int Apple::add(int num){
take(num);
}
int Apple::add(int num) const{
take(num);
}
void Apple::take(int num) const
{
cout<<"take func "<<num<<endl;
}
int Apple::getCount() const
{
take(1);
// add(); //error
return apple_number;
}
int main(){
Apple a(2);
cout<<a.getCount()<<endl;
a.add(10);
const Apple b(3);
b.add(100);
return 0;
}

View File

@ -0,0 +1,13 @@
class Apple
{
private:
int people[100];
public:
Apple(int i);
static const int apple_number;
void take(int num) const;
int add(int num);
int add(int num) const;
int getCount() const;
};

View File

@ -0,0 +1,32 @@
#include<iostream>
#include"apple.cpp"
using namespace std;
const int Apple::apple_number=10;
Apple::Apple(int i)
{
}
int Apple::add(int num){
take(num);
}
int Apple::add(int num) const{
take(num);
}
void Apple::take(int num) const
{
cout<<"take func "<<num<<endl;
}
int Apple::getCount() const
{
take(1);
// add(); //error
return apple_number;
}
int main(){
Apple a(2);
cout<<a.getCount()<<endl;
a.add(10);
const Apple b(3);
b.add(100);
return 0;
}

View File

@ -0,0 +1,14 @@
class Apple
{
private:
int people[100];
public:
Apple(int i);
static int ap; //在类实现文件中定义并初始化
static const int apple_number;
void take(int num) const;
int add(int num);
int add(int num) const;
int getCount() const;
};

Binary file not shown.

View File

@ -0,0 +1,34 @@
#include<iostream>
#include"apple.cpp"
using namespace std;
const int Apple::apple_number=10;
int Apple::ap=666;
Apple::Apple(int i)
{
}
int Apple::add(int num){
take(num);
}
int Apple::add(int num) const{
take(num);
}
void Apple::take(int num) const
{
cout<<"take func "<<num<<endl;
}
int Apple::getCount() const
{
take(1);
// add(); //error
return apple_number;
}
int main(){
Apple a(2);
cout<<a.getCount()<<endl;
cout<<a.ap<<endl;
a.add(10);
const Apple b(3);
b.add(100);
return 0;
}

View File

@ -0,0 +1,11 @@
#include<iostream>
using namespace std;
void f(const int i){
i=10; // error: assignment of read-only parameter i
cout<<i<<endl;
}
int main(){
f(1);
}

View File

@ -0,0 +1,8 @@
#include<iostream>
using namespace std;
int main(){
const int b = 10;
b = 0; //error
const string s = "helloworld";
const int i,j=0;
}

View File

@ -0,0 +1 @@
extern const int ext=12;

View File

@ -0,0 +1,11 @@
#include<iostream>
/**
* by
* compile: g++ -o file const_file2.cpp const_file1.cpp
* execute: ./file
*/
extern const int ext;
int main(){
std::cout<<ext<<std::endl;
}

View File

@ -0,0 +1 @@
int ext;

View File

@ -0,0 +1,11 @@
#include<iostream>
/**
* by
* compile: g++ -o file file2.cpp file1.cpp
* execute: ./file
*/
extern int ext;
int main(){
std::cout<<(ext+10)<<std::endl;
}

View File

@ -0,0 +1,8 @@
#include<iostream>
using namespace std;
int main(){
const int *ptr;
*ptr=10; //error
}

View File

@ -0,0 +1,9 @@
#include<iostream>
using namespace std;
int main(){
const int p = 10;
const void *vp = &p;
void *vp = &p; //error
}

View File

@ -0,0 +1,12 @@
#include<iostream>
using namespace std;
int main(){
const int *ptr;
int val = 3;
ptr = &val; //ok
int *ptr1 = &val;
*ptr1=4;
cout<<*ptr<<endl;
}

View File

@ -0,0 +1,10 @@
#include<iostream>
using namespace std;
int main(){
int num=0;
int * const ptr=&num; //const指针必须初始化且const指针的值不能修改
int * t = &num;
*t = 1;
cout<<*ptr<<endl;
}

View File

@ -0,0 +1,8 @@
#include<iostream>
using namespace std;
int main(){
const int num=0;
int * const ptr=&num; //error! const int* -> int*
cout<<*ptr<<endl;
}

View File

@ -0,0 +1,8 @@
#include<iostream>
using namespace std;
int main(){
const int num=10;
const int * const ptr=&num; //error! const int* -> int*
cout<<*ptr<<endl;
}

View File

@ -0,0 +1,10 @@
#include<iostream>
using namespace std;
int main(){
const int p = 3;
const int * const ptr = &p;
cout<<*ptr<<endl;
}

View File

@ -0,0 +1,138 @@
# Things about decltype
## About Author
![](../img/wechat.jpg)
## 1.Basic
The syntax of decltype is:
```
decltype (expression)
```
Brackets are essential here.The function of decltype is "the type of query expression".Therefore, the effect of the above statement is to return the type of the expression expression.Note that decltype only "queries" the type of the expression and does not "evaluate" the expression.
### 1.1 Deduce expression type
```
int i = 4;
decltype(i) a; //The result is int. The type of a is int
```
### 1.2 Used with using / typedef to define types.
```c++
using size_t = decltype(sizeof(0));//sizeof(a)的返回值为size_t类型
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);
vector<int >vec;
typedef decltype(vec.begin()) vectype;
for (vectype i = vec.begin; i != vec.end(); i++)
{
//...
}
```
like auto, improves the readability of the code.
### 1.3 Reuse anonymous types
In C + +, we sometimes encounter some anonymous types, such as:
```c++
struct
{
int d ;
doubel b;
}anon_s;
```
With decltype, we can reuse this anonymous structure:
```c++
decltype(anon_s) as ;//Defines an anonymous structure above
```
### 1.4 In generic programming, auto is used to trace the return value type of function
```c++
template <typename T>
auto multiply(T x, T y)->decltype(x*y)
{
return x*y;
}
```
Code[decltype.cpp](decltype.cpp)
## 2.Discriminant rules
For decltype (E), the results are affected by the following conditions:
If e is a marker expression or class member access expression without parentheses, decltype (E) of is the type of entity named by E.In addition, if e is an overloaded function, it will result in compilation errors.
Otherwise, assume that the type of E is t, and if e is a dying value, then decltype (E) is t&&
Otherwise, assume that the type of E is t, and if e is a dying value, then decltype (E) is t&&
Otherwise, assuming that the type of E is t, decltype (E) is t.
Markers are defined by programmers except for keywords, literals and other tags that the compiler needs to use. The expression corresponding to a single marker is a marker expression. For example:
```c++
int arr[4]
```
Then arr is a marker expressionranther than arr[3]+0
Example
```c++
int i = 4;
int arr[5] = { 0 };
int *ptr = arr;
struct S{ double d; }s ;
void Overloaded(int);
void Overloaded(char);// reload function
int && RvalRef();
const bool Func(int);
//Rule 1: derivation is its type
decltype (arr) var1; //int 标记符表达式
decltype (ptr) var2;//int * 标记符表达式
decltype(s.d) var3;//doubel 成员访问表达式
//decltype(Overloaded) var4;//重载函数。编译错误。
//规则二:将亡值。推导为类型的右值引用。
decltype (RvalRef()) var5 = 1;
//规则三Lvalue, derived as a reference to the type
decltype ((i))var6 = i; //int&
decltype (true ? i : i) var7 = i; //int& A conditional expression returns an lvalue
decltype (++i) var8 = i; //int& ++i返回i的左值。
decltype(arr[5]) var9 = i;//int&. []操作返回左值
decltype(*ptr)var10 = i;//int& *操作返回左值
decltype("hello")var11 = "hello"; //const char(&)[9] 字符串字面常量为左值且为const左值。
//Rule 4: if none of the above is true, this type is derived
decltype(1) var12;//const int
decltype(Func(1)) var13=true;//const bool
decltype(i++) var14 = i;//int i++返回右值
```
Fromhttps://www.cnblogs.com/QG-whz/p/4952980.html

Binary file not shown.

View File

@ -0,0 +1,60 @@
/**
* @file decltype.cpp
* @brief g++ -o decltype decltype.cpp -std=c++11
* @author
* @version v1
* @date 2019-08-08
*/
#include <iostream>
#include <vector>
using namespace std;
/**
* auto
*/
template <typename T>
auto multiply(T x, T y)->decltype(x*y)
{
return x*y;
}
int main()
{
int nums[] = {1,2,3,4};
vector<int> vec(nums,nums+4);
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<" ";
cout<<endl;
using nullptr_t = decltype(nullptr);
nullptr_t nu;
int * p =NULL;
if(p==nu)
cout<<"NULL"<<endl;
typedef decltype(vec.begin()) vectype;
for(vectype i=vec.begin();i!=vec.end();i++)
cout<<*i<<" ";
cout<<endl;
/**
*
*/
struct
{
int d ;
double b;
}anon_s;
decltype(anon_s) as; // 定义了一个上面匿名的结构体
cout<<multiply(11,2)<<endl;
return 0;
}

View File

@ -0,0 +1,161 @@
# From beginner to Master
## About author
![](../img/wechat.jpg)
## Traditional
Enum has the following problems:
- The scope is not limited, and it is easy to cause naming conflicts. For example
```c++
#include <iostream>
using namespace std;
enum Color {RED,BLUE};
enum Feeling {EXCITED,BLUE};
int main()
{
return 0;
}
```
- Implicit conversion to int
- The actual type used to represent an enumerated variable cannot be explicitly specified, Therefore, forward declaration of enumeration types cannot be supported.
Implementation[tradition_color.cpp](tradition_color.cpp)
## Classic Method
A simple way to solve the problem of naming conflicts caused by unlimited scope is to prefix the enumeration variables. Change the above example to COLOR_BLUE and FEELING_BLUE。
Generally speaking, we usually prefix all constants for uniformity.But the code for defining enumeration variables is cumbersome.This may have to be done in the C program. But C++ coder do not like this method。Alternatives is namespace:
```c++
namespace Color
{
enum Type
{
RED=15,
YELLOW,
BLUE
};
};
```
Then you can use `Color::Type c = Color::RED;` to define the new enumeration。If after`using namespace Color` the prefix can also be omitted to simplify the code.However, the scope closure provided by a namespace is not high because it can be subsequently extended.In large projects, it is still possible for different people to give different things the same enumeration type names.
A more "effective" approach is to limit its scope with a class or struct.For exampleThe new variable is defined in the same way as in the namespace above. This way, you don't have to worry about the class being modified elsewhere.We use structs instead of classes because we want these constants to be publicly accessible.
```c++
struct Color1
{
enum Type
{
RED=102,
YELLOW,
BLUE
};
};
```
Implementation[classic_practice.cpp](classic_practice.cpp)
## C++11 Enum class
The above approach solves the first problem, but it can not do anything for the latter two.FortunatelyC ++ 11 standard introduces enum class. It can solve the above problems.
- The scope of the new enum is no longer global
- Cannot be implicitly converted to another type
```c++
/**
* @brief C++11 enum class
* Equals to enum class Color2:int
*/
enum class Color2
{
RED=2,
YELLOW,
BLUE
};
r2 c2 = Color2::RED;
cout << static_cast<int>(c2) << endl; //
```
- You can specify a specific type to store enum
```c++
enum class Color3:char; // Forward statement
// Definition
enum class Color3:char
{
RED='r',
BLUE
};
char c3 = static_cast<char>(Color3::RED);
```
Implementation[classic_practice.cpp](classic_practice.cpp)
## Enum types in class
Sometimes we want certain constants to work only in classes. Because the macro constant defined by a is global, it can not achieve the purpose, so we want to use const to modify data members.The const data member does exist, but its meaning is not what we expected.
Data members are constants only for the lifetime of an objec. However, it is variable for the whole class, because the class can create multiple objects, and the values of const data members of different objects can be different.
Cannot be initialized in a class declaration const data memeber。The following usage is incorrectBecause the compiler does not know what the value of size is when the object of the class is not created.(c++11)
```c++
class A
{
const int SIZE = 100; // ErrorAttempt to initialize const data member in class declaration
int array[SIZE]; // ErrorUnknown size
};
```
This should be done in the initialization list of the class's constructor:
```c++
class A
{
A(int size); // Constructor
const int SIZE ;
};
A::A(int size) : SIZE(size) // The definition of Struct
{
}
A a(100); // The size of Object A is 100
A b(200); // The size of Object B is 200
```
How can I establish constants that are constant throughout a class?
It should be implemented with enumeration constants in the class. Such as:
```c++
class Person{
public:
typedef enum {
BOY = 0,
GIRL
}SexType;
};
//Access via Person::BOY or Person::GIRL.
```
Enum constants do not take up the storage space of the object . They are all evaluated at compile time
Drawback of EnumIts implied data type is an integer, the maximum is limited, and it cannot represent floating point.

Binary file not shown.

View File

@ -0,0 +1,87 @@
/**
* @file classic_practice.cpp
* @brief g++ -o classic_practice classic_practice.cpp -std=c++11
* @author
* @version v1
* @date 2019-08-07
*/
#include <iostream>
using namespace std;
/**
* @brief namespace解决作用域不受限
*/
namespace Color
{
enum Type
{
RED=15,
YELLOW,
BLUE
};
};
/**
* @brief using namespace Color 使
*
* 西
*
*
*
*
* 访
*
*/
struct Color1
{
enum Type
{
RED=102,
YELLOW,
BLUE
};
};
/**
* @brief C++11
* enum class Color2:int
*/
enum class Color2
{
RED=2,
YELLOW,
BLUE
};
enum class Color3:char; // 前向声明
// 定义
enum class Color3:char
{
RED='r',
BLUE
};
int main()
{
// 定义新的枚举变量
Color::Type c = Color::RED;
cout<<c<<endl;
/**
*
* using namespace Color; // 定义新的枚举变量
* Type c = RED;
*/
Color1 c1;
cout<<c1.RED<<endl;
Color1::Type c11 = Color1::BLUE;
cout<<c11<<endl;
Color2 c2 = Color2::RED;
cout << static_cast<int>(c2) << endl;
char c3 = static_cast<char>(Color3::RED);
cout<<c3<<endl;
return 0;
}

View File

@ -0,0 +1,10 @@
#include <iostream>
using namespace std;
enum Color {RED,BLUE};
enum Feeling {EXCITED,BLUE};
int main()
{
return 0;
}

View File

@ -0,0 +1,15 @@
# Things about explicit
## About Author
![](../img/wechat.jpg)
- explicit When decorating a constructor, you can prevent implicit conversion and copy initialization
- explicit When modifying a conversion function, you can prevent implicit conversion, except for context conversion
Code :[.explicit.cpp](./explicit.cpp)
Reference Link
> https://stackoverflow.com/questions/4600295/what-is-the-meaning-of-operator-bool-const

Binary file not shown.

View File

@ -0,0 +1,46 @@
#include <iostream>
using namespace std;
struct A
{
A(int) { }
operator bool() const { return true; }
};
struct B
{
explicit B(int) {}
explicit operator bool() const { return true; }
};
void doA(A a) {}
void doB(B b) {}
int main()
{
A a1(1); // OK直接初始化
A a2 = 1; // OK复制初始化
A a3{ 1 }; // OK直接列表初始化
A a4 = { 1 }; // OK复制列表初始化
A a5 = (A)1; // OK允许 static_cast 的显式转换
doA(1); // OK允许从 int 到 A 的隐式转换
if (a1); // OK使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换
bool a6(a1); // OK使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换
bool a7 = a1; // OK使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换
bool a8 = static_cast<bool>(a1); // OK static_cast 进行直接初始化
B b1(1); // OK直接初始化
// B b2 = 1; // 错误:被 explicit 修饰构造函数的对象不可以复制初始化
B b3{ 1 }; // OK直接列表初始化
// B b4 = { 1 }; // 错误:被 explicit 修饰构造函数的对象不可以复制列表初始化
B b5 = (B)1; // OK允许 static_cast 的显式转换
// doB(1); // 错误:被 explicit 修饰构造函数的对象不可以从 int 到 B 的隐式转换
if (b1); // OK被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换
bool b6(b1); // OK被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换
// bool b7 = b1; // 错误:被 explicit 修饰转换函数 B::operator bool() 的对象不可以隐式转换
bool b8 = static_cast<bool>(b1); // OKstatic_cast 进行直接初始化
return 0;
}

195
english/basic_content/extern/README.md vendored Normal file
View File

@ -0,0 +1,195 @@
# extern "C"
## About Author
![](../img/wechat.jpg)
## 1. Compiler difference between C and C ++
In C + +, we often see extern "C" modifier function in the header file. What's the effect. Is a function defined in C language module for C + + link.
Although C + + is compatible with C, the symbols generated by function compilation in C + + files are different from those generated by C language.Because C + + supports function overloading, the symbols generated by C + + function compilation have the information of function parameter type, while C does not.
Take `int add(int a, int b)` for example. The C + + compiler generates the. O file, `add` becomes `add_int_int` and so on, while C would be like this `_add`, that isFor the same function, in C and C + +, the symbols generated after compilation are different.
This leads to a problem: if the function implemented in C + + is implemented in C language, an error will occur when compiling the link, indicating that the corresponding symbol cannot be found. At this time`extern "C"` worksTell the linker to find its `_ C `language symbols such as `add` are not modified by C ++.
## 2.C ++ calls C functions
When referring to the header file of C, you need to add `extern "C"`
```c++
//add.h
#ifndef ADD_H
#define ADD_H
int add(int x,int y);
#endif
//add.c
#include "add.h"
int add(int x,int y) {
return x+y;
}
//add.cpp
#include <iostream>
#include "add.h"
using namespace std;
int main() {
add(2,3);
return 0;
}
```
Compile
```
//Generate add.o file
gcc -c add.c
```
Link
```
g++ add.cpp add.o -o main
```
Without extern "C"
```c++
> g++ add.cpp add.o -o main
add.o在函数main
add.cpp:(.text+0x0): `main'被多次定义
/tmp/ccH65yQF.o:add.cpp:(.text+0x0):第一次在此定义
/tmp/ccH65yQF.o在函数main
add.cpp:(.text+0xf)add(int, int)’未定义的引用
add.o在函数main
add.cpp:(.text+0xf)add(int, int)’未定义的引用
collect2: error: ld returned 1 exit status
```
With extern "C"
`add.cpp`
```c++
#include <iostream>
using namespace std;
extern "C" {
#include "add.h"
}
int main() {
add(2,3);
return 0;
}
```
When compiling, you must pay attention to generating intermediate files add.o through GCC
```
gcc -c add.c
```
Compile
```
g++ add.cpp add.o -o main
```
Code
- [add.h](extern_c++/add.h)
- [add.c](extern_c++/add.c)
- [add.cpp](extern_c++/add.cpp)
## 2.Calling C++ function in C
`extern "C"` It is a syntax error in C, which needs to be put in the C + + header file.
```c
// add.h
#ifndef ADD_H
#define ADD_H
extern "C" {
int add(int x,int y);
}
#endif
// add.cpp
#include "add.h"
int add(int x,int y) {
return x+y;
}
// add.c
extern int add(int x,int y);
int main() {
add(2,3);
return 0;
}
```
Compile
```c
g++ -c add.cpp
```
Link
```
gcc add.c add.o -o main
```
Code
- [add.h](extern_c/add.h)
- [add.c](extern_c/add.c)
- [add.cpp](extern_c/add.cpp)
In the header file of C language, the external function can only be specified as extern type. The declaration of extern "C" is not supported in C language. There will be compiler syntax error when the. C file contains extern "C". Therefore, the use of external "C" is all placed in CPP program related files or its header files.
The following forms are summarized:
1C + + calls C functions:
```c++
//xx.h
extern int add(...)
//xx.c
int add(){
}
//xx.cpp
extern "C" {
#include "xx.h"
}
```
2C calls C + + functions
```c
//xx.h
extern "C"{
int add();
}
//xx.cpp
int add(){
}
//xx.c
extern int add();
```

View File

@ -0,0 +1,5 @@
#include "add.h"
int add(int x,int y) {
return x+y;
}

View File

@ -0,0 +1,9 @@
#include <iostream>
using namespace std;
extern "C" {
#include "add.h"
}
int main() {
add(2,3);
return 0;
}

View File

@ -0,0 +1,4 @@
#ifndef ADD_H
#define ADD_H
extern int add(int x,int y);
#endif

Binary file not shown.

BIN
english/basic_content/extern/extern_c++/main vendored Executable file

Binary file not shown.

View File

@ -0,0 +1,5 @@
extern int add(int x,int y);
int main() {
add(2,3);
return 0;
}

View File

@ -0,0 +1,5 @@
#include "add.h"
int add(int x,int y) {
return x+y;
}

View File

@ -0,0 +1,6 @@
#ifndef ADD_H
#define ADD_H
extern "C" {
int add(int x,int y);
}
#endif

Binary file not shown.

BIN
english/basic_content/extern/extern_c/main vendored Executable file

Binary file not shown.

View File

@ -0,0 +1,111 @@
# Friend and Friend Class
## About Author
![](../img/wechat.jpg)
## 0.Summary
Friends provide a mechanism for ordinary functions or class member functions to access private or protected members in another class.In other words, there are two forms of friends:
1Friend FunctionOrdinary functions access a private or protected member of a class.
2Friend ClassMember functions in class a access private or protected members in class B
Advantages: improve the efficiency of the program.
Disadvantages: it destroys the encapsulation of classes and the transparency of data.
Conclusion
- Access to private members
- Breaking encapsulation
- Friendship is not transitive
- The unidirectionality of friend relationship
- There are no restrictions on the form and number of friend declarations
## 1.Friend function
It is declared in any region of the class declaration, and the definition is outside the class.
```
friend <type><name>(<Parameter table>);
```
Note that the friend function is only a common function, not a class member function of this class. It can be called anywhere. In the friend function, private or protected members of the class can be accessed through the object name.
Code[friend_func.cpp](friend_func.cpp)
```c++
#include <iostream>
using namespace std;
class A
{
public:
A(int _a):a(_a){};
friend int geta(A &ca); ///< Friend function
private:
int a;
};
int geta(A &ca)
{
return ca.a;
}
int main()
{
A a(3);
cout<<geta(a)<<endl;
return 0;
}
```
## 2.Friend Class
The declaration of a friend class is in the declaration of the class, and the implementation is outside the class.
```
friend class <friend class name>;
```
Class B is a friend of class A, so class B can directly access private members of A.
Code[friend_class.cpp](friend_class.cpp)
```c++
#include <iostream>
using namespace std;
class A
{
public:
A(int _a):a(_a){};
friend class B;
private:
int a;
};
class B
{
public:
int getb(A ca) {
return ca.a;
};
};
int main()
{
A a(3);
B b;
cout<<b.getb(a)<<endl;
return 0;
}
```
## 3.Attention
- Friendship has no inheritance
If class B is a friend of class A and class C inherits from Class A, then friend class B cannot directly access private or protected members of class C.
- Friendship is not transitive
If class B is a friend of class A and class C is a friend of class B, then friend class C cannot directly access private or protected members of class A, that is, there is no such relationship as "friend of friend".

Binary file not shown.

View File

@ -0,0 +1,28 @@
#include <iostream>
using namespace std;
class A
{
public:
A(int _a):a(_a){};
friend class B;
private:
int a;
};
class B
{
public:
int getb(A ca) {
return ca.a;
};
};
int main()
{
A a(3);
B b;
cout<<b.getb(a)<<endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,33 @@
/**
* @file friend_func.cpp
* @brief
* @author
* @version v1
* @date 2019-08-06
*/
#include <iostream>
using namespace std;
class A
{
public:
A(int _a):a(_a){};
friend int geta(A &ca); ///< 友元函数
private:
int a;
};
int geta(A &ca)
{
return ca.a;
}
int main()
{
A a(3);
cout<<geta(a)<<endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,33 @@
/**
* @file func_pointer.cpp
* @brief 使
* @author
* @version v1
* @date 2019-07-20
*/
#include<iostream>
using namespace std;
/**
* @brief pFun
*/
void (*pFun)(int);
/**
* @brief pFun不一样
*/
typedef void (*func)(void);
void myfunc(void)
{
cout<<"asda"<<endl;
}
void glFun(int a){ cout<<a<<endl;}
int main(){
func pfun = myfunc;/*赋值*/
pfun();/*调用*/
pFun = glFun;
(*pFun)(2);
}

Some files were not shown because too many files have changed in this diff Show More