c++中的强制类型转换,及基本文件读写(对比c语言)

这个标题有点乱,只是刚好想把这两点整理一下,就放在一起了!

类型转换

c++除了能使用c语言的强制类型转换外,还新增了四种强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast。语法为:


static_cast<new_type>      (expression)

dynamic_cast<new_type>     (expression) 

const_cast<new_type>       (expression) 

reinterpret_cast<new_type> (expression)

注:new_type为目标数据类型,expression为原始数据类型变量或者表达式。
 

 

const_cast

用于修改类型的const或volatile属性。 除了const 或volatile修饰之外, new_type和expression的类型是一样的。


const char *a;

char *b = const_cast<char*>(a);//去掉const指针const属性

	

char *a;

const char *b = const_cast<const char*>(a);//给指针加上const属性

 

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属性

static_cast  

相当于传统的C语言里的强制转换,该运算符把expression转换为new_type类型,用来强迫隐式转换,例如non-const对象转为const对象,编译时检查,用于非多态的转换,可以转换指针及其他,但没有运行时类型检查来保证转换的安全性。

  1. 基本数据类型之间互转。如:float转成int、int转成unsigned int等

  2. 把指针转换成void类型指针 。如:float*转成void*、Bean*转成void*、函数指针转成void*等

  3. 子类指针/引用与 父类指针/引用 转换。

  4. 注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。

    
    class Parent {
    
    public:
    
    	void test() {
    
    		cout << "p" << endl;
    
    	}
    
    };
    
    class Child :public Parent{
    
    public:
    
    	 void test() {
    
    		cout << "c" << endl;
    
    	}
    
    };
    
    Parent  *p = new Parent;
    
    Child  *c = static_cast<Child*>(p);
    
    //输出c
    
    c->test();
    
     
    
    //Parent test加上 virtual 输出 p
    
     
    
    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属性
    

     

 

reinterpret_cast  

 new_type必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针(new_type)转换成一个整数,也可以把一个整数转换成一个指针(new_type)(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。

错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用reinterpret_cast方式。


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

 

 

    float i = 10;

    //&i float指针,指向一个地址,转换为int类型,j就是这个地址

    int j = reinterpret_cast<int>(&i);

    cout  << hex << &i << endl;

    cout  << hex  << j << endl;

 

    return 0;

}

 

 

他们的区别 

static_cast和reinterpret_cast的区别主要在于多重继承,比如:


class A {

    public:

    int m_a;

};

 

class B {

    public:

    int m_b;

};

 

class C : public A, public B {};

 

C c;

printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));
 

前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。 

dynamic_cast

 
  1. 运算形式如下:

  2. dynamic_cast<type*>(e)

  3. dynamic_cast<type&>(e)

  4. 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也可以是一个空指针,结果是所需类型的空指针。 

在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。

class A
{
public:
	virtual void test(void) = 0;
};
class D
{
public:
	virtual void test(void) = 0;
};

class B : public A
{
public:
	void test(void)
	{
		cout << "--------------" << endl;
	}
};

class C : public D
{
public:
	void test(void)
	{
		cout << "++++++++++++++++" << endl;
	}
};
 

 

Parent  *p = new Child;

Child  *c = dynamic_cast<Child*>(p);

if (c) {

	cout << "转换成功" << endl;

}
 

值得注意的是,我们可以在一个操作中同时完成类型转换和条件检查两项任务,如下代码:


//指针类型

if(Child  *c = dynamic_cast<Child*>(p);){

  //使用c指向的Child对象  

}

else{

  //使用p指向的Parent对象  

}

 

//引用类型

void f(const Parent &b){

 try{

   const Child &d = dynamic_cast<const Parent &>(b);  

   //使用b引用的Child 对象

 }

 catch(std::bad_cast){

   //处理类型转换失败的情况

 }

}

注:因为不存在所谓空引用,所以引用类型的dynamic_cast转换与指针类型不同,在引用转换失败时,会抛出std::bad_cast异常,该异常定义在头文件typeinfo中。 

char*与int转换

 

//char* 转int float

int i = atoi("1");

float f = atof("1.1f");

cout << i << endl;

cout << f << endl;

	

//int 转 char*

char c[10];

//10进制

itoa(100, c,10);

cout << c << endl;

 

