首页 > 其他分享 >static_cast, dynamic_cast与reinterpret_cast的区别

static_cast, dynamic_cast与reinterpret_cast的区别

时间:2024-02-02 21:01:21浏览次数:23  
标签:Woman dynamic pWoman cast static howOld 指针

在C++中,static_cast, dynamic_castreinterpret_cast都可用于类型转换,它们在具体使用时有什么区别?此外,更为重要的是,为什么不推荐使用强制类型转换?

1. static_cast

static_cast是静态类型转换,“静态”一词是指在程序编译期间完成类型的转换,这应该是平时使用最多的类型转换。例如,将一个浮点数转化为整数,就可以使用static_cast:

float a = 10.5;
int b = static_cast<int>(a);

2. dynamic_cast

dynamic_cast是动态类型转换,“动态”一词是指在程序运行期间完成类型的转换,如果转换失败且转换的目标类型是指针,则返回一个空指针;如果转换失败且转换的目标类型是引用,则会抛出std::bad_cast异常。

动态类型转换与C++的多态有关,常用于基类与子类指针或引用的转换,且基类中至少要有一个虚函数。例如:

class Base { 
    virtual void f();
};

class Derived : public Base {
    void f() override;
};


Derived* ptr = new Derived();
Base* ptrBase = dynamic_cast<Base*>(ptr);

当然,这个例子并没有很好地展示出dynamic_cast的功能,文章最后有一个例子展示了需要使用dynamic_cast的情形。

3. reinterpret_cast

reinterpret的意思是“重新解释”,它不会改变任何底层的数据,而是告诉编译器应该把当前数据当作哪种类型。例如,有一个指向整数的指针,你可以使用reinterpret_cast将其转化为一个指向浮点数的指针:

int a = 10;
float* ptrB = reinterpret_cast<float*>(&a);

转换完成后,没有任何数据被改变,只是ptrB之后会被编译器当作一个指向浮点数的指针,这种感觉有点像C语言中的union. 可以看出,这种转换更偏向底层,使用时一定要小心。

当然,既然存在这一转换,就一定有它的用处。例如,在OpenGL中,可以将一个指针传递到窗口:

class App {
    ...
};

App* app1 = new App();
glfwSetWindowUserPointer(app1);

函数glfwSetWindowUserPointer的参数是void*类型的指针,可以通过函数glfwGetWindowUserPointer获取这个指针,获取到的指针类型也是void*,但我们已经知道它必然是一个App*类型的指针,此时可以使用reinterpret_cast将其转换回来:

void* ptr = glfwGetWindowUserPointer();
App* app1 = reinterpret_cast<App*>(ptr);

4. 强制类型转换

C语言中,可以通过(T)xx转换为类型T,C++中也支持这种写法,这种写法被称为强制类型转换。它有什么问题呢?请看下面这个例子:

 

我们首先定义类Human

class Human {
protected:
    int mAge;  // 年龄

public:
    virtual void say() {
        std::cout << "I'm a human.\n";
    }
};

这个类表示人类,它有一个成员mAge,表示人类的年龄;还有一个虚函数say, 此函数会输出一句话。

 

接下来定义类Man, 这个类继承自Human类:

class Man : public Human {
public:
    Man(int age) {
        mAge = age;
    }

    void say() override {
        std::cout << "I'm a man.\n";
    }

    void howOld() {
        std::cout << "I'm " << mAge << " now.\n";
    }
};

这个类表示男人。其中,虚函数say被重载,此外还有一个成员函数howOld, 输出当前的年龄。

 

最后定义类Woman, 同样继承自Human类:

class Woman : public Human {
public:
    Woman(int age) {
        mAge = age;
    }

    void say() override {
        std::cout << "I'm a woman.\n";
    }
};

这个类表示女人。它只重载了虚函数say, 并没有提供howOld方法(因为女性的年龄不会轻易告诉别人)。

 

我们在main函数中创建一个指向Woman对象的指针,并尝试通过指针访问howOld方法:

int main() {
    auto pWoman = new Woman(32);
    pWoman->howOld();
}

这段代码应当会报错,因为Woman类没有howOld方法。以下是博主使用g++编译时输出的报错信息:

error: 'class Woman' has no member named 'howOld'

 

但如果我们将指针pWoman强制转换Man*类型的指针呢?代码如下:

int main() {
    auto pWoman = new Woman(32);
    ((Man*)pWoman)->howOld();
}

令人诧异的是,这段代码可以正常运行,输出如下:

I'm 32 now.

使用强制类型转换后,竟然输出了女性的年龄,这真的是太糟糕了!

 

我们不妨使用static_cast转换试试:

int main() {
    auto pWoman = new Woman(32);
    (static_cast<Man*>(pWoman))->howOld();
}

这段代码会在编译时报错:

error: invalid 'static_cast' from type 'Woman*' to type 'Man*'

 

再使用dynamic_cast试试:

int main() {
    auto pWoman = new Woman(32);
    (dynamic_cast<Man*>(pWoman))->howOld();
}

代码可以编译成功,但运行时会出错,因为类型转换失败,dynamic_cast会返回一个空指针。对返回值加以判断,程序就可以正常运行了:

