C++类型转化表达式小结

const_cast

根据http://www.cplusplus.com的说法,const_cast用于对象指针或引用的const的添加和删除操作

例子如下:

// const_cast
#include <iostream>
using namespace std;

void print (char * str)
{
  cout << str << '\n';
}

int main () {
  const char * c = "sample text";
  print ( const_cast<char *> (c) );
  return 0;
}

输出为

sample text

http://en.cppreference.com上有更多的信息

函数指针和成员函数指针不可用于const_cast

const_cast可以使实际指代const对象的到非const类型的引用或指针,但是通过非const访问路径修改const对象则是未定义行为。

更详细的例子

#include <iostream>

struct type {
    type() :i(3) {}
    void m1(int v) const {
        // this->i = v;                 // 编译错误:这是指向 const 的指针
        const_cast<type*>(this)->i = v; // 只要对象不是 const 就 OK
    }
    int i;
};

int main() 
{
    int i = 3;                    // i 不声明为 const
    const int& cref_i = i; 
    const_cast<int&>(cref_i) = 4; // OK :修改 i
    std::cout << "i = " << i << '\n';

    type t; // note, if this is const type t;, then t.m1(4); is UB
    t.m1(4);
    std::cout << "type::i = " << t.i << '\n';

    const int j = 3; // j 声明为 const
    int* pj = const_cast<int*>(&j);
    // *pj = 4;         // 未定义行为!

    void (type::*mfp)(int) const = &type::m1; // 指向成员函数指针
//  const_cast<void(type::*)(int)>(mfp); // 编译错误: const_cast 对函数指针不起作用
}

输出

i = 4
type::i = 4

reinterpret_cast

reinterpret_cast可以在任意类型指针进行转换,哪怕是不相关的类型。

还可用于指针或引用与整型的相互转化,不单是int,还包括short、long等整数类型。

原因在于reinterpret_cast是“simple binary copy”,cplusplus的原话是“The operation result is a simple binary copy of the value from one pointer to the other. All pointer conversions are allowed: neither the content pointed nor the pointer type itself is checked.”

经过测试,整型与char *之间的转化也可以正常进行

cppreference的例子

#include <cstdint>
#include <cassert>
#include <iostream>
int f() { return 42; }
int main()
{
    int i = 7;

    // 指针到整数并转回
    uintptr_t v1 = reinterpret_cast<uintptr_t>(&i); // static_cast 为错误
    std::cout << "The value of &i is 0x" << std::hex << v1 << '\n';
    int* p1 = reinterpret_cast<int*>(v1);
    assert(p1 == &i);

    // 到另一函数指针并转回
    void(*fp1)() = reinterpret_cast<void(*)()>(f);
    // fp1(); 未定义行为
    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
    std::cout << std::dec << fp2() << '\n'; // 安全

    // 通过指针的类型别名使用
    char* p2 = reinterpret_cast<char*>(&i);
    if(p2[0] == '\x7')
        std::cout << "This system is little-endian\n";
    else
        std::cout << "This system is big-endian\n";

    // 通过引用的类型别名使用
    reinterpret_cast<unsigned int&>(i) = 42;
    std::cout << i << '\n';

    const int &const_iref = i;
    // int &iref = reinterpret_cast<int&>(const_iref); // 编译错误——不能去除 const
    // 必须用 const_cast 代替: int &iref = const_cast<int&>(const_iref);
}

输出

The value of &i is 0x7fff352c3580
42
This system is little-endian
42

static_cast

static_cast可以在有联系的类型之间进行指针转换(between pointers to related classes),不但包括派生类转换基类,也包括基类转换派生类。

static_cast还可以完成以下两种

Convert from void* to any pointer type.可以有void *到任何类型

Convert integers, floating-point values and enum types to enum types.由整数、浮点、枚举值到枚举值

此外

Explicitly call a single-argument constructor or a conversion operator. 调用单一参数的构造函数或转换的重载符号

Convert to rvalue references. (由左值)转化成右值的引用

Convert enum class values into integers or floating-point values. 枚举类转化为整数、浮点数

Convert any type to void, evaluating and discarding the value. 任意类型到void,求值后舍弃该值

示例

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

int main()
{
    // 1: 初始化转换
    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: 静态向下转型
    D d;
    B& br = d; // 通过隐式转换向上转型
    br.hello();
    D& another_d = static_cast<D&>(br); // 向下转型
    another_d.hello();

    // 3: 左值到亡值
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
    std::cout << "after move, v.size() = " << v.size() << '\n';

    // 4: 弃值表达式
    static_cast<void>(v2.size());

    // 5. 隐式转换的逆
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "*ni = " << *ni << '\n';

    // 6. 数组到指针后随向上转型
    D a[10];
    B* dp = static_cast<B*>(a);

    // 7. 有作用域枚举到 int 或 float
    E e = E::ONE;
    int one = static_cast<int>(e);
    std::cout << one << '\n';

    // 8. int 到枚举,枚举到另一枚举
    E e2 = static_cast<E>(one);
    EU eu = static_cast<EU>(e2);

    // 9. 指向成员指针向上转型
    int D::*pm = &D::m;
    std::cout << br.*static_cast<int B::*>(pm) << '\n';

    // 10. void* 到任何类型
    void* voidp = &e;
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

输出

n = 3
v.size() = 10
Hello world, this is B!
Hello world, this is D!
after move, v.size() = 0
*ni = 3
1
0

dynamic_cast

dynamic_cast只能用于类或者void *的指针、引用转换,同时必须为多态以使用运行时检查的

例子

#include <iostream>

struct V {
    virtual void f() {};  // 必须为多态以使用运行时检查的 dynamic_cast
};
struct A : virtual V {};
struct B : virtual V {
  B(V* v, A* a) {
    // 构造中转型(见后述 D 的构造函数中的调用)
    dynamic_cast<B*>(v); // 良好定义: v 有类型 V* , B 的 V 基类,产生 B*
    dynamic_cast<B*>(a); // 未定义行为: a 有类型 A* , A 非 B 的基类
  }
};
struct D : A, B {
    D() : B((A*)this, this) { }
};

struct Base {
    virtual ~Base() {}
};

struct Derived: Base {
    virtual void name() {}
};

int main()
{
    D d; // 最终导出类
    A& a = d; // 向上转型,可以用 dynamic_cast ,但不必须
    D& new_d = dynamic_cast<D&>(a); // 向下转型
    B& new_b = dynamic_cast<B&>(a); // 侧向转型


    Base* b1 = new Base;
    if(Derived* d = dynamic_cast<Derived*>(b1))
    {
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // 调用安全
    }

    Base* b2 = new Derived;
    if(Derived* d = dynamic_cast<Derived*>(b2))
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // 调用安全
    }

    delete b1;
    delete b2;
}

输出

downcast from b2 to d successful

dynamic_cast与static_cast在类转换上的不同在于,dynamic_cast会确保转化成功,在转化不成功时会设置为NULL,如上例中

Derived* d = dynamic_cast<Derived*>(b1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值