C语言类型转换
隐式类型转换:
int myMax(int a,int b){}
调用:myMax(1,‘A’);
强制类型转换(显式类型转换):
int *p = (int *)malloc(…)
typename1 a = (typename2)b;
C++里面提供一组可以在不同场合使用的强制转换(本质就是类模板)
static_cast(exp)
1.用于基本的类型转换,不能用于指针间的转换(pc = static_cast<char*>(pi)😉
比如将Int转为char型(和C语言强制类型转换相似)
(static_cast安全性由程序员自己维护)
T:要转成的类型 exp:要转换的变量
2.继承体系中:可以实现强制类型转换 危险!
在同一继承体系:
向上转 子->父 没有问题 因为父类的行为都在子类中
向下转 父->子 可能会有问题,编译的时候有可能不会发现
3.C++所有隐式转换都是用static_cast(exp)来实现的
int i = 10;
double d = i;
reinterpret_cast
dynamic_cast 动态的
const_cast
#include <iostream>
using namespace std;
class Base
{
protected:
int i;
int j;
public:
Base(int i,int j)
{
this->i = i;
this->j = j;
}
void printA(){cout << "i:" << i << endl;}
void printSum()
{
cout << "i+j" << i+j << endl;
}
};
class Derived:public Base
{
protected:
int a;
int b;
public:
Derived(int i,int j,int a,int b):Base(i,j)
{
this->a = a;
this->b = b;
}
void printB(){cout << "a:" << a << endl;}
void printSum()
{
cout << "a+b" << a+b << endl;
}
};
int main()
{
int i = 74;
char c = 'c';
cout << "i:" << i << endl;
cout << "c:" << c << endl;
int *pi = &i;
char *pc = &c;
c = static_cast<char>(i);
cout << "i:" << i << endl;
cout << "c:" << c << endl;
cout << "-----------------------------------" << endl;
Derived *d1 = new Derived(1,2,3,4);
d1->printSum();
Base *b = static_cast<Base*>(d1); //将派生类强制转换为基类
b->printA();
b->printSum();
return 0;
}
C++里面提供一组可以在不同场合使用的强制转换(本质就是类模板)
static_cast(exp)
reinterpret_cast(exp) 重新解释 (最危险)
1.用于指针与整数之间的强制类型转换
*2.用于指针之间的强制类型转换
3.函数之间也可以进行强制类型转换
问题:
操作符修改了操作数类型,但是仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换
reinterpret_cast映射出来的类型仅仅为了“故弄玄虚”
dynamic_cast(exp) 动态的
const_cast(exp)
#include <iostream>
using namespace std;
int main()
{
int x = 1;
char c = 'c';
cout << "x:" << x << endl;
cout << "c:" << c << endl;
int *px = reinterpret_cast<int*>(&x);
char *pc = reinterpret_cast<char*>(&c);
cout << "x:" << *px << endl;
cout << "c:" << *pc << endl;
return 0;
}
C++里面提供一组可以在不同场合使用的强制转换(本质就是类模板)
static_cast(exp)
reinterpret_cast(exp) 重新解释 (最危险)
dynamic_cast(exp) 动态的 (最独特)
1.主要是用于类层次间的转换,还可以用于类之间的转换;
2.dynamic_cast最特殊,涉及到多态,C语言中就没有强制类型转换可以替代
3.dynamic_cast有类型检测比static_cast更安全(运行时候检查)
用于继承体系中进行安全的“向下转换”(父->子)
向上转可以,但是没必要,可以用虚函数实现
*4.用的时候要有虚函数 要有多态,才可以用
因为多态是向上转,本来就是基类指针(引用)指向子类对象
只不过又转回了子类(向下转)而已
const_cast(exp)
#include <iostream>
using namespace std;
class Animals //抽象类
{
public:
virtual void cry() = 0; //纯虚函数
};
class Dog:public Animals
{
public:
void cry()
{
cout << "dog cry..." << endl;
}
void Lookhome()
{
cout << "dog lookhome..." << endl;
}
};
class Cat:public Animals
{
public:
void cry()
{
cout << "cat cry..." << endl;
}
void playBall()
{
cout << "cat playBall..." << endl;
}
};
void func(Animals *b)
{
b->cry();
Dog *d = dynamic_cast<Dog*>(b); //向下转 基类指针->派生类指针
d->Lookhome();
Cat *c = dynamic_cast<Cat*>(b);
c->playBall();
}
int main()
{
Dog d;
Cat c;
func(&d);
func(&c);
return 0;
}
C++里面提供一组可以在不同场合使用的强制转换(本质就是类模板)
static_cast(exp)
reinterpret_cast(exp) 重新解释 (最危险)
dynamic_cast(exp) 动态的 (最独特)
const_cast(exp)
用于去除变量的const属性
不能改变基础类型
#include <iostream>
using namespace std;
int main()
{
const int c_val = 1;
int &use_val = const_cast<int&>(c_val); //use_val没有const属性的c_val
int *ptr_val = const_cast<int*>(c_val); //基础类型被改变就无效
use_val = 666;
cout << use_val<< endl;
return 0;
}
异常处理机制;
异常概念:
异常是程序运行时候遇到的任何错误(同步错误)或者意外行为(非语法错误,非逻辑错误)
(数组下标越界/段错误/除数为0)
异常机制:
程序员在编程时候对这些潜在问题进行适当处理,预防意外情况发生
分为两个部分:
异常的检测/异常的处理
(分开进行)
语法:
1.抛掷异常: throw
void fun()
{
…
throw<异常对象>; <异常对象>一般表示类型,可以是普通数据类型也可以是自定义类型
…
}
2.检测(捕获)异常 try块
将那些有可能产生错误的语句放进try部分
try
{
…
void fun(); throw
…
}
3.处理异常 catch块
catch(<异常对象类型>)
{
异常的处理程序
}
注意点:
1.假如try部分没有引起异常 catch不会执行
2.如果try块没有匹配的处理程序,ternimal函数将被自动调用
ternimal函数功能: 调用abort()终止程序
共同点:终止程序
exit(1):会做一些收尾工作,变量、对量的回收
abort():直接结束
3.异常机制与函数机制互不干涉,
捕捉方式是基于类型匹配,函数是基于参数匹配
4.函数:隐式类型转换
异常:必须精确匹配,不可以隐式类型转换
异常处理与函数机制:
异常处理特点:
异常检测和异常处理不同函数体;
这样底层可以着重解决问题 不必考虑异常处理;
上层调用者可以在适当位置设计针对不同类型的处理
函数处理特点:
通过栈处理,先进后出/依次访问,无法跳跃处理
异常处理遇到错误可以条约若干级进行处理
double div(double a,double b)
{
if(0 == b)
{
cout << “…” << endl;
exit(1);
}
return a/b;
}
#include <iostream>
using namespace std;
double div(double a,double b)
{
if(0 == b)
{
throw b; //抛掷异常
}
return a/b;
}
int main()
{
try //检测异常
{
cout << "8.4/2.1" << div(8.4,2.1) << endl;
cout << "8.4/3.7" << div(8.4,3.7) << endl;
cout << "8.4/0.0" << div(8.4,0.0) << endl;
}
catch(double) //处理异常
{
cout << "error..." << endl;
}
return 0;
}
异常接口声明:
1.为了增加程序可读性,可以在函数声明中列出所有可能抛出的异常类型
void func() throw(int,double,char) 仅仅只能抛出列出的类型
{
}
2.void func() 可以抛出所有类型的异常
3.void func() throw()
不抛出任何类型的异常
#include <iostream>
using namespace std;
void func() throw(int,double,char)
{
int i = 10;
throw "abc123";
}
int main()
{
try
{
func();
}
catch(int)
{
cout << "int" << endl;
}
catch(double)
{
cout << "double" << endl;
}
catch(char)
{
cout << "char" << endl;
}
catch(...)
{
cout << "抛出其他异常" << endl;
}
return 0;
}
栈解旋:
异常抛出后,在进入try块起,一直到异常抛掷前
期间里在栈上构造的对象都会被自动析构
这个过程就叫栈解旋。
#include <iostream>
using namespace std;
class Test
{
private:
int i;
int j;
public:
Test(int a,int b)
{
i = a;
j = b;
cout << "Test construct..." << endl;
}
~Test()
{
cout << "Test destruct..." << endl;
}
};
void func() //抛掷异常
{
int x = 10;
cout << "---------" << endl;
throw x;
cout << "---------" << endl;
}
void func2() //为了看清楚构造和析构
{
Test t1(10,20);
func();
}
int main()
{
try
{
func2();
}
catch(int)
{
cout << "int" << endl;
}
catch(...)
{
cout << "抛掷其他异常" << endl;
}
return 0;
}
异常的层次结构(继承中的异常/异常+多态)
catch的类型匹配可以作为多态的接口
写一个异常类作为成员数据(数组类中创建自己的异常类)
#include <iostream>
using namespace std;
class myArray
{
private:
int m_len;
int *m_p;
public:
myArray(int len);
~myArray();
int get_len(){return m_len;}
int& operator[](int index);
class eSize //抽象异常类
{
protected:
int size;
public:
eSize(int s){size=s;}
virtual void printS() = 0;
};
class eNegative:public eSize
{
public:
eNegative(int len):eSize(len){}
void printS()
{
cout << "eNegative,size为负数..." << endl;
}
};
class eZero:public eSize
{
public:
eZero(int len):eSize(len){}
void printS()
{
cout << "eZero,size为0..." << endl;
}
};
class tooBig:public eSize
{
public:
tooBig(int len):eSize(len){}
void printS()
{
cout << "tooBig,size太大了..." << endl;
}
};
class tooSmall:public eSize
{
public:
tooSmall(int len):eSize(len){}
void printS()
{
cout << "tooSmall,size太小了..." << endl;
}
};
};
myArray::myArray(int len)
{
if(len<0) throw eNegative(len);
if(0==len) throw eZero(len);
if(len>1000) throw tooBig(len);
if(len<10) throw tooSmall(len);
m_len = len;
m_p = new int[m_len];
}
myArray::~myArray()
{
if(m_p != NULL)
{
delete[] m_p;
m_p = NULL;
m_len = 0;
}
}
int& myArray::operator[](int index)
{
return m_p[index];
}
int main()
{
try
{
myArray a(30);
for(int i = 0;i < a.get_len();i++)
{
a[i] = i+1;
cout << a[i] << i << endl;
}
}
catch(myArray::eSize &e)
{
e.printS();
}
catch(...)
{
cout << "抛出其他异常..." << endl;
}
return 0;
}
输入输出流
iostream定义了4种流对象 cin cout
表示错误流
cerr:没有带缓冲,发送给他的任何内容都直接输出
clog:带缓冲,只有当缓冲区满了之后才发出
istream ostream fstreambase strstreambase…
#include <iostream>
using namespace std;
int main()
{
// 1.cin
int mint;
double mdouble;
cin >> mint;
cin >> mdouble;
cout << mint;
cout << mdouble;
char buf[100];
cin >> buf;
cout << buf;
//普通cin遇到空格就停止输入
// 2.cin.get() 成员函数
//读取单个字符
char ch1,ch2,ch3;
cin.get(ch1);
cout << ch1 << endl;
cin.get(ch2).get(ch3);
//3.cin.getline() 读取整行(回车键确定输入结束)
// 有两个参数,1.数组名,2.最大长度,(20,输入19个,最后一个空字符)
char buf[20];
cin.getline(buf,20);
cout << buf << endl;
//4.cin.ignore()
// 有时候取缓冲区一部分,而舍去另一部分
//两个参数:1.整型数值/整形表达式(表示忽略字符的最大数目)
// 2.字符表达式(遇到这个字符就停止忽略,继续输入)
int i1 = 0;
int i2 = 0;
cin >> i1;
cin.ignore(2,'\n');
cin >> i2;
cout << i1 << endl;
cout << i2 << endl;
// 如果输入 12 34 56 78
// 21 43 65 87 输出 12 \n 21
// cin.peek()偷窥
// cin.putback()
return 0;
}
文件
打开文件:
1.加头文件 #include
2.建立流 (定义流对象)
输入流对象 ifstream in; 定义一个输入流对象
输出流对象 ofstream out;
输入输出流对象 fstream both;
3.open打开文件
让一个文件与对应的流相关联
void open(const char*,int ,int = filebuf::openport)
1.const char* 表示相关联的文件名
2.文件访问方式: 读、写、读+写以及二进制模式等
ifstream in 默认值ios::in
ofstream out 默认值ios::out
3.文件保护方式
磁盘文件?
文本文件(ASCII文件)/二进制文件
文本文件:每个字符用ASCII代替,便于输入输出,占用空间较大
可以直接打开看到内容,可读性好
二进制文件:占用空间小 转换时间快
不是一个字节对应一个字符 打开之后都是乱码
读写: get() put() 读取一个字符
read() write() 读取一组字符
<流对象>.write()((char*)&<对象名>,sizeof(…))
#include <iostream>
#include <fstream>
using namespace std;
class Student
{
public:
int age;
char name[30];
public:
Student(int a,char *n)
{
age = a;
strcpy(name,n);
}
};
int main()
{
ofstream os1;
ifstream is1;
char name[30];
int age;
os1.open("test.txt"); //默认为文本文件
os1 << "i_love_you" << endl << 20 << endl;
os1.close();
is1.open("test.txt");
is1 >> name >> age;
is.1close();
cout << name << endl << age<< endl;
ofstream os2;
ifstream is2;
Student s1(18,"wang");
os2.open("text2.txt",ios::binary); //二进制文件
os2.write((char*)&s1,sizeof(s1));
os2.close();
is2.open("text2.txt",ios::binary);
is2.read((char*)&s1,sizeof(s1));
is2.close();
cout << s1.name << endl << s1.age << endl;
return 0;
}