【C++入门到精通】C++类型的转换 | static_cast | reinterpret_cast | const_cast | dynamic_cast [ C++入门 ]

这篇具有很好参考价值的文章主要介绍了【C++入门到精通】C++类型的转换 | static_cast | reinterpret_cast | const_cast | dynamic_cast [ C++入门 ]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++入门到精通】C++类型的转换 | static_cast | reinterpret_cast | const_cast | dynamic_cast [ C++入门 ],C++,c++,java,开发语言

引言

当我们在进行C++编程时,类型转换是一个非常常见的操作。而在C++中,我们有多种类型转换的方式可供选择。其中包括**static_castreinterpret_castconst_castdynamic_cast**。这些类型转换操作符能够在不同的场景下帮助我们实现所需的类型转换。本文将详细介绍这些类型转换方式的用法和适用条件,以帮助读者更好地理解和运用它们。无论你是刚刚接触C++还是有一定经验的开发者,相信这篇文章都能对你的编程技能有所提升。让我们一起深入探索C++类型转换的奥秘吧!

一、强制转换(集成C语言的语法)

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化。C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换

  • 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  • 显式类型转化:需要用户自己处理
void Test ()
{
	int i = 1;
	// 隐式类型转换
	double d = i;
	printf("%d, %.2f\n" , i, d);
	
	int* p = &i;
	// 显示的强制类型转换
	int address = (int) p;
	printf("%x, %d\n" , p, address);
}

C风格的类型转换格式相对简单,但存在下面一些缺点。

  1. 隐式类型转换可能会导致一些问题,例如数据精度丢失。这是因为在隐式类型转换过程中,编译器会自动进行一些类型转换操作,可能会改变原始数据的精度或范围
  2. 显式类型转换将所有类型转换情况混合在一起,使得代码可读性和清晰度不足。在C语言中,使用强制类型转换来实现显式类型转换。

为了解决这些问题,C++引入了自己的类型转换风格。C++支持四种类型转换操作符:static_castreinterpret_castconst_castdynamic_cast这些操作符提供了更加明确和具体的类型转换方式,能够更好地控制类型转换的行为

🚨🚨注意由于C++要兼容C语言,所以在C++中仍然可以使用C语言的类型转换风格,即强制类型转换。然而,为了编写更安全和可维护的代码,建议尽量避免使用C风格的类型转换,而是使用C++的类型转换操作符来实现类型转换。

二、static_cast 操作符

1. 操作符介绍

static_cast是C++语言中的一种类型转换操作符,它主要用于进行较为 “自然” 和低风险的类型转换,例如整型和浮点型、字符型之间的互相转换。此外,如果一个对象所属的类重载了强制类型转换运算符T(如Tintint*或其他类型名),则也可以使用static_cast将该对象转换为T类型。

🚨🚨注意static_cast不能用于不同类型的指针之间的转换,包括指向基类和派生类的指针之间的转换。也不能用于整型和指针之间的互相转换,因为这些转换的风险比较高。此外,static_cast也不能用于不同类型的引用之间的转换

因此,在使用static_cast时,我们需要根据具体的情况来选择合适的类型转换操作符。如果需要进行风险较高的类型转换,应该使用reinterpret_castconst_castdynamic_cast等其他类型转换操作符。同时,我们需要始终保持对类型转换的合法性和安全性的警惕性。

2. 使用示例

当使用static_cast时,可以将其用于以下几种情况的类型转换:

(1)基本类型之间的转换

int num = 10;
double result = static_cast<double>(num);

在上述代码中,将整数类型的变量num转换为浮点数类型的变量result

(2)类型之间的隐式转换

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void foo() 
    {
        cout << "Derived::foo()" << endl;
    }
};

Base* basePtr = new Derived;
Derived* derivedPtr = static_cast<Derived*>(basePtr);
derivedPtr->foo();

在上述代码中,将指向基类Base的指针basePtr转换为指向派生类Derived的指针derivedPtr,然后调用Derived类的成员函数foo()

(3)类指针和引用之间的转换

class MyClass {
public:
    void foo() 
    {
        cout << "MyClass::foo()" << endl;
    }
};

void bar(MyClass& obj) 
{
    obj.foo();
}

MyClass obj;
bar(static_cast<MyClass&>(obj));

