logo
Published on

都2023年了,还在用C风格的强转吗?

都2023年了,还在用C风格的强转吗?

C风格

int a = 1;
float b = (float)a; // 普通的强转
float c = float(a); // 函数风格的强转

上面的例子为C风格的强制类型转换----简单粗暴!直接使用"()"括起来即可。 没有类型检查,直接硬转,转的对错全凭程序员的“造化”了。

在C++中,强制类型转换分为四种,当然在C++中仍然支持C风格的强转,但是C++保留C风格的强转仅仅是为了语言兼容性的考虑。 因此,都2023年了,还在用C风格的强转吗?

C++中的四种强制类型转换分别用于不同的目的,这四种强制类型转换,每一种都对应着一个名字, C++中这么分是为了提供更丰富的含义和功能以及更好的类型检查机制,方便代码的书写与维护。 因此,都2023年了,还在用C风格的强转吗?

下面我们来认识一下这四种强制类型转换,有时也称它们为强制类型转换运算符或者强制类型转换操作符。

static_cast

称为静态转换,可以理解为正常转换,在编译期间就会进行类型转换的检查, 通常用于相关类型之间的互相转换,主要用于数值类型之间的相互转换。

enum class Week {
    Mondy = 1,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
};

int a = 1;
float b = static_cast<float>(a);
Week day = static_cast<Week>(a);

reinterpret_cast

称为重新解释转换,也会在编译期间进行类型转换的检查,但是这是一个非常自由且奇怪的类型转换, 使用此转换会将数据以二进制存在的形式进行重新解释。通常用于无关类型的互相转换,也就等于乱转、瞎转、自由转、爱咋转咋转。 使用最多的情况为与void*进行相互转换。

class Bag {
public:
    Bag() = default;
    ~Bag() = default;

    void Set(int thing) {
        thing_ = thing;
    }
    int Get() {
        return thing_;
    }

private:
    int thing_ = 0;
};

void Transfer(void *trans) {
    Bag *bag = reinterpret_cast<Bag*>(trans);
    bag->Set(9);
}

int main() {
    Bag *bag = new Bag();
    Transfer(reinterpret_cast<void*>(bag));
    std::cout << bag->Get() << std::endl;
    delete bag;
    return 0;
}

dynamic_cast

称为动态转换,此强制类型转换不会在编译期间进行类型检查,而是在运行时进行类型的识别与检查,通常用于父类型向子类型转换。 dynamic_cast能将父类的指针或者引用安全的转换为子类的指针或者引用,其实是在帮助开发者做安全检查, 不过使用dynamic_cast有个一前提条件,那就是父类中必需至少又一个虚函数! dynamic_cast会在运行时做类型检查,因此类型检查是要付出代价的,不过与安全性相比,这个代价是非常值得的。

class Base {
public:
    Base() = default;
    virtual ~Base() = default;

    virtual void Play() = 0;
};

class Player : public Base {
public:
    Player() = default;
    ~Player() = default;

    void Play() override {
        std::cout << "play" << std::endl;
    }
};

class Test {
public:
    Test() = default;
    ~Test() = default;
    void Play() {
        std::cout << "test play" << std::endl;
    }
};

int main() {
    Base *base = new Player();
    Player *player = dynamic_cast<Player*>(base);
    if (player != nullptr) {
        player->Play();
    }
    Test *test = dynamic_cast<Test*>(base);
    if (test != nullptr) { // test is not subclass of Base, so test must is nullptr.
        test->Play();
    }
    delete base;
    return 0;
}

const_cast

称为常量转换,const_cast会在编译期间进行类型转换的检查,这个类型转换只能做一件事,不过也就只有const_cast能够做这件事, 那就是将常量指针或者引用转换成非常量指针或者引用,需要注意的是,const_cast只能转换指针或者引用类型,不能转换普通数值类型。 当你的代码里出现了const_cast,那说明你要重新设计一下你的代码了。

class Test {
public:
    Test() = default;
    ~Test() = default;

    int value = 0;
};

void Change(const Test &test) {
    Test &change = const_cast<Test&>(test);
    change.value = 1;
}

int main() {
    Test test;
    std::cout << test.value << std::endl;
    Change(test);
    std::cout << test.value << std::endl;
    return 0;
}