//int 转 char*

char c1[10];

sprintf(c1, "%d", 100);

cout << c1 << endl;

文件读写

主要介绍<fstream>相关类以及<stdio.h>fopen

ifstream

ifstream 是用来操作文件的输入流类。文件流通过构造函数或者通过调用open函数来完成与文件的绑定。

打开文件

  1. 通过构造函数
    std::ifstream ifs ("test.txt", std::ifstream::in);

  2. 通过open()函数

std::ifstream ifs;
ifs.open("test.txt",std::ifstream::in);

一个一个字符读取 std::istream::get

可以一个一个读取并返回读取到的值,或者读取连续(n-1)个字符并保存在字符数组中。这种读取方式不怎么适用。

void getbychar(){
    std::ifstream ifs("test.txt", std::ifstream::in);
    char str[256];
    ifs.get(str, 10); // 从ifs中读取10-1=9个字符,保存在str内
    std::cout << "str: " << str << std::endl;

    char c = ifs.get();  // 一次读取一个字符
    while (ifs.good()) {
        std::cout << c;
        c = ifs.get();
    }
    ifs.close();
}

一行一行读取

istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );

一次读取一行,从流中读取字符并将其保存于c字符串中,知道遇到界定符delim(’\n’)或者已经向s写入了n个字符。

需要注意的是n要大于文件中最长的一行的字符数。如果此函数因为已经读取了n个字符而停止但是却没有找到界定符,那么failbit将会被设置。

void getbyline(){
    std::ifstream ifs("test.txt", std::ifstream::in);
    char str[256];
    while(ifs.good()){ // 如果想测试只读取一行中一些字符,判断内可改为 !ifs.eof() && !ifs.fail()
        ifs.getline(str,256);
        std::cout << str << std::endl;
    }   
}

>>操作符就和我们常用的cin>>一样的用法

void getlikecin(){
    std::ifstream ifs("test.txt");
    std::string str;
    int num;
    ifs >> num;
    std::cout << num << std::endl;
    while(ifs.good()){
        ifs >> str;
        std::cout << str << std::endl;
    }   
    ifs.close();
}

如果你运行了上面这个程序,你会发现,最后一个字符串会被输出两次!这是因为ifs完成最后一次读取后不会立即设置eof状态,所以程序会再进行一轮循环,在这轮循环ifs才会设置eof状态。结果就是最后一次读取的内容被输出了两次。

while循环可改为:

while(ifs>>str){
std::cout << str << std::endl;
}
  •  

或者

while(ifs.good()){
    if(ifs >> str)
        std::cout << str << std::endl;
} 

stdio.h

C语言类型的文件读写,只需#include <stdio.h>即可。

打开文件
FILE * fopen ( const char * filename, const char * mode );
mode 可取

modedescription
“r”读:打开一个文件进行读取操作。文件必须已经存在
“w”写:创建一个空文件进行写操作。若同名文件已经存在,则会清空原文件的内容。
“a”附加:打开一个文件,在文件末尾进行写操作。若文件不存在,则会创建新文件。
“+”更新:需要和上述r/w/a进行结合,结合后文件将会变成即可读也可写。
“b”二进制读写:需要和上述模式进行结合成”rb”,”wb”,”ab”
“x”避免重写已有文件:新C标准但不是C++的一部分,通过和”w”结合成”wx”,”wbx”等,若同名文件已存在,则会迫使此函数失败。
FILE *pFile;
pFile = fopen("test.txt","r");

读取文件
int fscanf ( FILE * stream, const char * format, ... );
根据format声明的格式从stram中读取数据并保存在后面的参数中。这种读取适用于文件格式固定,每个字段类型确定的情况下进行读取操作。

#include <stdio.h>

int main ()
{
  char str [80];
  float f;
  FILE * pFile;

  pFile = fopen ("myfile.txt","w+");
  fprintf (pFile, "%f %s", 3.1416, "PI"); // 先向文件写入 3.1416 PI
  rewind (pFile); // 设置pFile的位置指示回到文件开头
  fscanf (pFile, "%f", &f);  // 读取一个浮点数
  fscanf (pFile, "%s", str);  // 读取一个字符串
  fclose (pFile);
  printf ("I have read: %f and %s \n",f,str);
  return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值