在上述代码中,将一个对象obj转换为对应类型的引用,并传递给函数bar()进行调用。

🚨🚨注意static_cast并不能执行所有类型之间的转换。对于一些风险较高的转换,如不同类型的指针之间的转换,应该使用其他类型转换操作符。在使用static_cast时,始终要保持对类型转换的合法性和安全性的警惕性,确保转换操作的正确性。

三、reinterpret_cast 操作符

1. 操作符介绍

reinterpret_cast是C++语言中的一种类型转换操作符,它可以用于不同类型之间的指针、引用以及指针和能容纳指针的整数类型之间的转换。这种转换提供了很大的灵活性,但也存在较高的风险和安全隐患,因为转换时执行的是逐个比特复制的操作,没有对类型之间的关联性进行检查。

因此,在使用reinterpret_cast时,程序员需要非常谨慎,确保转换的合法性和安全性。例如,将一个int* 指针、函数指针或其他类型的指针强制转换成string*类型的指针是可能的,但这样做可能会引发错误,程序员需要自行承担查找错误的繁琐工作(C++ 标准不允许将函数指针转换成对象指针,但有些编译器,如 Visual Studio 2010,则支持这种转换)

2. 使用示例

(1)将指针转换为整数

int* ptr = new int(10);
uintptr_t ptrToInt = reinterpret_cast<uintptr_t>(ptr);

这段代码将一个int类型的指针ptr转换为一个uintptr_t(无符号整数)类型的值ptrToInt。这可以用于某些特殊情况下,例如将指针存储到一个整数类型的变量中。

(2)将整数转换为指针

uintptr_t intToPtr = 0x12345678;
int* intPtr = reinterpret_cast<int*>(intToPtr);

这段代码将一个uintptr_t类型的整数intToPtr转换为一个int类型的指针intPtr。需要注意的是,这种转换是不安全的,因为整数可能不是有效的地址值,所以使用时需要非常小心。

(3)将指向基类的指针转换为指向派生类的指针

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void foo() { std::cout << "Derived::foo()" << std::endl; }
};

Base* basePtr = new Derived();
Derived* derivedPtr = reinterpret_cast<Derived*>(basePtr);
derivedPtr->foo();

这段代码展示了如何将一个指向基类Base的指针basePtr转换为一个指向派生类Derived的指针derivedPtr。由于Derived是从Base派生而来,并且声明了虚函数,因此这种转换是安全的。

🚨🚨注意:如果BaseDerived之间没有继承关系,或者Derived没有声明虚函数,那么使用reinterpret_cast进行转换是不安全的

(4)将指向不同类型的指针进行转换

int i = 10;
float f = reinterpret_cast<float&>(i);

这段代码将一个int类型的变量i转换为一个float类型的变量f。由于intfloat在内存中的表示方式不同,因此这种转换的结果是未定义的,可能会导致程序出现奇怪的行为。

四、const_cast 操作符

1. 操作符介绍

const_cast是C++语言中的一种类型转换操作符,它主要用于去除常量属性。const_cast可以将指向常量对象的指针或引用转换为指向非常量对象的指针或引用

const_cast的主要作用是修改对象的常量性,使得可以通过非常量指针或引用对其进行修改。这在某些特定情况下是很有用的,比如当一个函数被声明为接受非常量参数时,但实际传入的是常量参数时,可以使用const_cast将参数转换为非常量类型。

🚨🚨注意:使用const_cast进行类型转换时,必须确保原始对象本身并不是常量,否则修改常量对象的值会导致未定义行为。同时,修改被const_cast转换后的对象可能会引发其他问题,因此在使用const_cast时需要谨慎考虑

2. 使用示例

(1)移除常量性以修改对象的值

const int value = 5;
int& ref = const_cast<int&>(value);
ref = 10;

这段代码中,一个常量整数value被声明并初始化为5。然后通过const_cast将其转换为一个非常量的整数引用ref,并将其值修改为10。需要注意的是,修改一个本身被声明为常量的对象是一种未定义行为,所以在实际应用中应该避免这样的转换

(2)在函数中移除常量性以调用非常量版本的成员函数

class MyClass {
public:
    void foo() { std::cout << "Non-const foo()" << std::endl; }
    void foo() const { std::cout << "Const foo()" << std::endl; }
};

