玩命加载中 . . .

4.11-类型转换


static_cast

🔷允许执行任意的隐式转换和相反转换

🔷没有运行时类型检查来保证转换的安全性

🔷进行上行转换(把派生类的指针或引用转换成基类表示)是安全的

🔷进行下行转换(把基类的指针或引用转换为派生类表示),由于没有动态类型检查,所以是不安全的

class Base {
public:
    Base(): b(1) {}
    virtual void fun() {}
    int b;
};

class Derived: public Base {
public:
    Derived(): d(2) {}
    int d;
};

int main() {
    Base *b1 = new Derived; // 基类指针指向派生类对象
    Base *b2 = new Base;    // 基类指针指向基类对象
    Derived *d1 = static_cast<Derived*>(b1);    // 下行转换,安全
    cout << d1->d << endl;  // 2
    Derived *d2 = static_cast<Derived*>(b2);    // 下行转换,不安全
    cout << d2->d << endl;  // 0,基类没有d这个成员,也没报错
    return 0;
}

使用:

  1. 用于基本数据类型之间的转换,如把int转换成char
  2. 把任何类型的表达式转换成void类型

任何具有明确定义的类型转换,只要不包括底层const,都可以使用static_cast

int i = 10, j = 100;
double slope = static_cast<double>(j) / i;

使用static_castvoid*指针转换回原来的类型。

// 任何非常量对象的地址都能存入void*
double d = 3.14;
void *p = &d;
double *dp = static_cast<double*>(p);

dynamic_cast

在进行下行转换时,dynamic_cast具有类型检查(信息在虚函数中)的功能,比static_cast更安全。转换后必须是类的指针、引用或者void*,基类要有虚函数,可以交叉转换

dynamic_cast本身只能用于存在虚函数的父子关系的强制类型转换;对于指针,转换失败则返回nullptr,对于引用,转换失败会抛出异常

基类没有虚函数,说明没有让基类指针指向子类的必要(不具有多态性),所以使用dynamic_cast会报错

class A {};
class B : public A {};
int main() {
    A *pA = new A;
    B *pB = dynamic_cast<B*>(pA); // error: cannot dynamic_cast 'pA' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
    return 0;
}

下行转换要转换成功,要求基类指针指向的派生类对象,这样才能把基类指针转换成派生类指针

class Base {
public:
    Base(): b(1) {}
    virtual void fun() {}    // 要有虚函数
    int b;
};

class Derived: public Base {
public:
    Derived(): d(2) {}
    int d;
};

int main() {
    Base *b1 = new Derived; // 基类指针指向派生类对象
    Base *b2 = new Base;    // 基类指针指向基类对象
    Derived *d3 = dynamic_cast<Derived*>(b1);   // 下行转换成功,等价于static_cast
    cout << d3->d << endl;  // 2 转换成功
    Derived *d4 = dynamic_cast<Derived*>(b2);   // 下行转换不成功,返回nullptr
    if (d4 == nullptr) {
        cout << "d4 is nullptr" << endl;    // d4 is nullptr 转换失败
    } else {
        cout << d4->d << endl;
    }

    return 0;
}

const_cast

常指针转换为非常指针,并且仍然指向原来的对象。常引用被转换为非常引用,并且仍然指向原来的对象。去掉类型的constvolatile属性

int n = 10;
const int *p2 = &n; // 指向常量的指针
int *p3 = const_cast<int*>(p2); // 转换为普通指针
*p3 = 100;  // 可以修改指向的对象
cout << *p2 << ", " << *p3 << endl; // 100, 100

reinterpret_cast

  • 用于位的简单重新解释
  • 允许将任何指针转换为其他指针类型
  • 允许将任何整数类型转换为指针类型以及反向转换
  • 滥用reinterpret_cast可能带来风险,除非所需转换本身是低级别的,否则应使用其他强制转换
int n = 97;
int *p = &n;
char *c1 = reinterpret_cast<char*>(p);   // int*指针转换为char*指针
char *c2 = (char*)p;
cout << *c1 << ", " << *c2 << endl;  // a, a

类型转换不做检查

class A {
public:
    int a;
};

class B {
public:
    char b;
};

int main() {
    A *pa = new A;
    pa->a = 0x12345678;
    B *pb = reinterpret_cast<B*>(pa);
    cout << pb->b << endl;  // 小端存储,对应0x78,也就是120,即'x'
    return 0;
}

文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录