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
    return 0;
}

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(pb);   // Not safe, D can have fields  
                                   // and methods that are not in B.  

  //upcast: safe
   B* pb2 = static_cast(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表达式转换成一个右值引用:

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具体解析,参见:C++ std::move和std::forward源码分析


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(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 
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;
    return 0;
}

本条中的示例:

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");
    return 0;
}

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");
    return 0;
}

附cppreference上的代码

#include 
#include 

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 EU { ONE = 1, TWO, THREE };

int main()
{
    // 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(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(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(one);
    EU eu = static_cast(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);
}

参考

http://en.cppreference.com/w/cpp/language/static_cast
https://msdn.microsoft.com/zh-cn/library/c36yw7x9.aspx
引用折叠

你可能感兴趣的:(C/C++)