void callNonConstFoo(const MyClass& obj) 
{
    const_cast<MyClass&>(obj).foo();
}

int main() 
{
    MyClass obj;
    callNonConstFoo(obj);
    return 0;
}

这段代码中,MyClass类有两个版本的成员函数foo,一个是非常量版本,一个是常量版本。在函数callNonConstFoo中,通过const_cast移除了对象obj的常量性,并调用了非常量版本的成员函数foo

🚨🚨注意这种转换只能在实际上对象本身是非常量的情况下使用,否则将导致未定义行为

(3)移除常量性以进行底层操作

void writeToMemory(const void* addr, int value) 
{
    int* ptr = const_cast<int*>(static_cast<const int*>(addr));
    *ptr = value;
}

这段代码演示了将常量指针转换为非常量指针,从而通过指针修改内存中的值。在函数writeToMemory中,通过const_cast将常量void指针addr转换为非常量int指针ptr,并将value的值写入到ptr指向的内存位置。

🚨🚨注意:在实际应用中,应该非常小心使用const_cast,避免对本身被声明为常量的对象进行修改,以及避免产生未定义行为。const_cast应该被谨慎使用,并且只在确实有必要的情况下才使用

五、dynamic_cast 操作符

1. 操作符介绍

reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。

相比之下,dynamic_cast一种更安全的转换操作符,它专门用于将多态基类指针或引用强制转换为派生类指针或引用。dynamic_cast在进行转换时会进行运行时类型检查,确保转换的安全性。如果转换成功,则返回指向派生类对象的指针或引用;如果转换失败,即基类对象不是派生类对象,那么dynamic_cast会返回一个空指针

🚨🚨注意:dynamic_cast只能用于多态类型之间的转换,即涉及到虚函数的继承体系。对于非多态基类和派生类之间的转换,则无法使用dynamic_cast,只能使用reinterpret_cast来完成转换,但这样的转换是不安全的

2. 使用示例

(1)将基类指针转换为派生类指针并调用成员函数

class Base {
public:
    virtual void foo() { std::cout << "Base::foo()" << std::endl; }
};

class Derived : public Base {
public:
    void foo() override { std::cout << "Derived::foo()" << std::endl; }
};

int main() 
{
    Base* basePtr = new Derived();
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
    if (derivedPtr != nullptr) 
    {
        derivedPtr->foo(); // 输出 "Derived::foo()"
    }
    delete basePtr;
    return 0;
}

这段代码中,一个派生类Derived对象被创建,并将其地址赋值给一个基类Base指针basePtr。然后通过dynamic_castbasePtr转换为一个Derived指针derivedPtr,并调用其成员函数foo。由于Derived是从Base派生而来,并且声明了虚函数,所以这种转换是安全的。

🚨🚨注意如果BaseDerived之间没有继承关系,或者Derived没有声明虚函数,那么使用dynamic_cast进行转换会导致编译错误

(2)使用dynamic_cast进行运行时类型检查

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {};

void foo(Base* basePtr) {
    if (dynamic_cast<Derived*>(basePtr)) {
        std::cout << "basePtr points to a Derived object" << std::endl;
    } else {
        std::cout << "basePtr does not point to a Derived object" << std::endl;
    }
}

int main() {
    Base* basePtr = new Derived();
    foo(basePtr);
    delete basePtr;
    return 0;
}

这段代码中,函数foo接受一个基类Base指针basePtr作为参数,并使用dynamic_cast将其转换为一个Derived指针。如果转换成功,则说明basePtr指向的对象是Derived类型的,可以执行相应的操作。

🚨🚨注意:如果BaseDerived之间没有继承关系,或者Derived没有声明虚函数,那么使用dynamic_cast进行转换会返回空指针nullptr

温馨提示

感谢您对博主文章的关注与支持!另外,我计划在未来的更新中持续探讨与本文相关的内容,会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!文章来源地址https://www.toymoban.com/news/detail-837090.html

