C++新式转型之static_cast
⽤来强迫隐式转换(implict conversions),例如将non-const对象转为const对象,将int转为double。他也可以⽤来执⾏上述多种转换的反向转换,例如将void*转换为typed指针,将pointer-to-base转为pointer-to-derived(downcast)。但他⽆法将const转为non-
const(const_cast)
依然参考cppreference,不牵涉到类型检查,⽐dynamic_cast要好理解了。
1) If there is an implicit conversion sequence from expression to new_type, or if overload resolution for a direct
initialization of an object or reference of type new_type from expression would find at least one viable function, then static_cast(expression) returns the imaginary variable Temp initialized as if by new_type Temp(expression);, which may involve implicit conversions, a call to the constructor of new_type or a call to a user-defined conversion operator.
强制隐式转换,转换时会调⽤构造器、或者调⽤⽤户定义的转换操作符,这种⽅式,跟C风格的类型转换颇为相似。
int main()
{
int a = 65;//⼤写字母A的ASCII码
char c = static_cast<char>(a);
cout << c << endl;//输出A
return0;
}
2) If new_type is a pointer or reference to some class D and the type of expression is a pointer or reference to its non-virtual base B, static_cast performs a downcast. This downcast is ill-formed if B is ambiguous, inaccessible, or virtual base (or a base of a virtual base) of D. Such static_cast makes no runtime checks to ensure that the object’s runtime type is actually D, and may only be used safely if this precondition is guaranteed by other means, such as when implementing static polymorphism. Safe downcast may be done with dynamic_cast.
static_cast也可以执⾏downcast操作,即,将基类指针转化为派⽣类指针,但这样的操作往往是危险的,因为它不做运⾏时检查。
static_cast返回结果看似没有问题,因为基类对象往往是派⽣类对象的subobject,派⽣类有可能包含基类不包含的域:class B {};
class D : public B {};
void f(B* pb, D* pd) {
//downcast
D* pd2 = static_cast<D*>(pb);  // Not safe, D can have fields
// and methods that are not in B.
//upcast: safe
B* pb2 = static_cast<B*>(pd);  // Safe conversion, D always
// contains all of B.
}
3) If new_type is an rvalue reference type, static_cast converts the value of glvalue, class prvalue, or array prvalue
(until C++17)any lvalue (since C++17) expression to xvalue referring to the same object as the expression, or to its base sub-object (depending on new_type). If the target type is an inaccessible or ambiguous base of the type of the expression, the program is ill-formed. If the expression is a bit field lvalue, it is first converted to prvalue of the
underlying type. This type of static_cast is used to implement move semantics in std::move.
static_cast<T&&>(t)将t表达式转换成⼀个右值引⽤:
int a = 10;
int &&ra = static_cast<int&&>(a);
⽤static_cast来实现std::move中函数,直接看std::move源码
template<typename _Tp>
inline typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t)
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
关于std::move具体解析,参见:
4) If new_type is the type void (possibly cv-qualified), static_cast discards the value of expression after evaluating it.
将表达式转化为void类型,如若此做,表达式的值将被丢弃。该表达式也可以是cv-qualified
void func(const int& a)
{
return static_cast<void>(a);
}
5) If a standard conversion sequence from new_type to the type of expression exists, that does not include lvalue-to-
rvalue, array-to-pointer, function-to-pointer, null pointer, null member pointer, function pointer, (since C++17) or boolean conversion, then static_cast can perform the inverse of that implicit conversion.
static_cast可以执⾏反向的隐式转换,除了某些情况以外。⽐如static_cast可以将左值引转成右值却不能反过来。
int main()
{
int &b = static_cast<int&>(10);//error inverse of lvalue-to-rvalue
int n = 10;
int &&a = static_cast<int &&>(n);// ok lvalue-to-rvalue
}
6) If conversion of expression to new_type involves lvalue-to-rvalue, array-to-pointer, or function-to-pointer
conversion, it can be performed explicitly by static_cast.
跟5)类似,可以⽤static_cast将左值转成右值,将数组转指针,函数转指针。这些可以显⽰地⽤static_cast来表⽰
void func(int a)
{
cout << a << endl;
}
typedef void(*pFunc)(int);
int main()
{
pFunc p = static_cast<pFunc>(func);
p(10);
}
7) Scoped enumeration type can be converted to an integer or floating-point type. When the target type is cv bool, the
result is false if the original value is zero and true for all other values. For the remaining integral types, the result is the value of the enum if it can be represented by the target type and unspecified otherwise. (since C++11)
8) Integer, floating-point, or enumeration type can be converted to any complete enumeration type. The result is
unspecified (until C++17)undefined behavior (since C++17) if the value of expression, converted to the
enumeration’s underlying type, is out of range (if the underlying type is fixed, the range is the range of the type. If the underlying type is not fixed, the range is all values possible for the smallest bit field large enough to hold all
enumerators of the target enumeration)
7)和8)枚举相关,可以将枚举类型转成整型,或者将枚举类型1转成枚举类型2
9) A pointer to member of some class D can be upcast to a pointer to member of its unambiguous, accessible base
class B. This static_cast makes no checks to ensure the member actually exists in the runtime type of the pointed-to object.
指向类成员的指针可以向上转型成基类的成员指针,这⾥的pointer-to-member的⽤法如下:
#include <iostream>
using namespace std;
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
Car c1;
c1.speed = 1;      // direct access
cout << "speed is " << c1.speed << endl;
c1.*pSpeed = 2;    // access via pointer to member
cout << "speed is " << c1.speed << endl;
return0;
}
本条中的⽰例:
struct B {
int m = 0;
void hello() const {
std::cout << "Hello world, this is B!\n";
}
};
struct D : B {
void hello() const {
std::cout << "Hello world, this is D!\n";
}
};
int main()
{
// static downcast
D d;
B& br = d; // upcast via implicit conversion
// pointer to member upcast
int D::*pm = &D::m;
std::cout << br.*static_cast<int B::*>(pm) << '\n';
system("pause");
return0;
}
10) A prvalue of type pointer to void (possibly cv-qualified) can be converted to pointer to any type. If the value of the original pointer satisfies the alignment requirement of the target type, then the resulting pointer value is unchanged, otherwise it is unspecified. Conversion of any pointer to pointer to void and back to pointer to the original (or more cv-qualified) type preserves its original value.
将指针转成void*再转回去,将保持原值。
int main()
{
int a = 65;
void * pa = &a;
//void * to any type
char *pc = static_cast<char *>(pa);
cout << *pc << endl;
system("pause");
return0;
}
附cppreference上的代码
#include <vector>
#include <iostream>
struct B {
int m = 0;
void hello() const {
std::cout << "Hello world, this is B!\n";
}
};
struct D : B {
void hello() const {
std::cout << "Hello world, this is D!\n";
}
};
enum class E { ONE = 1, TWO, THREE };
enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };
int main()
typec转dp{
// 1: initializing conversion
int n = static_cast<int>(3.14);
std::cout << "n = " << n << '\n';
std::vector<int> v = static_cast<std::vector<int>>(10);
std::cout << "v.size() = " << v.size() << '\n';
// 2: static downcast
D d;
B& br = d; // upcast via implicit conversion
br.hello();
D& another_d = static_cast<D&>(br); // downcast
another_d.hello();
// 3: lvalue to xvalue
std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
std::cout << "after move, v.size() = " << v.size() << '\n';
// 4: discarded-value expression
static_cast<void>(v2.size());
// 5. inverse of implicit conversion
void* nv = &n;
int* ni = static_cast<int*>(nv);
std::cout << "*ni = " << *ni << '\n';
/
/ 6. array-to-pointer followed by upcast
D a[10];
B* dp = static_cast<B*>(a);
// 7. scoped enum to int or float
E e = E::ONE;
int one = static_cast<int>(e);
std::cout << one << '\n';
// 8. int to enum, enum to another enum
E e2 = static_cast<E>(one);
EU eu = static_cast<EU>(e2);
// 9. pointer to member upcast
int D::*pm = &D::m;
std::cout << br.*static_cast<int B::*>(pm) << '\n';
// 10. void* to any type
void* voidp = &e;
std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}
参考

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。