int main() {
    auto pWoman = new Woman(32);
    auto pMan = dynamic_cast<Man*>(pWoman);
    if (pMan) {
        pMan->howOld();
    }
    else {
        std::cout << "convert failed.\n";
    }
}

运行后,程序输出如下:

convert failed.

 

最后使用reinterpret_cast试试:

int main() {
    auto pWoman = new Woman(32);
    (reinterpret_cast<Man*>(pWoman))->howOld();
}

编译后,程序输出如下:

I'm 32 now.

 

从这个例子中,可以看出不同类型转换方式的区别。最后,展示一个使用dynamic_cast的例子:

void howOldAreYou(Human* pHuman) {
    Man* pMan = dynamic_cast<Man*>(pHuman);
    if (pMan) {
        pMan->howOld();
    }
    else {
        std::cout << "My age is a secret.\n";
    }
}


int main() {
    Man* p1 = new Man(23);
    Woman* p2 = new Woman(35);
    howOldAreYou(p1);
    howOldAreYou(p2);
}

程序输出为:

I'm 23 now.
My age is a secret.

标签:Woman,dynamic,pWoman,cast,static,howOld,指针
From: https://www.cnblogs.com/overxus/p/17991592

相关文章

  • media图片不显示static
    settings.pySTATIC_URL='static/'#Defaultprimarykeyfieldtype#https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-fieldDEFAULT_AUTO_FIELD='django.db.models.BigAutoField'STATICFILES_DIRS=[BASE_DIR/......
  • 比较以下Unity AStar Pathfinding, NavMesh, Recast Navigation 寻路算法的优点与缺点
    一、AStarPathfindingAStarPathfinding是一种基于图搜索的寻路算法,它使用启发式搜索来找到最短路径。AStarPathfinding的优点包括:高效性:AStarPathfinding是一种高效的寻路算法,因为它使用启发式搜索来找到最短路径,可以大大减少搜索空间,从而提高寻路速度。灵活性:AStarPathf......
  • c++ cast
    static_caststatic_cast(expression)用于非多态类型的低风险转换,如基类和派生类之间的转换,基本数据类型之间的转换(包括任何隐式转换),用户自定义转换,把void指针转换成目标类型的指针等。不进行运行时类型检查,只在编译时检查。具体如下用于类层次结构中基类和派生类之间指针......
  • Fortify Static Code Analyzer 23.2 for macOS, Linux & Windows - 静态应用安全测试
    FortifyStaticCodeAnalyzer23.2formacOS,Linux&Windows-静态应用安全测试FortifySCA-代码漏洞扫描工具|静态代码测试|代码安全分析请访问原文链接:https://sysin.org/blog/fortify-static-code-analyzer/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.o......
  • ZooKeeper's atomic broadcast protocol:Theory and practice 翻译
    ZooKeeper’satomicbroadcastprotocol:TheoryandpracticeZooKeeper的原子广播协议:理论和实践Andr´eMedeirosMarch20,2012Abstract摘要ApacheZooKeeperisadistributedcoordinationserviceforcloudcomputing,providingessentialsynchronizationandgrou......
  • .net core 静态文件的访问权限控制(UseStaticFiles)
    官方文档:https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/static-files?view=aspnetcore-8.0&viewFallbackFrom=aspnetcore-2.2wwwroot中的文件,可以在Startup类的Configure方法中添加以下语句:app.UseStaticFiles();默认情况下,诸如HTML、css、图像、js之类的静态资......
  • rust使用lazy_static对全局变量多线程并发读写示例
    首先需要在项目依赖Cargo.toml添加lazy_static依赖项[dependencies]lazy_static="1.4.0"示例代码如下:uselazy_static::lazy_static;usestd::sync::{RwLock,RwLockReadGuard,RwLockWriteGuard};usestd::thread;#[derive(Debug)]structSharedData{data:Vec<......
  • 在.framework框架下的winfrom中使用Castle.DynamicProxy实现AOP问题小记
    1.需求:为项目中通讯PLC模块实现AOP,实现统一的日志打印,参数校验,方法执行时间统计2.问题:①现有项目没有IOC容器,没法使用部分AOP库的方法注册到IOC,(注:如果要实现IOC对现有代码改动大,并且AOP只是针对部分模块实现)②要在尽量小的代码改动下实现针对以上问题选择使用Castle.DynamicProx......
  • Day57 Static关键字详解
    Static关键字详解static加在方法上叫静态方法static加在属性上叫静态属性1.staticpackagecom.oop.demo09;//staticpublicclassStudent{//一.静态属性privatestaticintage;//加了static是静态的变量多线程!privatedoublescore;//没有s......
  • AI4Science 再填新成员:谷歌推出天气模型MetNet-3 已落地相关产品、谷歌天气预报模型Gr
    相关:https://zhidx.com/news/40169.htmlhttps://zhidx.com/news/40290.html论文地址:https://www.science.org/doi/10.1126/science.adi2336《Learningskillfulmedium-rangeglobalweatherforecasting》Editor’ssummaryThenumericalmodelsusedtopredictwea......