This commit is contained in:
yinkanglong_lab
2021-03-05 14:48:39 +08:00
parent 8db31d7c87
commit 2b95374f4f
31 changed files with 1049 additions and 27 deletions

View File

@@ -155,12 +155,24 @@ char a3[]="c++"//自动添加表示字符串结束的空字符
```
//下标遍历
int m[5]={1,2,3,4,5};
for(int i=0;i<5;i++){
cout<<m[i]<<endl;
}
//容器遍历
int k[] = {1,2,3};
for (auto l:k){
cout<<l<<endl;
}
//迭代器遍历
int m[5]={1,2,3,4,5};
int* beg =begin(m);
int* last = end(m);
while(beg!=last){
cout<<*beg<<endl;
beg++;
}
```
### 指针和数组
@@ -173,7 +185,7 @@ string *p2 = &num[0];
string *p3 = num;//相互等价
```
- 数组指针本身也是迭代器。可以使用 begin 函数和 end 函数,实现器遍历。
- 数组指针本身也是迭代器。可以使用 begin 函数和 end 函数,实现迭代器遍历。
```
int ia[]={1,2,3};
@@ -223,9 +235,18 @@ for(int i=0;i<row_cnt;i++){
* 两层容器遍历,遍历多维数组。
```
for(auto &row : ia){
for (auto &col:row){
*col;
int ia[2][3] = {1, 2, 3, 4, 5, 6};
//这里使用引用的原因是,数组在传递时候不能直接赋值!!!!
//如果不加引用将会出现以下情况
//auto row = ia[0]。但是数组没办法赋值。所以生成数组的一个引用
//auto &row =ia[0]。相当于生成ia[0]指针的一个别名。
//书上这么说,外层引用添加的原因,是防止第二层数组被当做指针使用。
for (auto &row : ia)
{
for (auto col : row)
{
cout << col << endl;
}
}
}
```
```
![](2021-03-04-17-20-26.png)

View File

@@ -73,17 +73,38 @@ int main()
// int n;
// };
// helo a[10];
//数组的容器遍历
// int k[] = {1,2,3};
// for (auto l:k){
// cout<<l<<endl;
// }
// cout<<*(k+1)<<endl;
int ia[2][3]={1,2,3,4,5,6};
for(auto &row:ia){
for(auto col:row){
cout<<col<<endl;
//数组的迭代器遍历,通过指针的方法进行遍历
// int m[5]={1,2,3,4,5};
// int* beg =begin(m);
// int* last = end(m);
// while(beg!=last){
// cout<<*beg<<endl;
// beg++;
// }
// for(int i=0;i<5;i++){
// cout<<m[i]<<endl;
// }
int ia[2][3] = {1, 2, 3, 4, 5, 6};
//这里使用引用的原因是,数组在传递时候不能直接赋值!!!!
//如果不加引用将会出现以下情况
//auto row = ia[0]。但是数组没办法赋值。所以生成数组的一个引用
//auto &row =ia[0]。相当于生成ia[0]指针的一个别名。
//书上这么说,外层引用添加的原因,是防止第二层数组被当做指针使用。
for (auto &row : ia)
{
for (auto col : row)
{
cout << col << endl;
}
}
return 0;

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -0,0 +1,104 @@
# 表达式
## 1 基础
### 组合运算
- 优先级
- 结合律
### 类型转换
### 运算符重载
### 左值和右值
## 2 算数运算符
![](2021-03-04-17-25-36.png)
## 3 逻辑和关系运算法
![](2021-03-04-17-26-34.png)
### 短路求值
- 逻辑与,当第一个判定为否的时候,不再执行第二个判定,可以用来屏蔽第二步的计算,代替条件判断!!!!!!!
- 逻辑或,当第一个判定为是的时候,不再执行第二个判定,可以用来屏蔽第二步的计算,代替条件判断!!!!!!!
当且晋档左侧的运算对象无法确定表达式的结果是,才会计算右侧运算对象的值!
## 4 赋值运算法
![](2021-03-04-17-30-19.png)
## 5 递增递减运算符
- 尽量使用前置版本的自增自减运算符。
- 后置递增运算符的优先级高于解引用的运算符。
```
*pb++ //等价于*(pb++)
```
## 6 成员访问运算符
- 点运算符。对象成员访问运算符。
- 箭头运算符。指针成员访问运算符。
- 解引用运算符的优先级抵御点运算符。所以解引用运算符的优先级很低。
```
*p.size();//相互等价*(p.size())
```
## 7 条件运算符
- ?:
## 8 位运算符
- 位运算符作用域证书类型的运算对象,并把运算对象看成二进制位的集合。
![](2021-03-04-17-39-49.png)
## 9 sizeof 运算符
## 10 逗号运算符
## 11 类型转换
### 隐式类型转换——算数转换
- 整形提升
### 其他隐式类型转换
- 数组转换成指针
- 转换成个布尔类型
- 转换成常量
### 显式转换——强制类型转换。
- static_cast 没有类型检查的强制类型转换。可以将 void\*转换为目标类型,更多的应用于指针的强制类型转换。
```
double d =10;
void * p = &d;
double *dp = static_cast<double *>(p)//然后正常使用dp。也可以转换为其他类型取前一个字节或者四个字节。
```
- const_cast 去掉底层的 const
- reinterpret_cast 为运算对象的位模式提供较低层次上的重新解释。
### C 强制类型转换
```
type(expr);
(type)expr;
```
## 12 优先级
![](2021-03-04-20-43-17.png)
![](2021-03-04-20-43-53.png)

10
C++/C++基础/3.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include<iostream>
using namespace std;
int main(){
int a=1;
int b=2;
int c=(b<<1);
cout<<(a|b)+c<<endl;
}

80
C++/C++基础/5 语句.md Normal file
View File

@@ -0,0 +1,80 @@
# 语句
## 1 简单语句
### 分类
* 表达式语句
* 空语句
* 分号
* 复合语句,用花括号括起来——也被称作块。一个块就是一个作用域。
## 2 语句作用域
## 3 条件语句
### if-else语句
### 嵌套if-else语句
### 悬垂else
else与离他最近的if匹配。从而消除程序的二义性。
### 使用花括号控制执行路径
### switch语句
### default标签
## 4 循环语句
### while语句
while(condition)
statement
### 传统for循环
for(init-statement;condition;expression)
statement
### 容器for循环
for(delaration:expression)
statement
### dowhile语句
do
statement
while(condition)
## 5 跳转语句
break;
continue;
## 6 try语句块
### 概述
异常处理机制主要包括以下内容
* throw表达式引发raise抛出异常
* try-catch语句块try用来捕获异常catch用来处理异常。
* 异常类。用于在throw表达式和catch子句之间传递具体的信息。
### throw 表达式
throw runtime_error("data must refer to ISBN")//抛出一个异常类。
### try语句块
![](2021-03-04-21-04-30.png)
* 只允许最多有一个catch捕获。捕获之后跳转到catch之后执行。
### 标准异常
![](2021-03-04-21-05-54.png)

183
C++/C++基础/6 函数.md Normal file
View File

@@ -0,0 +1,183 @@
# 函数
## 1 函数基础
### 构成
- 返回类型、形参列表、函数体
- 使用调用运算符来执行函数,传入实参列表。
- 编写函数
- 调用函数
- 主调函数和被调函数。程序的控制权由主调函数交给被调函数。
- return 语句返回。程序的控制权由被调函数返回给主调函数
- 形参和实参
- 没有规定实参的求值顺序,默认是从右向左。
### 局部对象
- 形参和函数体内部定义的变量同城局部变量
- 局部变量会屏蔽外部同名的变量。
- 自动对象。运行时自动创建,栈函数运行完时自动释放。只存在于块执行期间的对象是一种自动对象。
- 局部静态带向。初始化全局静态数据段。直到程序终止才会被销毁。
### 函数声明
- 在头文件中进行函数的声明。
### 分离式编译
- 把程序分离到多个文件中去。每个文件独立编译。
- 最后链接各个独立编译的文件
## 2 参数传递
### 值传递
- 初始值被赋值给形参。但是形参的修改无法改变原来变量的值。
- 指针也是值传递,拷贝的是指针的值。通过指针能够修改原来的对象。即修改指针指向的值,但是原来指针的值依旧不能修改。
### 引用传递
- 传递原来变量的引用,修改会直接引起原来变量的变化。
- 感觉使用引用传递要通过指针地址的值传递快多了。
- 引用传递还能帮我们一次返回多个结果。
- 如果形参不需要修改原来实参的值,需要传递常量引用。
### 数组形参
数组的两个性质
- 不能直接 copy 数组
- 数组使用时通常会转换成指针
即相当于传递了指向原来的数组的指针。
### main 处理命令行选项
```
int main(int argc,char **argv){
}
```
### 可变参数
C++中使用 initializer_list 类实现多个参数的传递。也是一个容器类,可以返回迭代器。
![](2021-03-04-21-57-59.png)
## 3 返回类型和 return 语句
### 无返回值的函数。
void fun(){
return;//可以省略,不返回任何东西。
}
### 有返回值的函数
- 返回值将会被 copy 到调用地点。
- 函数内指针指向的局部变量会销毁。返回后便不可引用。
- 不要返回局部对象的引用或指针。
- 通过形参的引用变量返回值。
```
void hello(int &a){
a=10;
}
```
- 列表初始化返回值。
vector<string> process()
{
return {"function","hello"}
}
> 原来 C++11 中添加大括号进行初始化的主要目的,就是返回多个值啊。但是返回值类型还是必须相同的。也就是说可以使用中括号进行复制列表初始化。
### 返回数组指针
## 4 函数重载
### 定义重载函数
- 如果同一个作用域的几个函数名字相同但是形参列表不同,则成为函数重载。
- 可以通过 const 来区分重载了哪个具体的函数。
### 调用重载函数
- 函数匹配
- 重载确定
### 重载与作用域
- 函数外部的重载函数可能被局部同名变量屏蔽掉。
## 5 特殊用途语言特性
### 默认参数
- 实参按位置解析,默认参数填补缺少的尾部实参。
### 内联函数
- 普通的函数调用操作系统需要开单独的空间,保护寄存器状态。
- 内联函数相当于常量,可以直接替换使用到内联函数的地方。直接嵌入到函数调用的地方。
### constexpr 函数
- 用于常量表达式的函数。
- 函数的返回值及所有的形参的类型都是字面值常量
- 函数中只有一条 return 语句。
- 保证函数在编译过程中能够直接计算结果。
### assert 预处理宏
```
assert(expr);
```
- 预处理变量,使用表达式作为条件。
- 程序执行过程中,如果表达式为真,则 assert 什么也不做。如果表达式为假,则输出信息终止程序。
## 6 函数匹配
1. 选定本次调用对应的重载函数集,集合中的函数称为候选函数。候选函数的特点:与被调用的函数重名;声明在调用点可见。
2. 选出能被实参调用的函数,称为可行函数。实参与形参的数量相等;实参与形参对应的类型相同。
3. 默认参数的重载函数优先级,高于,类型转换的重载函数的优先级。
![](2021-03-04-22-45-04.png)
## 7 函数指针
### 定义函数指针
- 函数指针指向的是函数,而非变量或对象。函数指针指向某种特定的类型的函数。函数的类型由它的返回值类型和形参类型共同决定,与函数名无关。
```C++
bool lengthCompare(const string &,const string &);
bool (*pf)(const string &,const string &);
//*pf两端如果没有括号则指针是指向返回值的指针。
//两个函数是等价的
```
### 使用函数指针
- 当把函数名作为一个值使用时。函数自动的转换成指针。
```
pf = lengthCompare;
pf = &lengthCompare;//两者是等价的。
pf = 0;//pf不指向任何函数
pf = nullptr;//pf不指向任何函数。
```
- 在多个重载函数中pf 的类型必须指向特定的某个重载函数。

32
C++/C++基础/6.cpp Normal file
View File

@@ -0,0 +1,32 @@
#include <iostream>
#include <vector>
using namespace std;
int hello(int a, int b)
{
cout << a << b << endl;
return 0;
}
//多个形参列表,必须是相同类型。
//另外把这个东西换成vector也是没有问题的。
//但是这个东西C++默认提供的类型,不需要头文件。
int multi_value(initializer_list<int> lst)
{
auto begin = lst.begin();
auto last = lst.end();
while (begin != last)
{
cout << *begin << endl;
begin++;
}
return 0;
}
int main()
{
int i = 0;
// hello(i+1,i=i+1);
multi_value({1, 2, 3, 5});
return 0;
}

178
C++/C++基础/7 类.md Normal file
View File

@@ -0,0 +1,178 @@
# 类
## 1 定义抽象数据类型
### 概念
- 数据抽象是一种依赖于接口和实现的分离的编程技术。
- 类的接口包括用户所能执行的操作;类的实现包括类的数据成员、负责接口实现的函数体以及定义类所需要的的各种私有函数。
- 封装实现了类的接口和实现的分离。
### 设计类
- 定义包含数据成员和成员函数
- 定义在类内部的函数是隐式的 inline 函数!
### this 指针
- this 指针。用来指明当前绑定的对象。只在依赖对象的函数中添加 this 指针。
### 常量成员函数
- 常量成员函数。const 关键字放在成员函数的参数列表之后。常量函数的 this 指针指向常量对象。不能对常量对象内数据进行修改。
```
class A{
const int getM(){//表示返回值是const类型的
}
int getN() const{//表示函数是const类型的
}
}
```
- 当一个函数被 const 说明后,其函数中出现的对外部数据的任何写入或修改都将被系统检查为出错。如果把函数 writeme()说明为:
```
void writeme(int i) const { me = i; } //系统将会检查出错误。
```
- 作用:当函数体较大且复杂时,如果我们希望系统帮助避免对对象内容进行修改,那么我们就会将这个函数定义为常量型函数,这就是使用它的主要目的。
### 构造函数
- 控制对象的初始化过程。只要类对象被创建就会执行构造函数。
- 构造函数没有返回类型。构造函数不能被声明成 const
- 默认构造函数没有任何实参。
- **合成的默认构造函数**。编译器隐式地创建的默认构造函数。合成默认构造函数初始化过程:
- 如果类内存在初始值,使用它来初始化成员
- 否则,默认初始化该成员。
```
hello{
hello()=default;//要求编译器生成默认的构造函数。
}
```
### 构造函数的初始值列表
```
hello{
heelo(int aa,int bb):a(aa),b(bb),c(0){
};//列表初始化。
}
```
## 2 访问控制与封装
### 访问说明符
- public对外部函数可见。
- private被类成员访问但不能被外部访问。private 部分封装了类的实现细节。
### 定义类
- class 和 struct 都能定义类。
- class 的默认访问控制是 private
- struct 的默认访问控制是 public
### 友元
- 类的接口可以不是类的成员。下图中print、add、read 是类的接口但是不是类的成员。被称作非成员接口函数。
![](2021-03-05-11-26-54.png)
- 非成员接口函数无法访问类的私有变量。可以声明友元,访问私有变量。友元的声明智能出现在类定义的内部。友元是突破访问控制符的方法。
![](2021-03-05-11-28-27.png)
- 友元也为多种形式的接口提供了方法。比如可以重载上述的 read 函数,让它成为多个不同的类友元。可以实现一个接口在多种不同情况下的使用。
## 3 类的其他特性
- 类内的函数可以被声明为内联函数
- 成员函数可以被重载。
- (日了狗了,真 TM 特例也太多了吧有必要吗可变成员函数mutable 声明的变量,是可变数据成员。即是是 const 对象的成员,它也是可变数据成员,依然能够改变。
### 类类型
- 类通过类名来标识。如果两个类的内容完全一致,但是类名不一样,也无法相互赋值。
- 两种创建对象的方法
```
Hello h;
class Hello h;//包含关键字class创建对象。两者等价。
```
- 类可以进行前向声明,而不进行定义。他是一个不完全的类型。
```
class Hello;
```
- 在创建类的对象之前,类必须被定义。所以如果要引用其他头文件中的类,类必须在该头文件就被定义,否则没办法创建对象进行连接。
- 其他类、类成员都可以声明为类的友元。
## 4 类的作用域
- 在类的作用域外,通过对象、引用、指针,使用成员访问运算符访问。
- 在类外定义函数,需要指明类作用域,使用作用域运算符::实现类内的函数。函数体内可以直接使用类作用域内的内容。函数体外的返回值通过作用域运算符使用类作用域内的内容。
### 名字查找与类的作用域
名字查找的步骤
* 作用域内查找使用之前的声明。
* 查找外层作用域的声明
* 如果没找到报错。
类内名字查找比较特殊。
* 首先编译成员声明。
* 然后编译函数体。
* 所以即使类的成员声明在类的末尾,对之前的函数来说也是可见的。
成员定义中普通块作用域的名字查找
* 首先在成员函数内查找声明。
* 类内查找。所有的类成员都被考虑。
* 在成员函数定义之前的作用域内查找。
## 5 构造函数再探
* 当成员是常量或引用的时候,初始化是必不可少的。
* 成员初始化的书序与他们在类定义中的出现顺序一致。而非初始化列表中传入参数的顺序。
### 委托构造函数
* 委托构造函数使用类的其他构造函数执行自己的初始化过程。
![](2021-03-05-13-42-02.png)
初始化执行的新婚徐
1. 初始化列表
2. 委托构造函数
3. 初始化函数体
4. 值初始化。(在成员变量定义的时候给出的值)
5. 默认初始化(以上情况都没有的时候)
### 默认构造函数的作用
默认初始化在一下情况发生:
* 块作用域内不适用任何初始值定义一个非静态变量
* 一个类本身含有类类型的成员其而是用合成的默认构造函数时。(包含关系的外部合成默认构造函数会自动调用内部的默认构造函数。)如果有自定义的默认构造函数,需要自己手动初始化内部默认构造函数。
* 类类型的成员没有在构造函数的处置类表中显式的初始化。
值初始化在一下情况发生
> 类的基本特性
>
> - 数据抽象和封装
> - 继承
> - 多态

74
C++/C++基础/7.cpp Normal file
View File

@@ -0,0 +1,74 @@
#include<iostream>
#include<vector>
using namespace std;
// 这种使用流的方式感觉很好玩。
class Book{
private:
int a;
int b;
public:
istream &read(istream &is)
{
is>>a>>b;
return is;
}
ostream & print(ostream &os)
{
os<<a<<b<<endl;
return os;
}
};
class Car{
public:
int a=0;
int b=1;
Car(int aa,int bb):a(aa),b(bb){};//初始化列表,进行初始化
Car(int aa):Car(aa,0){};//委托构造函数,使用第一个构造函数进行构造。
Car():Car(0,0){};//默认构造函数,委托构造函数
string m="fjeioaf";
string *n=&m;
};
int main(){
Book bk;
Car cr;
// if(1){
// Car cr2;
// string k="shuai";
// cr2.a=2;
// cr2.b=3;
// cr2.m="yinkanglong";
// cr2.n=&k;
// cout<<"k addr:"<<&k<<endl;
// cr=cr2;//输出地址发现,二者地址不同,应该是发生了拷贝赋值,而不是单纯的地址赋值。
// cout<<&cr<<endl;
// cout<<&cr2<<endl;
// }
// cout<<cr.a<<cr.b<<cr.m<<endl;
// cout<<*(cr.n)<<endl;
// cout<<"cr addr:"<<cr.n<<endl;//发现这个地址与局部变量k的地址一致并且可以访问。
// // 块作用域能够限制名称的可见性但是函数的才是堆栈生成销毁的条件。所以k的地址指向的值能够用。
// // istream i = bk.read();
// // ostream o = bk.print();
// vector<Car> vc(3);//vector会自动调用元素对象的默认初始化函数。
// cout<<vc[1].a<<endl;
// vc[2].b=10;
// cout<<vc[2].b<<endl;
string uu = "fei";
int rr(12);
cout<<rr<<endl;
Car t1(3,4);//调用构造函数
Car t2 = Car(3,4);//调用构造函数
// Car* t = new Car(3,4);
Car tt{3,4};//可以调用构造函数
vector<Car> ttt{Car(3.4),Car(5,6)};
cout<<ttt[0].a<<endl;
cout<<ttt[1].b<<endl;
return 0;
}

View File

@@ -0,0 +1,183 @@
# 强制类型转换
- [参考文献](https://www.cnblogs.com/chenyangchun/p/6795923.html)
## 1 强制类型转换
### C 强制类型转换
```
(type-id)expression//转换格式1
type-id(expression)//转换格式2
```
### C++强制类型转换
```
static_cast<new_type> (expression)
dynamic_cast<new_type> (expression)
const_cast<new_type> (expression)
reinterpret_cast<new_type> (expression)
```
- static_cast
- dynamic_cast
- const_cast
- reinterpret_cast
## 2 详解
### static_cast
static_cast 相当于传统的 C 语言里的强制转换,该运算符把 expression 转换为 new_type 类型,用来强迫隐式转换,例如 non-const 对象转为 const 对象,编译时检查,用于非多态的转换,可以转换指针及其他,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
- 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
- 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
- 进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
- 用于基本数据类型之间的转换,如把 int 转换成 char把 int 转换成 enum。这种转换的安全性也要开发人员来保证。
- 把空指针转换成目标类型的空指针。
- 把任何类型的表达式转换成 void 类型。
> 注意static_cast 不能转换掉 expression 的 const、volatile、或者\_\_unaligned 属性。
1. 基本类型数据转换举例如下:
```
char a = 'a';
int b = static_cast<char>(a);//正确将char型数据转换成int型数据
double *c = new double;
void *d = static_cast<void*>(c);//正确将double指针转换成void指针
int e = 10;
const int f = static_cast<const int>(e);//正确将int型数据转换成const int型数据
const int g = 20;
int *h = static_cast<int*>(&g);//编译错误static_cast不能转换掉g的const属性
```
2. 类上行和下行转换:
```
if(Derived *dp = static_cast<Derived *>(bp)){//下行转换是不安全的
//使用dp指向的Derived对象
}
else{
//使用bp指向的Base对象
}
if(Base*bp = static_cast<Derived *>(dp)){//上行转换是安全的
//使用bp指向的Derived对象
}
else{
//使用dp指向的Base对象
}
```
### dynamic_cast
- dynamic_cast 主要用于类层次间的上行转换和下行转换还可以用于类之间的交叉转换cross cast
- 在类层次间进行上行转换时dynamic_cast 和 static_cast 的效果是一样的;
- 在进行下行转换时dynamic_cast 具有类型检查的功能,比 static_cast 更安全。
- dynamic_cast 是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
```
dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)
```
- type 必须是一个类类型
- 在第一种形式中type 必须是一个有效的指针
- 在第二种形式中type 必须是一个左值
- 在第三种形式中type 必须是一个右值。
- 在上面所有形式中e 的类型必须符合以下三个条件中的任何一个:
- e 的类型是是目标类型 type 的公有派生类
- e 的类型是目标 type 的共有基类
- e 的类型就是目标 type 的的类型。
- 如果一条 dynamic_cast 语句的转换目标是指针类型并且失败了,则结果为 0。如果转换目标是引用类型并且失败了则 dynamic_cast 运算符将抛出一个 std::bad_cast 异常(该异常定义在 typeinfo 标准库头文件中)。e 也可以是一个空指针,结果是所需类型的空指针。
1. 指针类型.
举例Base 为包含至少一个虚函数的基类Derived 是 Base 的共有派生类,如果有一个指向 Base 的指针 bp我们可以在运行时将它转换成指向 Derived 的指针,代码如下:
```
if(Derived _dp = dynamic_cast<Derived _>(bp)){
//使用 dp 指向的 Derived 对象
}
else{
//使用 bp 指向的 Base 对象
}
```
值得注意的是在上述代码中if 语句中定义了 dp这样做的好处是可以在一个操作中同时完成类型转换和条件检查两项任务。
2. 引用类型
因为不存在所谓空引用,所以引用类型的 dynamic_cast 转换与指针类型不同,在引用转换失败时,会抛出 std::bad_cast 异常,该异常定义在头文件 typeinfo 中。
```
void f(const Base &b){
try{
const Derived &d = dynamic_cast<const Base &>(b);
//使用 b 引用的 Derived 对象
}
catch(std::bad_cast){
//处理类型转换失败的情况
}
}
```
### const_cast
- const_cast用于修改类型的 const 或 volatile 属性。
- 该运算符用来修改类型的 const(唯一有此能力的 C++-style 转型操作符)或 volatile 属性。除了 const 或 volatile 修饰之外, new_type 和 expression 的类型是一样的。
- 常量指针被转化成非常量的指针,并且仍然指向原来的对象;
- 常量引用被转换成非常量的引用,并且仍然指向原来的对象;
- const_cast 一般用于修改底指针。如 const char \*p 形式。
举例转换如下
```
const int g = 20;
int *h = const_cast<int*>(&g);//去掉const常量const属性
const int g = 20;
int &h = const_cast<int &>(g);//去掉const引用const属性
const char *g = "hello";
char *h = const_cast<char *>(g);//去掉const指针const属性
```
### reinterpret_cast
- new_type 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。
- reinterpret_cast 意图执行低级转型,实际动作(及结果)可能取决于编辑器,这也就表示它不可移植。
- 举一个错误使用 reintepret_cast 例子将整数类型转换成函数指针后vc++在执行过程中会报"...中的 0xxxxxxxxx 处有未经处理的异常: 0xC0000005: Access violation"错误:
```
#include <iostream>
using namespace std;
int output(int p){
cout << p <<endl;
  return 0;
}
typedef int (*test_func)(int );//定义函数指针test_func
int main(){
int p = 10;
test_func fun1 = output;
fun1(p);//正确
test_func fun2 = reinterpret_cast<test_func>(&p);
fun2(p);//...处有未经处理的异常: 0xC0000005: Access violation
return 0;
}
```
## 3 c++强制转换注意事项
- 新式转换较旧式转换更受欢迎。原因有二,一是新式转型较易辨别,能简化“找出类型系统在哪个地方被破坏”的过程;二是各转型动作的目标愈窄化,编译器愈能诊断出错误的运用。
- 尽量少使用转型操作,尤其是 dynamic_cast耗时较高会导致性能的下降尽量使用其他方法替代。

View File

@@ -0,0 +1,118 @@
# 初始化方法
> 参考文献
> * [谈谈C++中各种初始化方式](https://blog.csdn.net/u014359097/article/details/50788911)
> * [C++的各种初始化方式](https://www.cnblogs.com/pluse/p/7088880.html)
## 1 初始化方法
C++中的初始化主要包括五种:
* 默认初始化
* 值初始化
* 直接初始化
* 拷贝初始化
* 列表初始化
```
class Car{
public:
int a=0;
int b=1;
Car(int aa,int bb):a(aa),b(bb){};//初始化列表,进行初始化
Car(int aa):Car(aa,0){};//委托构造函数,使用第一个构造函数进行构造。
Car():Car(0,0){};//默认构造函数,委托构造函数
string m="fjeioaf";
string *n=&m;
};
//一下是初始化方法
Car t1(3,4);//调用构造函数
Car t2 = Car(3,4);//调用构造函数
// Car* t = new Car(3,4);
Car tt{3,4};//可以调用构造函数
vector<Car> ttt{Car(3.4),Car(5,6)};
```
### 默认初始化
默认初始化是定义对象时,没有使用初始化器,也即没有做任何初始化说明时的行为。
```
int i;
vector<int> v;
```
原理:
这些变量被定义了而不是仅仅被声明因为没有extern关键字修饰而且没有显式的赋予初值。特别的如果采用动态分配内存的方式即采用new关键字创建的变量不加括号时如int *p=new int;也是默认初始化加了括号如int *p=new int())为值初始化。变量的值与变量的类型与定义的位置有关系。
1. 对于内置类型变量如intdoublebool等如果定义在语句块外则变量被默认初始化为0如果定义在语句块内变量将拥有未定义的值。
2. 对于类类型的变量如string或其他自定义类型不管定义于何处都会执行默认构造函数。如果该类没有默认构造函数则会引发错误。因此建议为每个类都定义一个默认构造函数=default
### 值初始化
> 未明确的直接初始化
* 值初始化是值使用了初始化器(即使用了圆括号或花括号)但却没有提供初始值的情况。
```
int i{};
new int();
new int{};
```
原理:
1. 当不采用动态分配内存的方式即不采用new运算符写成int a();是错误的值初始化方式,因为这种方式声明了一个函数而不是进行值初始化。
2. 如果一定要进行值初始化必须结合拷贝初始化使用即写成int a=int();
3. 值初始化和默认初始化一样对于内置类型初始化为0对于类类型则调用其默认构造函数如果没有默认构造函数则不能进行初始化。
### 直接初始化和拷贝初始化
> 从形式而言,相对
* 直接初始化与拷贝初始化对应,其内部实现机理不同。
* 直接初始化是指采用小括号的方式进行变量初始化(小括号里一定要有初始值,如果没提供初始值,那就是值初始化了!)。
* 拷贝初始化是指采用等号(=)进行初始化的方式。拷贝初始化看起来像是给变量赋值,实际上是执行了初始化操作,与先定义再赋值本质不同。
```C++
vector<int> v1(10); //直接初始化,匹配某一构造函数
vector<string> v2(10); //直接初始化,匹配某一构造函数
vector<int> v3=v1; //拷贝初始化,使用=进行初始化
```
原理:
1. 对于内置类型变量如intdoublebool等直接初始化与拷贝初始化差别可以忽略不计。
2. 对于类类型的变量如string或其他自定义类型直接初始化调用类的构造函数调用参数类型最佳匹配的那个拷贝初始化调用类的拷贝构造函数。
### 列表初始化
列表初始化是C++ 11 新引进的初始化方式它采用一对花括号进行初始化操作。能用直接初始化和拷贝初始化的地方都能用列表初始化而且列表初始化能对容器进行方便的初始化因此在新的C++标准中,推荐使用列表初始化的方式进行初始化。
```
[new] T [object] { arg1, arg2, ... };
```
* 如果T是aggregate集合类型list对object成员逐个初始化。
* 如果T不是aggregate类型编译器查找最匹配的list参数的T的构造函数。
举例:
```
int a{3};
vector<int> b{3,4,5};
Car t{3,4};
vector<Car> ttt{Car(3.4),Car(5,6)};
```
* 所有其他初始化形式都是list initialization的特殊表现形式或者与其相关。理解的要点在于list中的参数要么按构造函数的参数声明顺序要么按aggregate类型成员声明顺序逐个赋值。
## 2 类的构造函数
### 默认构造函数
### 合成默认构造函数
### 委托构造函数
### 拷贝构造函数
### 构造函数类型和初始化的方法
> 介绍初始化的方法、构造函数的类型、初始化执行的顺序。
1. 列表初始化
2. 委托构造函数
3. 初始化函数体
4. 值初始化。(在成员变量定义的时候给出的值)
5. 默认初始化(以上情况都没有的时候)

View File

@@ -1,3 +1,8 @@
# 标准库-头文件
* [参考文献](https://blog.csdn.net/sxhelijian/article/details/7552499)
## 1 C 标准库
其中包含的引用头文件如下:

View File

@@ -7,4 +7,7 @@ int aa=3;
int hello(){
cout<<a+100<<endl;
return 0;
}
int N::world(){
return 111;
}

View File

@@ -7,7 +7,8 @@ const int aaa=10;//定义常量,在文件内部有效。
// class M;//仅进行声明
class N//对类类型进行了定义(当包含定义的时候,就应该尽量避免多次定义,使用条件编译进行控制)。类型定义并没有生成变量。
{
int m;//仅进行声明
public:
int m=0;//仅进行声明
int world();//仅进行声明
};
// extern N k;//仅声明了了一个变量

View File

@@ -6,6 +6,8 @@ int main()
{
cout<<a<<endl;
hello();
N nnn;
cout<<nnn.world()<<endl;
// a=12;
return 0;
}

View File

@@ -2,20 +2,27 @@
### 毕设
* 读论文
* 论文复现(一周时间)
- 读论文
- 论文复现(一周时间)
### 工作
* 制作简历(明天)
* 知识复习——语言
* C++语法、面向对象、机制、STL
* Java
* 知识复习——算法
* 数据结构
* 算法
* 知识复习——基础
* 计算机网络
* 数据库
* 操作系统
* Linux与网络编程
- 制作简历(明天)
- 知识复习——语言
- C++
- 语法 primer
- 面向对象
- 标准库 STL
- 设计模式有道云笔记gitee 设计模式库,书)
- effective 系列
- 系列视频
- 问题专项解决)
- Java语法、标准库
- 知识复习——算法
- 数据结构
- 算法
- 知识复习——基础
- 计算机网络
- 数据库
- 操作系统
- Linux 与网络编程