C++09

Day09总结

类型转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
* 类型转换——静态类型和动态类型转换(static cast)
* 类型转换——常量类型——重新解释类型转换
*
* 一般情况下,尽量少的去使用类型转换,除非来解决非常特殊的问题
*
* 1.静态转换
* 1.1用于类层次结构中基类(父类)和派生类(子类)之间引用或者指针的转换
* 1.1.1进行上行转换(派生类引用转换成基类)是安全的
* 1.1.2进行下行转换(基类指针引用转换成派生类)是不安全的
* 1.2 用于基本数据类型之间的转换,如把int转换成char。
* 这种转换的安全性也要开发人员来保证
*
*
* 静态类型转换 static_cast
* 语法 static_cast<目标类型>(原对象)
* 对于内置数据类型是可以转换的
* 对于自定义数据类型,必须是父子之间的指针或者引用可以转换成功
* 2.动态类型转换
* 语法 dynamic_cast<目标类型>(原对象)
* 对于内置数据类型是不可以转换的
* 对于自定义数据类型
* 父转子:不安全,转换失败
* 子转父:安全,转换成功
* 如果发生堕胎,总是安全的
* 3.常量转换(const_cast)
* 该运算符用来修改类型的const属性
* 常量指针被转化为非常量指针,并且仍然指向原来的对象
* 常量引用被转化为非常量引用,并且仍然指向原来的对象
* 注意:不能直接对非指针和非引用的变量使用const_cast 操作符去直接移除其const
* */
/*******************************************************/
//1.静态类型转换
#include<bits/stdc++.h>
using namespace std;
//1.1 内置数据类型的静态类型转换
void test01()
{
//内置数据类型
char a='a';
//static_cast<目标类型>(原对象)
double d = static_cast<double>(a);
cout<<d<<endl;

}
//1.2 (指针实现)自定义数据类型的静态类型转换
class Base
{
virtual void func(){}
};
class Son:public Base
{
virtual void func(){}
};
class Other
{};
void test02()
{
//自定义数据类型
Base*base =NULL;
Son *son =NULL;

//base转为Son*类型 向下类型转换 不安全
Son*son2 = static_cast<Son*>(base);
//Son 转为Base*类型 向上类型转换 安全
Base*base2 = static_cast<Base*>(son);
//base 转为Other* 是不会成功的
//因为没有父子关系
/*Other*other = static_cast<Base*>(Other);*/
}
//1.3(引用实现)静态类型转换
void test03()
{
Base base;
Son son;
Base& base1 =base;
Son& son1 = son;
//Son 转为Base*类型 向上类型转换 安全
Base& base2 = static_cast<Base&>(son1);
//base转为Son*类型 向下类型转换 不安全
Son& son2 = static_cast<Son&>(base1);
//无继承关系之间的转换 是不成功的
/*Other&other = static_cast<Base&>(Other);*/
}
/*********************************************************/
//2.动态类型转换
void test04()
{
//内置数据类型,是不允许内置数据类型之间的转换的
char c = 'c';
//以下代码会报错
/* double d = dynamic_cast<double>(c);*/
}
void test05()
{
//base转为Son*类型 向下类型转换 不安全
//不安全,转换失败
Base*base =NULL;
Son *son =NULL;
/*Son*son2 = dynamic_cast<Son*>(base);*/
//Son 转为Base*类型 向上类型转换 安全
Base*base2 = dynamic_cast<Base*>(son);

//如果发生多态,那么父子之间转换总是安全的
Base *base3 = new Son;
//将base3转为Son*
Son*son3 = dynamic_cast<Son*>(base3);
}
/*********************************************************/
//3.常量转换
//3.1指针类型的转换
void test06()
{
const int *p =NULL;
//将const int*转为int*
int *p2 = const_cast<int *>(p);
//将 p2转为const int*
const int *p3 = const_cast<const int *>(p2);
}
//3.2 指针类型的转换
void test07()
{
const int a = 10;//放在符号表中,直接拿掉不可以!!
const int &aRef = a;
int &aRef2 = const_cast<int&>(aRef);
//注意:不能直接对非指针和非引用的变量使用const_cast 操作符去直接移除其const
/*int b = const_cast<int>(a);*/

}
/********************************************************/
//4.重新解释转换 最不安全 不建议用
void test08()
{
int a = 10;
int *p = reinterpret_cast<int*>(a);

//将base*转为Other*
Base*base = NULL;
Other *other = reinterpret_cast<Other*>(base);//是可以转换成功的,就会引起很多操作问题
//不建议使用

}

异常的基本语法

