c++类型转换,异常,输入输出流

c++类型转化,c++严格遵守类型匹配

静态转换static_cast的用法

1.用于类层次结构中基类和派生类指针或者引用之间的转换

子类---->父类(不安全)

父类----->子类(安全)

2.普通的类型转换

//基本类型转化
#include<iostream>
using namespace std;
int main()
{
    char a = 'c';
    double b = static_cast<double>(a);
    cout << b << endl;
    return 0;
}

 不存在父子关系的类无法转换

#include<iostream>
using namespace std;
class father{};
class child : public father{};
void test()
{
    father *p1 = NULL;
    child *p2 = NULL;
    //派生类向基类转换(不安全)
    father* pp1 = static_cast<father*>(p2);
    //基类转派生类(安全)
    child* pp2 = static_cast<child*>(p1);
}
int main()
{
    test();
    return 0;
}

动态类型转换dynamic_cast:

dynamic_cast非常的严格失去精度或者不安全都不可以转换。类似于上面的派生类转基类

#include<iostream>
using namespace std;
class father
{
public:
    virtual void func(){}         //虚函数
};
class child : public father
{
public:
    void func(){}
};
void test()
{
    father *p = new child;          //父类的指针指向子类的对象
    child *b = dynamic_cast<child*>(p);   //由父类转为子类是不安全的,但是这里发生了多态,所有就可以使用动态的类型转换
}
int main()
{
    test();
    return 0;
}

常量转换const_cast:

只能对指针或者引用进行转换,但是一般不用,我们只需要强制类型转换即可

void test2()
{
    int* a =NULL;
    const int* b = NULL;
    //去掉const
    int* c = const_cast<int*>(b);
    //加上const
    const int* d = const_cast<const int*>(a);
    int e;
    int& f = e;
    const int& h = e;
    //加上const
    const int& g = const_cast<const int&>(f);
    //去掉const
    int& L = const_cast<int&>(h);

}

重新解释转换reinterpret_cast:(最不安全)

这个不太适用就不解释了

异常的基本使用:

