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++ 转换的非正式分类的更多相关文章

  1. [C++][操作符]四种显示转换操作符

    整理了C++ Primer中提到的四种显示转换,用思维导图写出来,是不是很清晰O(∩_∩)O.

  2. Hibernate中3种结果转换的详细说明(转)

    Hibernate中3种结果转换的详细说明 在hibernate使用的过程中.我们通常需要对结果进行解释. Hibernate为我们提供了以下3种解释方法: Transformers.ALIAS_TO ...

  3. 如何批量转换 WordPress 文章分类

    可能建博之初,分类设置过于详细,后来想重新整理并删除一些分类项目,比如删除分类A,并将其中的所有文章划归到分类B中,手动修改文章的分类过于麻烦,有木有什么方法可以批量移动文章到另一个分类中呢? 网上闲 ...

  4. Hibernate Transformers之三种结果转换说明

    在hibernate使用的过程中,我们通常需要对结果进行解释.Hibernate为我们提供了以下3种查询结果解释方法: Transformers.ALIAS_TO_ENTITY_MAP //把输出结果 ...

  5. C++提供的四种新式转换--const_cast dynamic_cast reinterpret_cast static_cast

    关于强制类型转换的问题,许多书都讨论过,写的最具体的是C++之父的<C++的设计和演化>. 最好的解决方法就是不要使用C风格的强制类型转换,而是使用标准C++的类型转换符:static_c ...

  6. C++ 四种显示转换

    转自:http://www.jellythink.com/archives/205   (果冻想) 前言 这篇文章总结的是C++中的类型转换,这些小的知识点,有的时候,自己不是很注意,但是在实际开发中 ...

  7. C++四种强制转换

    C++的四种强制类型转换,所以C++不是类型安全的.分别为:static_cast , dynamic_cast , const_cast , reinterpret_cast 为什么使用C风格的强制 ...

  8. php 23种设计模式 - 设计模式简介以及分类

    一. Introduction[介绍] 设计模式:提供了一种广泛的可重用的方式来解决我们日常编程中常常遇见的问题.设计模式并不一定就是一个类库或者第三方框架,它们更多的表现为一种思想并且广泛地应用在系 ...

  9. 面试问题之C++语言:说一说C++中四种cast转换

    C++中四种类型转换是:static_cast.dynamic_cast.const_cast.reinterpret_cast 1.const_cast 常量转换,用于将const变量转为非cons ...

  10. 九种常见UML图(分类+图解)

    九种常见UML图 1.类图 概述 类图(Class Diagram)是面向对象系统建模中最常用和最重要的图,是定义其它图的基础. 类图主要是用来显示系统中的类.接口以及它们之间的静态结构和关系的一种静 ...

随机推荐

  1. The second day learning summary

    1.什么是接口测试? 接口测试是测试系统组件间接口的一种测试.接口测试主要用于外部系统与系统之间以及内部各个子系统之间的交互点,定义特定的交互点,然后通过这些交互点来,通过一些特殊的规则也就是协议,来 ...

  2. 华企盾DSC由于半透明软件设置了需要管理员权限打开导致半透明打不开加密文件

    解决方法: 1.右键该应用程序->属性->兼容性,去掉[以管理员权限运行此程序] 2.也可以打开控制面板->系统和安全->用户账户控制设置调至最低

  3. mybatis测试类的书写步骤

    mybatis测试类的书写步骤 private SqlSession session; @Test //* 1.根据UserMapper接口的Class对象获取Mapper接口类型的对象 //* 2. ...

  4. Codeforce Round 916(div3)

    Codeforces Round 916(div3) [Problem - A - Codeforces]:Problemsolving Log A.题 直接看样例进行分析,发现每一次出现的字符代表着 ...

  5. 简单几行实现sliver上线提醒

    准备魔改sliver去掉一些特征什么的,这里记录一下最简单实现上线消息通过企业微信机器人提醒的方式,这很简单也有很多不足还需要接着改的 protobuf中对消息Beacon和Session的定义如下, ...

  6. Python——第二章:文件操作

    文件操作 1. 找到这个文件. 双击打开它 open(文件路径, mode="", encoding="") 文件路径: 1. 绝对路径 d:/test/xxx ...

  7. 通用 Mapper 的批量插入实现

    具体的 SQL 模板实现如下所示: import org.apache.ibatis.mapping.MappedStatement; import tk.mybatis.mapper.MapperE ...

  8. CVE-2023-36025 Windows SmartScreen 安全功能绕过漏洞

    CVE-2023-36025是微软于11月补丁日发布的安全更新中修复Windows SmartScreen安全功能绕过漏洞.攻击者可以通过诱导用户单击特制的URL来利用该漏洞,对目标系统进行攻击.成功 ...

  9. 文心一言 VS 讯飞星火 VS chatgpt (38)-- 算法导论5.4 2题

    二.假设我们将球投入到b个箱子里,直到某个箱子中有两个球.每一次投掷都是独立的并且每个球落入任何箱子的机会均等.请问投球次数期望是多少? 文心一言: 这是一个典型的鸽巢原理(Pigeonhole Pr ...

  10. 作为所有类的顶层父类,没想到Object的魔力如此之大!

    写在开头 在上一篇博文中我们提到了Java面向对象的四大特性,其中谈及"抽象"特性时做了一个引子,引出今天的主人公Object,作为所有类的顶级父类,Object被视为是James ...