到了这里,关于【C++入门到精通】C++类型的转换 | static_cast | reinterpret_cast | const_cast | dynamic_cast [ C++入门 ]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • static_cast与dynamic_cast到底是什么?

    写这个随笔说一下C++的static_cast和dynamic_cast用在子类与父类的指针转换时的一些事宜。首先,【static_cast,dynamic_cast】【父类指针,子类指针】,两两一组,共有4种组合:用 static_cast 父类转子类、用 static_cast 子类转父类、使用 dynamic_cast 父类转子类、用 dynamic_cast 子类转父类

    2024年04月24日
    浏览(30)
  • srand(static_cast<unsigned>(time(NULL)))

    srand(static_castunsigned(time(NULL))) 在 C++ 中是用来初始化随机数生成器的代码。 这段代码中, time(NULL) 返回系统当前时间距离 Epoch(Unix 时间的起始时间,通常是1970年1月1日 00:00:00 UTC)的秒数,用 NULL 表示不考虑时区的情况下获取当前时间。然后,将这个时间值传递给 srand 函数,

    2024年02月07日
    浏览(39)
  • C++的类型转换运算符:dynamic_cast

    顾名思义,与静态类型转换相反,动态类型转换在运行阶段(即应用程序运行时)执行类型转换。 可检查 dynamic_cast 操作的结果,以判断类型转换是否成功。使用 dynamic_cast 运算符的典型语法如下: 例如: 如上述代码所示,给定一个指向基类对象的指针,程序员可使用 dyna

    2024年02月15日
    浏览(42)
  • 【C++】dynamic_cast 进行类型转换步骤以及底层实现

    dynamic_cast 是 C++ 中的一种类型转换方式,它可以在运行时进行类型检查, 用于将一个指针或引用强制转换为另一个类型的指针或引用 。dynamic_cast 能够进行安全的向下转型,即将一个基类指针或引用转换为派生类指针或引用。如果转换成功,dynamic_cast 返回转换后的指针或引用

    2023年04月25日
    浏览(45)
  • C++从入门到精通——static成员

    声明为 static 的类成员称为类的静态成员,用 static 修饰的成员变量,称之为静态成员变量;用 static 修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。 静态成员是指属于类而不属于类的任何对象的成员。静态成员在类的所有对象之间共享,并且

    2024年04月25日
    浏览(29)
  • 【C++入门到精通】C++入门 —— 类和对象(初始化列表、Static成员、友元、内部类、匿名对象)

    目录 一、初始化列表 ⭕初始化列表概念 ⭕初始化列表的优点 ⭕使用场景 ⭕explicit 二、Static成员 ⭕Static成员概念 🔴静态数据成员: 🔴静态函数成员: ⭕使用静态成员的优点 ⭕使用静态成员的注意事项 三、友元 ⭕友元的概念 ⭕类友元 ⭕函数友元  四、内部类 ⭕

    2024年02月14日
    浏览(44)
  • c++中static静态成员变量和静态成员函数、explcit和隐式类型转换、友元函数()详解

    声明为 static 的类成员 称为 类的静态成员 ,用 static 修饰的 成员变量 ,称之为 静态成员变量 ;用 static 修饰 的 成员函数 ,称之为 静态成员函数 。 静态成员变量一定要在类外进行初始化   静态成员 为 所有类对象所共享 ,不属于某个具体的对象,存放在静态区   静态成

    2024年02月04日
    浏览(49)
  • C++ 之 【类与对象】从入门到精通一条龙服务 最终篇(static成员、友元、匿名对象。。。)

    💴到用时方恨早,白首方悔挣的少 车到山前没有路,悬崖勒马勒不住 –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀– 在创建对象时,编译器通过调用构造函数,给对象中各个

    2024年04月16日
    浏览(45)
  • (04)基础强化:接口,类型转换cast/convert,异常处理,传参params/ref/out,判断同一对象

         1、New的截断是指什么?              new除了新开空间创建初始化对象外,还有一个 隐藏 父类同名方法的作用。                  当子类想要隐藏父类同名的方法时用new,用了new后父类同名方法将到此为止,后面         继承的子类,将再也继承不到父类的同

    2024年02月01日
    浏览(44)
  • 17. C++ static、const 和 static const 类型成员变量声明以及初始化

    1. C++ static、const 和 static const 类型成员变量声明以及初始化 const 定义的常量在超出其作用域之后其空间会被释放; static 定义的静态常量在函数执行后不会释放其存储空间; 1.2 static static 表示的是静态的 类的静态成员函数、静态成员变量是和类相关的,而不是和类的具体对

    2024年01月18日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包