C++学习
七、转换函数
1、标准转换函数
//1. reinterpret_cast<new type>(expression)
将一个类型的指针转换为另一个类型的指针,它也允许从一个指针转换为整数类型
//2. const_cast<new type>(expression)
const 常量指针与普通指针间的相互转换
注:不能将非常量指针变量转换为普通变量
//3. static_cast<new type>(exprssion)
主要用于基本类型间的相互转换,和具有继承关系间的类型转换
//4. dynamic_cast<newtype>(expression)
只有类中含有虚函数才能使用 dynamic_cast ,只能在继承类对象间转换
/*dynamic_cast具有类型检查功能,比static_cast更安全*/
//1和2比较危险,后续可能会被淘汰,3和4在项目中偶尔还会遇到
例30、reinterpret_cast
首先回顾C语言的强制转换,错误案例如下
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int a;
char *p =&a;
}
错误结果如下
@ubuntu:/mnt/hgfs/ub2$ g++ cast1.cpp
cast1.cpp: In function ‘int main()’:
cast1.cpp:11:12: error: cannot convert ‘int*’ to ‘char*’ in initialization
char *p =&a;
^
@ubuntu:/mnt/hgfs/ub2$
所以需要进行强制转换
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int a;
char *p =(char *)&a;
}
以上是C语言的做法,在C++中,写成如下形式
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int a;
char *p =reinterpret_cast<char *>(&a);
}
例31、const_cast
同样的道理,在C语言中,对修饰为常量的参数取地址会出错,如下
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
const int b = 100;
int *p = &b;
}
@ubuntu:/mnt/hgfs/ub2$ g++ cast3.cpp
cast3.cpp: In function ‘int main()’:
cast3.cpp:10:14: error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]
int *p = &b;
^~
@ubuntu:/mnt/hgfs/ub2$
在C++中,有方式实现把常量的地址强转为其它的数据类型
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
const int b = 100;
int *p =const_cast<int *>(&b);
}
注意,这种做法很危险,不推荐。
例32、static_cast
然后接下来是静态方面的强制转换
#include <stdio.h>
#include <iostream>
using namespace std;
class A{
};
class B:public A{
};
int main()
{
A a;
B &p = a;
}
运行结果报错
@ubuntu:/mnt/hgfs/ub2$ g++ cast5.cpp
cast5.cpp: In function ‘int main()’:
cast5.cpp:19:10: error: invalid initialization of reference of type ‘B&’ from expression of type ‘A’
B &p = a;
^
@ubuntu:/mnt/hgfs/ub2$
在C++中可以进行强制转换,写成
#include <stdio.h>
#include <iostream>
#include <typeinfo>
using namespace std;
class A{
};
class B:public A{
};
int main()
{
A a;
B &p = static_cast<B &>(a);
}
这种做法跟const_cast 那样也是很危险,不推荐。
例33、dynamic_cast
这时候可以使用高级一点的强制转换dynamic_cast
#include <stdio.h>
#include <iostream>
using namespace std;
class A{
};
class B:public A{
};
int main()
{
A a;
B &p = dynamic_cast<B &>( a );
}
这时候错误反馈信息就很到位
@ubuntu:/mnt/hgfs/ub2$ g++ cast7.cpp
cast7.cpp: In function ‘int main()’:
cast7.cpp:18:31: error: cannot dynamic_cast ‘a’ (of type ‘class A’) to type ‘class B&’ (source type is not polymorphic)
B &p = dynamic_cast<B &>( a );
^
@ubuntu:/mnt/hgfs/ub2$
当使用到虚函数时候,就变成了警告,编译也让过,但执行就会出问题,如下所示
#include <stdio.h>
#include <iostream>
#include <typeinfo>
using namespace std;
class A{
public:
virtual void show()
{
cout<<"aaaaaaa"<<endl;
}
};
class B:public A{
public:
void show()
{
cout<<"bbbbbbbbbbbbaaaaaaa"<<endl;
}
};
int main()
{
A a;
B &p = dynamic_cast<B &>( a );
}
结果
@ubuntu:/mnt/hgfs/ub2$ g++ cast8.cpp
cast8.cpp: In function ‘int main()’:
cast8.cpp:27:31: warning: dynamic_cast of ‘A a’ to ‘class B&’ can never succeed
B &p = dynamic_cast<B &>( a );
^
@ubuntu:/mnt/hgfs/ub2$ ./a.out
terminate called after throwing an instance of 'std::bad_cast'
what(): std::bad_cast
Aborted (core dumped)
@ubuntu:/mnt/hgfs/ub2$
执行出现段错误是因为出现异常却没设法去捕获异常而造成的。这时候需要用到异常处理(之前所学内容例29),修改如下
#include <stdio.h>
#include <iostream>
#include <typeinfo>
using namespace std;
class A{
public:
virtual void show()
{
cout<<"aaaaaaa"<<endl;
}
};
class B:public A{
public:
void show()
{
cout<<"bbbbbbbbbbbbaaaaaaa"<<endl;
}
};
int main()
{
try{
A a;
B &p = dynamic_cast<B &>( a );
}
catch(bad_cast e)
{
cout<<e.what()<<endl;
}
}
这时候编译虽然警告,但最后能够成功执行
@ubuntu:/mnt/hgfs/ub2$ g++ cast9.cpp
cast9.cpp: In function ‘int main()’:
cast9.cpp:29:31: warning: dynamic_cast of ‘A a’ to ‘class B&’ can never succeed
B &p = dynamic_cast<B &>( a );
^
@ubuntu:/mnt/hgfs/ub2$ ./a.out
std::bad_cast
@ubuntu:/mnt/hgfs/ub2$
2、自定义转换函数
例34、operator
#include <stdio.h>
#include <unistd.h>
#include <iostream>
using namespace std;
class Timer{
public:
Timer()
{
hour = 0;
min = 0;
sec = 0;
}
~Timer()
{
}
void addtimer(int sec=1)
{
this->min += (this->sec+sec)/60;
this->sec = (this->sec+sec)%60;
}
void show()
{
printf("%2d:%2d:%2d\n", hour, min, sec);
}
Timer operator+(int sec)
{
Timer tem;
tem.sec = this->sec+sec;
return tem;
}
Timer operator+(Timer &x)
{
Timer tem;
tem.sec = sec+x.sec;
tem.min = min+x.min;
tem.hour = hour+x.hour;
return tem;
}
Timer operator++(int)
{
Timer tem = *this;//backup
sec++;
return tem;
}
Timer operator++()
{
sec++;
return *this;
}
bool operator==(Timer &x)
{
if(sec==x.sec && min==x.min && hour==x.hour)
return true;
return false;
}
int &operator[](int i)
{
switch(i)
{
case 0:
return hour;
case 1:
return min;
case 2:
return sec;
}
}
//转换成int就operator int()
operator int()
{
//实现相应的功能,此处是转成秒
return sec+min*60+hour*60*60;
}
friend ostream &operator<<(ostream &out, const Timer &t);
private:
int hour;
int min;
int sec;
};
ostream &operator<<(ostream &out, const Timer &t)
{
out << "hour: "<<t.hour << " min: "<<t.min<<" sec: "<<t.sec<< endl;
}
int main()
{
Timer t;
t.addtimer(3);
int sec = t; //强转为整形类型
cout<< sec <<endl;
}
3、隐式构造
例35、explicit
#include <iostream>
using namespace std;
class mempool{
public:
//构造函数
//mempool(int size){
//explicit隐式构造
explicit mempool(int size){
data = new char[size];
cout<< "cccccccccc" <<endl;
}
~mempool()
{
delete [] data;
}
private:
char *data;
};
int main()
{
//调用构造函数
// mempool a(100);
//在平常构造函数时无法去识别下式子是赋值100还是表示a大小为100,使用explicit隐式构造可以报错区分
mempool a = 100;
}
错误提示
@ubuntu:/mnt/hgfs/ub2$ g++ mempool.cpp
mempool.cpp: In function ‘int main()’:
mempool.cpp:28:14: error: conversion from ‘int’ to non-scalar type ‘mempool’ requested
mempool a = 100;
^~~
@ubuntu:/mnt/hgfs/ub2$