详解C++ 转换的非正式分类

 更新时间:2022年01月20日 15:32:06   作者:mkckr0  
C++ 正式分类方法是直接按语法分类,分为:隐式转换和显示转换。这篇文章主要介绍了C++ 转换的非正式分类,需要的朋友可以参考下

C++ 正式分类方法是直接按语法分类,分为:隐式转换和显示转换。隐式转换又称为标准转换。显示转换又分为:C 风格转换、函数风格转换、C++ 风格转换。C++风格转换就是 static_castdynamic_castconst_castreinterpret_cast 这 4 种。

有很长一段时间我都有这样的疑问:转换前的对象和转换后的对象是不是同一个?

现在,我引入一种非正式分类方法,分为:同对象转换和异对象转换。这两个术语是我自己编的,只是为了方便说明问题。

  • 同对象转换:转换后的对象和转换前的对象是同一个,也就是不会构造一个新的对象,还是使用原来的对象。
  • 异对象转换:转换后的对象和转换前的对象不是同一个,也就是会构造一个新的的对象。

下面分别说明这两种转换的典型情况。

一、同对象转换

所有的值类别转换及其变形都是同对象转换。

1. 值类别转换

C++ 的值类别可以使用 static_cast 进行转换,属于同对象转换。注意:static_cast<T&>()static_cast<T&&>() 的语义不是将一个对象转换为一个引用,而是转换对象的值类别,使其能被对应的引用绑定。

// 左值转换为左值
int a = 1;
static_cast<int&>(a) = 2;
std::cout << a << std::endl;
// 输出:2
// 左值转换为右值
int a = 1;
int&& b = static_cast<int&&>(a);
b = 2;
std::cout << a << std::endl;
// 输出:2
// 右值转换为右值,转换前对象为非字面量
int a = 1;
int&& b = static_cast<int&&>(static_cast<int&&>(a));
b = 2;
std::cout << a << std::endl;
// 输出:2

2. 借助值类别转换进行 OOP 转换

这种情况带有值类别转换,属于同对象转换。

// upcast
struct A
{
    int x = 1;
};

struct B : A
{
};

B b;
static_cast<A&>(b).x = 2;
std::cout << b.x << std::endl;
// 输出:2
// downcast
struct A
{
    int x = 1;
};

struct B : A
{
};

B b;
static_cast<B&>(static_cast<A&>(b)).x = 2;
std::cout << b.x << std::endl;
// 输出:2
// sidecast
struct A1
{
    virtual void f1() {}
    int x = 1;
};

struct A2
{
    virtual void f2() {}
    int y = 1;
};

struct B : A1, A2
{
};

B b;
dynamic_cast<A2&>(static_cast<A1&>(b)).y = 2;
std::cout << b.y << std::endl;
// 输出:2

2. 借助值类别转换进行 const_cast 转换

这种情况带有值类别转换,也是同对象转换。注意:通过 const_cast 修改原本为 const 的对象是未定义行为。

struct A
{
    int x = 1;
};

{
    int a;
    const_cast<int&>(const_cast<const int&>(a)) = 2;
    std::cout << a << std::endl;
}
{
    A a;
    const_cast<A&>(const_cast<const A&>(a)).x = 2;
    std::cout << a.x << std::endl;
}
/* 输出:
2
2
*/

二、异对象转换

所有的非值类别转换都是异对象转换。

1. 普通的类型转换

// 标量类型
int a = 1;
int&& b = static_cast<int>(a);
b = 2;
std::cout << a << std::endl;
// 输出:1

 

// 类类型
struct A
{
    A() {
        std::cout << "A::A() " << x << std::endl;
    }
    A(const A&) {
        std::cout << "A::A(const A&) " << x << std::endl;
    }
    ~A() {
        std::cout << "A::~A() " << x << std::endl;
    }
    int x = 1;
};

A a;
A&& b = static_cast<A>(a);
b.x = 2;
std::cout << b.x << std::endl;
/* 输出:
A::A() 1
A::A(const A&) 1
2
A::~A() 2
A::~A() 1
*/

2. 指针转换

转换之后,指针本身是异对象,指针所指的对象是同对象。这种情况也包含:借助指针进行 OOP 转换,借助指针进行 const_cast 转换。

int* a = new int;
std::cout << a << std::endl;
int* && r = static_cast<int*>(a);
r = nullptr;
std::cout << a << std::endl;
/* 输出:
0x1ffdeb0 0x1ffdeb0
*/

到此这篇关于C++ 转换的非正式分类的文章就介绍到这了,更多相关C++ 转换非正式分类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 合并排序(C语言实现)

    合并排序(C语言实现)

    递归算法是把一个问题分解成和自身相似的子问题,然后再调用自身把相应的子问题解决掉。这些算法用到了分治思想。
    2013-02-02
  • C++ 赋值构造函数注意点介绍

    C++ 赋值构造函数注意点介绍

    下面小编就为大家带来一篇C++ 赋值构造函数注意点介绍。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • 使用Clion刷LeetCode的方法

    使用Clion刷LeetCode的方法

    这篇文章主要介绍了使用Clion刷LeetCode的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • C++生成随机浮点数的示例代码

    C++生成随机浮点数的示例代码

    在C++11之前,我们通常采用rand函数来生成随机数,但rand函数对一些情况显得难以处理。本文将介绍如何利用C++生成随机浮点数,需要的可以参考一下
    2022-04-04
  • C语言实现大学生考勤管理系统

    C语言实现大学生考勤管理系统

    这篇文章主要为大家详细介绍了C语言实现大学生考勤管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C语言中一些将字符串转换为数字的函数小结

    C语言中一些将字符串转换为数字的函数小结

    这篇文章主要介绍了C语言中一些将字符串转换为数字的函数小结,分别为atoi()函数和atol()函数以及atof()函数,需要的朋友可以参考下
    2015-08-08
  • c++ vector造成的内存泄漏问题

    c++ vector造成的内存泄漏问题

    这篇文章主要介绍了c++ vector造成的内存泄漏问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • C语言实现三子棋小游戏全程详解

    C语言实现三子棋小游戏全程详解

    完成一个三子棋的代码并不是很难,有困难且重要的是完成这个游戏代码所具备的思想,因为思想上的进步才是真正的进步,当我们有了这个思想上的武器,写出别的代码,难度就不会高
    2022-05-05
  • 简单总结C++中指针常量与常量指针的区别

    简单总结C++中指针常量与常量指针的区别

    这里我们来简单总结C++中指针常量与常量指针的区别,包括如何声明和使用常量指针以及指针常量,需要的朋友可以参考下
    2016-06-06
  • C语言怎样用指针指向字符串

    C语言怎样用指针指向字符串

    这篇文章主要介绍了C语言怎样用指针指向字符串问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10

最新评论