C++ 隐式和显式初始化,类型转换
C++ 隐式和显式初始化,类型转换
1. 隐式和显式初始化
1.1 C++隐式初始化
int ival(1024);
string hello("Hello world.")
1.2 C++显式初始化
int ival = 1024;
string hello = "Hello world."
*PS: 注意这里"=" 语法是拷贝构造函数而不是赋值运算!
因为一个新对象被定义一定要有一个构造函数而不不是一个赋值操作
string hello;
hello = "Hello world"; <- 这里hello 已经被定义了,才是赋值操作.
2.隐式和显式类型转换.
2.1
C++隐式转换发生在四种情况下
* 在混合类型的算术表达式中
int ival = 3;
double dval = 3.1415
ival + dval; //ival 被提升为double 类型:3.0
* 用一种类型的表达式赋值
int *pi = NULL; // NULL(0)被转换成了int* 类型的空指针值
* 用一个表达式传递给一个函数调用
extern double sqrt(double);
sqrt(2); //2被提升为double类型: 2.0
* 从一个函数返回一个表达式
double difference(int ival1, int ival2)
{
return ival1 - ival2; //返回值被提升为double 类型.
}
2.2
C++内建类型(char,int,short,double etc.)对像之间默认含有隐式转换
2.3
C++用户定义类对象之间可以含有隐式转换.
void dosomething(A aObject);
class A {
public:
A(int x = 0);
}
dosomething(20); // Ok 隐式转换
2.4
C++显式转换包含四种转换
static_cast : 编译期的转化,不能转换掉exdivssion的const、volitale、或者__unaligned属性
*所有内建类型对象之间的隐式转换都可用static_cast.
*把空指针转换成目标类型的空指针用static_cast。
*把任何类型的表达式转换成void类型用static_cast。
*类层次间的上行转换和下行转换也可以用static_cast,但下行转换即当把基类指针或引用转换成子类表示时,由于没有动态类型检查,所以是不安全的.反之是安全的.
dynamic_cast : 运行期的转换,类层次间的上行转换和下行转换
* dynamic_cast具有类型检查的功能,下行转换的效果跟static_cast是一样的,但下行转换比static_cast更安全。
* dynamic_cast还支持交叉转换,两个类如果有共同的祖先,他们的指针就可以用dynamic_cast.
const_cast : 编译期的转化,类型中的常量
reinterpret_cast : 任何指针都可以转换成其它类型的指针,可用于如char* 到 int*,或者One_class* 到 Unrelated_class* 等的转换,因此可能是不安全的。
2.5
C++内建类型指针之间不含有隐式转换(void * 除外),需要显式转换。
int ival = 0;
char* pc = NULL;
int* pi = NULL;
void* pv = NULL;
const char* pcc = "Hello world";
const int* pci = &ival;
const void* pcv = NULL;
pc = pi; //错误,没有标准的隐式转换.
pc = reinterpret_cast<char*>(pi); //必须使用reinterpret_cast 在位模式层次的显式转换
pc = pv; //错误,没有标准的隐式转换.
pc = static_cast<char*>(pv); //static_cast显式转换
pc = pcc; //错误,没有标准的隐式转换.
pc = const_cast<char*>(pcc); //const_cast显式转换
pc = pcv; //错误,没有标准的隐式转换.
pc = static_cast<char*>(const_cast<void*>(pcv)); //先const_cast 后 static_cast.
pv = pc; // OK; 隐式转换到void*
pv = pi; // OK; 隐式转换到void*
pv = pcc; //错误,没有标准的隐式转换.
pv = const_cast<char*>(pcc); //OK, const_cast显式转换,并且char* 隐式转换到void*
pv = pcv;//错误,没有标准的隐式转换.
pv = const_cast<void*>pcv;//OK, const_cast显式转换.
pcc = pc; // OK; 隐式转换到const char*
pcc = pi; // 错误,没有标准的隐式转换.
pcc = reinterpret_cast<char*>(pi); //必须使用reinterpret_cast 在位模式层次的显式转换.
pcc = pv; // 错误,没有标准的隐式转换.
pcc = static_cast<char*>(pv); //static_cast显式转换
pcc = pci;// 错误,没有标准的隐式转换.
pcc = reinterpret_cast<char*>pci; //必须使用reinterpret_cast 在位模式层次的显式转换.
pcc = pcv;//错误,没有标准的隐式转换.
pcc = static_cast<const char*>(pcv); //static_cast显式转换.
pcv = pv; // OK; 隐式转换到const void*
pcv = pc; // OK; 隐式转换到const void*
pcv = pi; // OK; 隐式转换到const void*
pcv = pcc;// OK; 隐式转换到const void*
2.6
显式转换可以消除不必要的提升.
double dval;
int ival;
ival += dval;
这段赋值,首先将ival提升到double型,然后与dval相加,得到结果再截取成int.
通过显式转换,消除ival 从int型到double型的不必要提升.
ival += static_cast<int>(dval);
2.7
C++用户定义对象之间可以禁止隐式转换。
void dosomething(A aObject);
class A {
public:
explicit A(int x = 0);
}
dosomething(20); // ERROR 隐式转换被禁止.
dosomething(static_cast<A>(20)); // OK 显式转换.
被声明为explicit 的构造函数通常比non-explicit更好.
2.8
综合起来说C++ 中应该尽量不使用转换,尽量使用显式转换来代替隐式转换.
尽量不用reinterper_cast 显式转换.