异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
* 三个关键字 try throw catch
* try:试图执行一段可能会出现异常的代码
* throw:出现异常后,抛出异常的关键字 throw+类型
* catch :捕获异常,catch(类型)
* 如果在try段执行期间没有异常,那么跟在try后面的catch字句就不会执行
* catch字句会根据出现的先后顺序被检查,匹配的catch语句捕获并处理异常(或继续抛出异常)
* 如果匹配的处理未找到,则于宁函数terminate 将自动被调用,其缺省功能调用abort 终止程序
* 如果处理不了的异常,可以在catch的最后一个分支,使用throw,向上抛
*
* 可以自定义自己的异常类MyError
* */
#include<bits/stdc++.h>
using namespace std;
class MyError
{
public:
void printError()
{
cout<<"我自己的异常类错误"<<endl;
}
};

class Person
{
public:
Person()
{
cout<<"Person的构造函数的调用"<<endl;
}
~Person()
{
cout<<"Person的析构函数的调用"<<endl;
}
};
int myDivide(int a, int b)
{
if(b==0)
{
/*return -1;*///C语言处理异常缺陷在于,返回值没有统一,返回的值可以是异常的结果,也可以是正确的结果
/*throw 3.14*/;//抛出一个1也可以,3.14也可以,不过需要捕获double类型
//有throw,必要catch
Person p1;
Person p2;
cout<<"AAA"<<endl;

//可以发现,Person p1,p2在throw之间,就已经被释放掉了
/*这就叫栈解旋:从try代码块开始其,到throw抛出异常前
所有栈上的对象都被释放掉,释放的顺序和构造的顺序都是相反的。*/
throw MyError();
}
return a/b;//当a/b=-1时,无法判断是否出错
}

void test01()
{
int a = 10;
int b= 0;
//尝试执行一段可能会出现异常的代码
try {
int ret = myDivide(a,b);
cout<<"ret的结果为 "<<ret<<endl;
}
catch (double)
{
//捕获到double以后,不想处理这个异常,想继续往上抛,直接加throw
throw ;
cout<<"double 类型异常的捕获"<<endl;
}
catch (MyError)
{
cout<<"找到啦"<<endl;
}
catch (...)
{
cout<<"其他 类型异常的捕获"<<endl;
}

}
int main()
{
try {
test01();
}
// catch (double)
// {
// cout<<"double 类型异常的捕获"<<endl;
// }
catch (int)
{
cout<<"MAin 函数Int 类型异常的捕获"<<endl;
}
catch (...)
{
cout<<"Main 函数其他 类型异常的捕获"<<endl;
}
//异常必须要有人处理,如果

system("pause");
return 0;
}

异常变量的声明周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
*异常变量的生命周期
* 1.catch (MyException e)会用拷贝构造
2.catch (MyException &e) 引用方式,建议用这种方式,节省开销
3.catch (MyException *e)指针方式,接收抛出 new MyException();堆区创建的对象,记得手动释放delete e;
* */
#include<bits/stdc++.h>
using namespace std;
class MyException
{
public:
MyException()
{
cout<<"MyException构造函数的调用"<<endl;
}
MyException(const MyException&myException)
{
cout<<"MyException拷贝函数的调用"<<endl;
}
~MyException()
{
cout<<"MyException析构函数的调用"<<endl;
}
};
void doWork(const char *string1)
{
throw MyException();
}
void test01()
{
try {
doWork(nullptr);
}
// catch (MyException e)会用拷贝构造
// catch (MyException &e) 引用方式,建议用这种方式,节省开销
// catch (MyException *e)指针方式,接收抛出 new MyException();堆区创建的对象,记得手动释放delete e;
catch (MyException &e)
{
cout<<"MyException异常捕获"<<endl;
}
}

异常多态的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
* 异常的多态使用
* 提供基类异常类:BaseException 纯虚函数 virtual void printError()=0;
* 提供两个子类继承异常基类,重写父类中的纯虚函数
* 测试 利用父类引用去接受子类对象,实现多态
* 抛出那种一场就打印哪种异常的printError函数
*
* */
#include<bits/stdc++.h>
using namespace std;
//异常的基类
class BaseException
{
public:
virtual void printError()=0;
};
//空指针异常
class NullPointerException:public BaseException
{
public:
virtual void printError()
{
cout<<"空指针异常"<<endl;
}
};
//越界异常
class OutOfRangeException:public BaseException
{
public:
virtual void printError()
{
cout<<"越界异常"<<endl;
}

};
void doWork(const char *string1)
{
// throw NullPointerException();
throw OutOfRangeException();
}
void test01()
{
try {
doWork(nullptr);
}
catch (BaseException&baseException)
{
baseException.printError();
}
}

系统标准异常类

