C++中的4种运算符转化以及它们的不同点

1、const_cast

const_cast用来帮助调用那些应该使用却没有使用const关键字的函数。即在特殊情况下降限制为const成员函数的const定义解除,使其能更改特定属性

代码示例:

#include <iostream>
 
struct type {
    
    
    int i;
 
    type(): i(3) {
    
    }
 
    void f(int v) const {
    
    
        // this->i = v;                 // compile error: this is a pointer to const
        const_cast<type*>(this)->i = v; // OK as long as the type object isn't const
    }
};
 
int main() 
{
    
    
    int i = 3;                 // i is not declared const
    const int& rci = i; 
    const_cast<int&>(rci) = 4; // OK: modifies i
    std::cout << "i = " << i << '\n';
 
    type t; // if this was const type t, then t.f(4) would be undefined behavior
    t.f(4);
    std::cout << "type::i = " << t.i << '\n';
 
    const int j = 3; // j is declared const
    int* pj = const_cast<int*>(&j);
    // *pj = 4;      // undefined behavior
 
    void (type::* pmf)(int) const = &type::f; // pointer to member function
    // const_cast<void(type::*)(int)>(pmf);   // compile error: const_cast does
                                              // not work on function pointers
}

输出:

i = 4
type::i = 4

2、dynamic_cast

如果启动了支持运行时间类型信息(RTTI),dynamic_cast可以有助于判断在运行时所指向对象的确切信息。它与typeid运算符有关。可以将一个基类的指针指向许多不同的子类型(派生类),然后将被转型为基础类的对象还原成原来的类。不过,限于对象指针的类型转换,而非对象变量。

代码示例:

#include <iostream>
 
struct V {
    
    
    virtual void f() {
    
    }  // must be polymorphic to use runtime-checked dynamic_cast
};
struct A : virtual V {
    
    };
struct B : virtual V {
    
    
  B(V* v, A* a) {
    
    
    // casts during construction (see the call in the constructor of D below)
    dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
    dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B
  }
};
struct D : A, B {
    
    
    D() : B(static_cast<A*>(this), this) {
    
     }
};
 
struct Base {
    
    
    virtual ~Base() {
    
    }
};
 
struct Derived: Base {
    
    
    virtual void name() {
    
    }
};
 
int main()
{
    
    
    D d; // the most derived object
    A& a = d; // upcast, dynamic_cast may be used, but unnecessary
    D& new_d = dynamic_cast<D&>(a); // downcast
    B& new_b = dynamic_cast<B&>(a); // sidecast
 
 
    Base* b1 = new Base;
    if(Derived* d = dynamic_cast<Derived*>(b1))
    {
    
    
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // safe to call
    }
 
    Base* b2 = new Derived;
    if(Derived* d = dynamic_cast<Derived*>(b2))
    {
    
    
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // safe to call
    }
 
    delete b1;
    delete b2;
}

输出:

downcast from b2 to d successful

3、reinterpret_cast

用于将一个指针转换成其他类型的指针,新类型的指针与旧指针可以毫不相关。通常用于某些非标准的指针数据类型转换,例如将void转换为char。它也可以用在指针和整型数之间的类型转换上。注意:它存在潜在的危险,除非有使用它的充分理由,否则就不要使用它。例如,它能够给将一个int类型的指针转换为float类型的指针,但是这样会造成数据无法被准确的读取。

代码示例:

#include <cstdint>
#include <cassert>
#include <iostream>
int f() {
    
     return 42; }
int main()
{
    
    
    int i = 7;
 
    // pointer to integer and back
    std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // static_cast is an error
    std::cout << "The value of &i is 0x" << std::hex << v1 << '\n';
    int* p1 = reinterpret_cast<int*>(v1);
    assert(p1 == &i);
 
    // pointer to function to another and back
    void(*fp1)() = reinterpret_cast<void(*)()>(f);
    // fp1(); undefined behavior
    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
    std::cout << std::dec << fp2() << '\n'; // safe
 
    // type aliasing through pointer
    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";
 
    // type aliasing through reference
    reinterpret_cast<unsigned int&>(i) = 42;
    std::cout << i << '\n';
 
    [[maybe_unused]] const int &const_iref = i;
    //int &iref = reinterpret_cast<int&>(const_iref); //compiler error - can't get rid of const
    //Must use const_cast instead:  int &iref = const_cast<int&>(const_iref);
}

可能的输出:

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

4、static_cast

static_cast能够在相关的对象和指针类型之间进行类型转换。有关的类之间必须通过继承、构造函数或者转换函数发生联系。static_cast操作符还能在数字(原始的)类型之间进行类型转换。通常情况下,static_cast操作符大多数用于将数域宽度较大的类型转换为较小的类型。当转换的类型是原始数据类型时,这种操作可以有效地禁止编译器发出警告。

代码示例:

#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: 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);
}

输出:

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

参考:
1、《C和C++程序员面试秘籍》
2、 https://en.cppreference.com/

谢谢阅读

猜你喜欢

转载自blog.csdn.net/weixin_43869898/article/details/111240028