//基本使用
#include<iostream>
using namespace std;
void func(int a,int b)
{
    if (b == 0)
    {
	throw - 1;//抛出异常
    }
}
void test()
{
    int a = 10;
    int b = 0;
    try
    {
    	func(a, b);
    }
    catch (int)  //捕获int异常
    {
    	cout << "异常已经被捕获\n";
    }
    catch (...)    //捕获任意类型异常
    {
    	cout << "其他异常被捕获\n";
    }
    
int main()
{
    test();
    return 0;
}

异常的跳级处理:

#include<iostream>
using namespace std;
void func(int a, int b)
{
    if (b == 0)
    {
    	throw - 1;//抛出异常
    }
}
void test()
{
    int a = 10;
    int b = 0;
    try
    {
    	func(a, b);
    }
    catch (int)  //捕获int异常
    {
    	cout << "test函数捕获异常\n";
    }
}
//main函数包含test()函数,test函数包含func()函数,并且每一层包含下一层的异常捕获 。
//然后main函数开始执行,调用test函数,然后test函数调用func函数,function函数抛出异常,先返回并且被test函数捕获处理
//这时候main函数里面的异常捕获并没有发挥作用
int main()
{
    try
    {
    	test();
    }
    catch (int)
    {
    	cout << "main函数捕获int异常\n";
    }
    return 0;
}

要是test函数不想处理异常可以把异常抛给下一级

catch (int)  //捕获int异常
{
    throw;                //加上这行代码异常将会抛给main函数
    cout << "test函数捕获异常\n";
}

 

如果throw的异常都没有人处理,那么程序将崩溃。调用terminate函数中断程序。

捕获自定义的类异常:

#include<iostream>
using namespace std;
class person{};
void func(int a,int b)
{
    if (b == 0)
    	throw person();//类名()表示匿名对象
}
void test()
{
    int a = 10;
    int b = 0;
    try      //尝试执行这个函数
    {
    	func(a,b);
    }
    catch (person)
    {
    	cout << "自定义类型异常\n";
    }
}
int main()
{
    test();
    return 0;
}

 

c++异常处理方式,使得异常的引发和处理不必在一个函数中,这样底层的函数可以着重去解决具体的问题,而不必过多考虑异常的处理。

栈解旋:

栈解旋的定义:从try开始到throw抛出异常之前,所有栈上的对象都会被释放。(出现异常的情况下)

#include<iostream>
using namespace std;
class father{};  //用来抛出异常的自定义类型
class person     //用来查看栈解旋的类
{
public:
    person()
    {
    	cout << "构造函数\n";
    }
    ~person()
    {
    	cout << "析构函数\n";
    }
};
void func(int a, int b)
{
    if (b == 0)
    {
    	person p1;
    	person p2;
    	throw father();//类名()表示匿名对象,出现错误就抛出father类型对象
    }
}
void test()
{
    int a = 10;
    int b = 0;
    try      //尝试执行这个函数
    {
    	func(a, b);
    }
    catch (father)        ///捕获father类型的异常
    {
    	cout << "自定义类型异常\n";
    }
}
int main()
{
    test();
    return 0;
}

运行结果:
构造函数
构造函数
析构函数
析构函数
自定义类型异常
请按任意键继续. . .

在处理异常之前就将栈释放,在main函数return之前就释放

异常在多态类的使用:

#include<iostream>
using namespace std;
class father    //父类
{
public:
    virtual void FUNC()
    {}
}; 
class child1 :public father
{
public:
    virtual void FUNC()
    {
    	cout << "壹号异常\n";
    }
};
class child2 :public father
{
public:
    virtual void FUNC()
    {
    	cout << "贰号异常\n";
    }
};
void func(int a, int b)
{
    if (b == 0)
    {	
    	throw child1();          //这里抛出的是派生类异常
    }
}
void test()
{
    int a = 10;
    int b = 0;
    try                              //尝试执行这个函数
    {
    	func(a, b);
    }
    catch (father& e)          //这里捕获的是父类的对象,用父类的指针或者引用指向子类的对象 ,已经发生了多态
    {
    	e.FUNC();             //既然已经发生了多态就是晚绑定,运行时绑定,那么就会调用类同名函数(FUNC)
    }
}
int main()
{
    test();
    return 0;
}

使用系统自定义的异常类:

c++给我们也提供了很多的异常类,他们都是通过继承的方式组织起来的。

#include<iostream>
#include<stdexcept>           //包含头文件
using namespace std;
class person
{
public:
    person(string a,int b)
    {
    	this->ages = b;
    	this->name = a;
    	if (b > 200 || b < 0)
    	{
    		throw out_of_range("年龄越界了\n");
    	}
    }
    string name;
    int ages;
};

void test()
{
    try      
    {
    	person p("刘老师", 1000);
    }
    catch (out_of_range& e)          //这里推荐传引用,out_of_range其实也是一个类类型
    { 
    	cout <<e.what();             //每个错误类都包含一个what()
    }
}
int main()
{
    test();
    return 0;
}

 

自己编写异常类:

 

#include<iostream>
#include<string>
using namespace std;
//_EXCEPTION_INLINE virtual __CLR_OR_THIS_CALL ~exception() _NOEXCEPT;
//_EXCEPTION_INLINE virtual const char * __CLR_OR_THIS_CALL what() const;
//c++中所有的系统自定义异常都是继承exception类,基类中有很多函数,我们要进行重写只需要对用到的函数进行重写就可以了
class perro:public exception          //点击F12可以查看基类,现在对上面的两个函数进行重写,因为不会继承到构造函数所以自己写
{
public:
    perro(string error)
    {
     	this->error = error;
    }
    virtual ~perro()         //因为也没有在堆上创建对象所以这个析构也就不自己实现了
    {
    
    }
    virtual const char * what() const
    {
    	return this->error.c_str();     //以为基类的what函数返回值是char* 类所以我们要对string类型进行强转
    }
    string error;
};
class person
{
public:
    person(string name, int ages)
    {
    	this->name = name;
    	if (ages<0 || ages>200)
    	{
    		throw perro("年龄太大了");
    	}
    	else
    		this->ages = ages;
    }
    string name;
    int ages;
};
void test()
{
    try
    {
    	person p("猪八戒", 300);
    }
    catch (perro & p1)
    {
    	cout << p1.what() << endl;
    }
}
int main()
{
    test();
    return 0;
}

C++输入输出流:

C++输入输出包含三方面的内容,标准IO(标准的键盘到屏幕,输出显示到键盘),文件IO(操作的是外存磁盘文件之间的输入输出),串IO(对内存中的指定的空间进行输入输出,通常指数组)

i-o-stream采用的是菱形继承,设计这个的大牛说的是,如果让他再设计一次,他不会再用菱形继承了,因为隐患太大了

标准输入输出:

//cin.get()一次只能读取一个字符
//cin.get(一个参数)读一个字符
//cin.get(两个参数)可以读字符串
//cin.getline()
//cin.ignore()
//cin.peek()
//cin.putback()

#include<iostream>
using namespace std;
void test()
{
    char c = cin.get();
    cout << "c =" << c << endl;
}
int main()
{
    test();
    return 0;
}

运行结果:
abc
c =a
请按任意键继续. . .
#include<iostream>
using namespace std;
void test()
{
    char c = cin.get();
    cout << "c =" << c << endl;
    c = cin.get();
    cout << "c =" << c << endl;
}
int main()
{
    test();
    return 0;
}


运行结果:
as
c =a
c =s
请按任意键继续. . .
#include<iostream>
using namespace std;
void test()
{
    char c = cin.get();
    cout << "c =" << c << endl;
    c = cin.get();
    cout << "c =" << c << endl;
    c = cin.get();
    cout << "c =" << c << endl;
}
int main()
{
    test();
    return 0;
}
运行结果:
as
c =a
c =s
c =

请按任意键继续. . .
//缓冲区有三个,一个a,s,\n,依次将三个字符读取出来
#include<iostream>
using namespace std;
void test()
{
    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;
}
int main()
{
    test();
    return 0;
}

运行结果:
as
c =a
c =s
c =


卡在了这里,程序在等你继续输入,因为缓冲区里面的三个字符都已经被读取完毕了
#include<iostream>
using namespace std;
//cin.get(两个参数)不会把缓冲区中的换行符拿走,也就是说换行符还在缓冲区之中
void test2()
{
    char buf[1024];
    cin.get(buf, 1024);         //等待输入一个字符串
    cout << buf << endl;
    //关于换行符是否还在缓冲区之中我们来读取一下
    char c = cin.get();   //如果缓冲区中有数据就从缓冲区中读取一个字符
    if (c == '\n')
    {
    	cout << "换行符还在缓冲区\n";
    }
}
int main()
{
    test2();
    return 0;
}

运行结果:
ahichiaudhv
ahichiaudhv
换行符还在缓冲区
请按任意键继续. . .

cin.get(一个参数) 

#include<iostream>
using namespace std;
void test3()
{
    char ch;
    cin.get(ch);
    cout << ch;
    cin.get(ch);
    cout << ch;
}
int main()
{
    test3();
    return 0;
}
运行结果:
a
a
换行符还在缓冲区
请按任意键继续. . .
#include<iostream>
using namespace std;

void test4()
{
    char buf[1024];
    cin.getline(buf,1024); //cin系列函数的意思都是从缓冲区读取多大长度的字符,只是读取,你没让输出的话不会输出
    char c;
    c = cin.get();
    if (c == '\n')
    {
    	cout << "换行符还在缓冲区\n";
    }
}
int main()
{
    test4();
    return 0;
}

运行结果:
abc


//什么意思呢?当你输入abc\n之后然后abc被getline读取了,然后char c并没有拿到\n,在等你输入数据,这是因为getline将换行符读取了,只是将换行符扔了而已
#include<iostream>
using namespace std;
void test5()
{
    cin.ignore();
    char c = cin.get();
    cout << c << endl;
}
int main()
{
    test5();
    return 0;
}

运行结果:
as
s
请按任意键继续. . .
//读取一个字符并扔掉

 

#include<iostream>
using namespace std;
void test6()
{
    char c = cin.peek();     //偷窥,从缓冲区偷窥一个字符但不拿出来
    cout << c << endl;
    char b = cin.get();
    cout << b << endl;
}
int main()
{
    test6();
    return 0;
}

结果:
as
a
a
请按任意键继续. . .


 

#include<iostream>
using namespace std;
void test7()
{
    char c = cin.get();
    cout << c << endl;
    cin.putback(c);
    char buf[1024];
    cin.get(buf, 1024);
    cout << buf << endl;
}
int main()
{
    test7();
    return 0;
}

运行结果:
hello world
h
hello world
请按任意键继续. . .

//cin.get()从缓冲区读取一个字符并且打印,然后cin.back()再将c又放了回去,然后再由get(两个参数)完整打印

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值