异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
* 使用系统标准异常类
* 标准异常头文件#include <stdexcept>
* 使用系统异常类 out_of_range("char*)等
* 捕获:catch (exception &e)或者对应类
*
* */
#include<bits/stdc++.h>
using namespace std;
//使用系统标准依然需要引用一个头文件
//#include <stdexcept>
class Person
{
public:
Person(int age)
{
if(age<0||age>150)
{
//年龄越界异常抛出
throw out_of_range("年龄必须在100-150之间");
}
this->m_Age = age;
}
int m_Age;
};
void test01()
{
try {
Person p1(151);
}
catch (out_of_range&e)//也可以catch(exception&e)
{
cout<<e.what()<<endl;
}

}

标准输入流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
* 输入输出流
* cin.get()一次只能读取一个字符
* cin.get(一个参数)读取一个字符
* cin.get(两个参数)可以读取字符串,不会读取换行符
* cin.getline()读取一行,会读取换行符
* cin.ignore() 忽略字符
* cin.peek()偷窥,偷看一个字符然后再放回缓冲区
* cin.putback()把字符放回缓冲区
*
* */

using namespace std;
/********************************************************/
void test01()
{
//输入as 缓冲区中有 a s \n 第一个拿a,第二个拿s 第三个拿\n
//第四个等待输入
char c = cin.get();
cout<<"c = "<<c<<endl;
c = cin.get();
cout<<"c = "<<c<<endl;
c = cin.get();
cout<<"c = "<<c<<endl;
c = cin.get();
cout<<"c = "<<c<<endl;
}
/*********************************************************/
//cin.get(两个参数)读取字符串的时候,不会读取换行符。
void test02()
{
//cin.get(两个参数)
char buf[1024];
cin.get(buf,1024);
char c = cin.get();
if(c=='\n')
{
cout<<"换行还在缓冲区"<<endl;
}else cout<<"换行不在缓冲区"<<endl;

cout<<buf<<endl;
}
/*********************************************************/
//cin.getline()
void test03()
{
char buf[1024];
cin.getline(buf,1024);
char c = cin.get();
if(c=='\n')
{
cout<<"换行还在缓冲区"<<endl;
}else cout<<"换行不在缓冲区"<<endl;
// cin.getline 把换行符读取,并且扔掉
cout<<buf<<endl;
}
/*********************************************************/
//cin.ignore ()
void test04()
{
cin.ignore(2);//没有参数代表忽略一个字符
//带参数,则说明忽略了n个字符
char c =cin.get();
cout<<"c ="<<c<<endl;
}
/*********************************************************/
//cin.peek()
void test05()
{
//输入as 看一眼 a,然后再放回缓冲区 缓冲区中还是as


char c = cin.peek();
cout<<"c = "<<endl;
cout<<"c ="<<c<<endl;
c = cin.get();
cout<<"c ="<<c<<endl;
}
/********************************************************/
//cin.putback()放回
void test06()
{
char c = cin.get();
cin.putback(c);
char buf[1024];
cin.getline(buf,1024);
cout<<buf<<endl;
//先拿走,后来又放回去了
}
/******************************************************/
//判断用户输入的内容,是字符串还是数字
void test07()
{
cout<<"请输入一个字符串或者数字:"<<endl;
char c = cin.peek();
if(c>='0'&&c<='9')
{
int num;
cin>>num;
cout<<"您输入的是数字"<<num<<endl;
} else if(c>='a'&&c<='z')
{
char buf[1024] = {0};
cin>>buf;
cout<<"您输入的是字符串"<<buf<<endl;
}else
{
cout<<"您输入的是啥玩意??"<<endl;
}
}
/********************************************************/
//让用户输入一个数字,必须在0-10之间的数字,如果输入有误,重新输入
void test08()
{
cout<<"请输入0-10之间的数字"<<endl;
int num;
while(1) {
cin >> num;
if (num > 0 && num <= 10) {
cout << "输入正确——数字为" << num << endl;
break;//输入正确就退出
}
cout << "输入有误"<<endl;
//缓冲区中的标志位
cin.clear();
cin.sync();//清空标志位,并且刷新缓冲区
// cout<<"Cin.fail = "<<cin.fail()<<endl;
}
}

标准输出流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
* 标准输出流
* cout.put() 缓冲区写字符
* cout.write()从buffer中写num个字节到当前输出流中
*
*
* */
#include<bits/stdc++.h>
using namespace std;

void test01()
{
/*
cout.put('a').put('b');
char buf[] = "helloworld";
cout.write(buf,strlen(buf));
*/

}
//格式化输出
void test02()
{
//通过流成员函数
int number =99;
cout.width(20);//预留20空间
cout.fill('*');//填充
cout.setf(ios::left);//左对齐
cout.unsetf(ios::dec);//卸载十进制
cout.setf(ios::hex);//安装十六进制
cout.setf(ios::showbase);//显示进制基数
cout.unsetf(ios::hex);//卸载十六0进制
cout.setf(ios::oct);//安装八进制

cout<<number<<endl;//打印
}
//使用控制符
void test03()
{
int number = 88;
cout<<setw(20)
<<setfill('*')
<<setiosflags(ios::showbase)//显示基数
<<setiosflags(ios::left)//左对齐
<<hex //安装十六进制
<<number
<<endl;
}
-------------本文结束,感谢您的阅读-------------