当前位置: 首页 > article >正文

深入理解隐式类型转换:从原理到应用

  • C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。
  •  构造函数前⾯加explicit就不再⽀持隐式类型转换。
  •  类类型的对象之间也可以隐式转换,需要相应的构造函数⽀持。

 内置类型隐式类型转换为类类型对象

在 C++ 中,如果一个类有一个以某种内置类型为参数的构造函数,那么就可以将该内置类型的值隐式转换为这个类的对象。这种隐式转换在某些情况下可以让代码更加简洁,但也可能会导致一些意外的行为。

#include <iostream>
class MyClass {
public:
    // 以 int 为参数的构造函数
    MyClass(int value) : data(value) {
        std::cout << "Constructor called with value: " << value << std::endl;
    }
    void printData() const {
        std::cout << "Data: " << data << std::endl;
    }
private:
    int data;
};

void func(const MyClass& obj) {
    obj.printData();
}

int main() {
    // 隐式类型转换:将 int 类型的 10 转换为 MyClass 类型的对象
    func(10);

    return 0;
}
代码解释
  • MyClass 类有一个以 int 为参数的构造函数,这使得 int 类型的值可以隐式转换为 MyClass 类型的对象。
  • 在 main 函数中,调用 func(10) 时,10 会被隐式转换为 MyClass 类型的对象,然后传递给 func 函数。

2. 使用 explicit 关键字禁止隐式类型转换

在构造函数前面加上 explicit 关键字后,该构造函数就不能用于隐式类型转换,只能用于显式的对象构造。这样可以避免一些潜在的错误。

#include <iostream>
class MyClass {
public:
    // 以 int 为参数的构造函数,使用 explicit 关键字
    explicit MyClass(int value) : data(value) {
        std::cout << "Constructor called with value: " << value << std::endl;
    }
    void printData() const {
        std::cout << "Data: " << data << std::endl;
    }
private:
    int data;
};

void func(const MyClass& obj) {
    obj.printData();
}

int main() {
    // 显式类型转换
    func(MyClass(10));

    // 以下代码会编译错误,因为禁止了隐式类型转换
    // func(10);

    return 0;
}
代码解释
  • MyClass 类的构造函数前面加上了 explicit 关键字,这意味着不能再进行隐式类型转换。
  • 在 main 函数中,调用 func(MyClass(10)) 时,使用了显式的对象构造,这样是合法的。而如果直接使用 func(10),则会导致编译错误

3. 类类型的对象之间的隐式转换

类类型的对象之间也可以进行隐式转换,前提是有相应的构造函数支持。

#include <iostream>
class Base {
public:
    Base(int value) : data(value) {
        std::cout << "Base constructor called with value: " << value << std::endl;
    }
    void printData() const {
        std::cout << "Base Data: " << data << std::endl;
    }
private:
    int data;
};

class Derived {
public:
    // 以 Base 类型为参数的构造函数
    Derived(const Base& base) : baseObj(base) {
        std::cout << "Derived constructor called" << std::endl;
    }
    void printBaseData() const {
        baseObj.printData();
    }
private:
    Base baseObj;
};

void func(const Derived& obj) {
    obj.printBaseData();
}

int main() {
    Base base(10);
    // 隐式类型转换:将 Base 类型的对象转换为 Derived 类型的对象
    func(base);

    return 0;
}
代码解释
  • Derived 类有一个以 Base 类型为参数的构造函数,这使得 Base 类型的对象可以隐式转换为 Derived 类型的对象。
  • 在 main 函数中,创建了一个 Base 类型的对象 base,然后调用 func(base) 时,base 会被隐式转换为 Derived 类型的对象,然后传递给 func 函数。

示例代码

#include<iostream>
using namespace std;
class A
{
public:
 // 构造函数explicit就不再⽀持隐式类型转换 
 // explicit A(int a1)
 A(int a1)
 :_a1(a1)
 {}
 //explicit A(int a1, int a2)
 A(int a1, int a2)
 :_a1(a1)
 , _a2(a2)
 {}
 void Print()
 {
 cout << _a1 << " " << _a2 << endl;
 }
int Get() const
 {
 return _a1 + _a2;
 }
private:
 int _a1 = 1;
 int _a2 = 2;
};
class B
{
public:
 B(const A& a)
 :_b(a.Get())
 {}
private:
 int _b = 0;
};
int main()
{
 // 1构造⼀个A的临时对象,再⽤这个临时对象拷⻉构造aa3 
 // 编译器遇到连续构造+拷⻉构造->优化为直接构造 
 A aa1 = 1;
 aa1.Print();
 const A& aa2 = 1;
 // C++11之后才⽀持多参数转化 
 A aa3 = { 2,2 };
 // aa3隐式类型转换为b对象 
 // 原理跟上⾯类似 
 B b = aa3;
 const B& rb = aa3;
 return 0;
}

 

注意:若想打印B类,就要在print后面加const

代码整体功能概述

这段代码定义了两个类 A 和 B,其中类 A 有两个构造函数,分别接收一个 int 类型参数和两个 int 类型参数;类 B 有一个以 const A& 为参数的构造函数。在 main 函数中,通过不同的方式展示了隐式类型转换的使用。

具体隐式类型转换分析

1. A aa1 = 1;

隐式类型转换过程:类 A 有一个以 int 为参数的构造函数 A(int a1),当执行 A aa1 = 1; 时,编译器会利用这个构造函数将 int 类型的 1 隐式转换为 A 类型的临时对象,然后使用这个临时对象进行拷贝构造 aa1。不过,现代编译器通常会对这种连续的构造和拷贝构造操作进行优化,直接将其转换为直接构造,也就是直接调用 A(int a1) 来构造 aa1 对象。

  • 执行结果:调用 A(int a1) 构造函数,将 _a1 初始化为 1_a2 使用默认值 2。随后调用 aa1.Print() 会输出 1 2

2. const A& aa2 = 1;

隐式类型转换过程:同样基于类 A 的 A(int a1) 构造函数,将 int 类型的 1 隐式转换为 A 类型的临时对象。由于 aa2 是一个常量引用,它可以绑定到这个临时对象上,延长临时对象的生命周期,使其在 aa2 的作用域内保持有效。

  • 执行结果:创建一个 A 类型的临时对象,_a1 为 1_a2 为 2aa2 引用这个临时对象。

3. A aa3 = { 2, 2 };

  • 隐式类型转换过程:在 C++11 及以后的标准中,支持多参数的列表初始化进行隐式类型转换。类 A 有一个接收两个 int 类型参数的构造函数 A(int a1, int a2),因此可以使用 { 2, 2 } 这样的初始化列表来隐式调用该构造函数,将其转换为 A 类型的对象。同样,编译器会进行优化,直接构造 aa3 对象。
  • 执行结果:调用 A(int a1, int a2) 构造函数,将 _a1 和 _a2 都初始化为 2

4. B b = aa3

  • 隐式类型转换过程:类 B 有一个以 const A& 为参数的构造函数 B(const A& a)。当执行 B b = aa3; 时,aa3 是 A 类型的对象,编译器会使用这个构造函数将 A 类型的 aa3 隐式转换为 B 类型的对象。同样,编译器会优化为直接构造 b 对象。
  • 执行结果:调用 B(const A& a) 构造函数,通过 aa3.Get() 获取 _a1 + _a2 的值(这里是 2 + 2 = 4),并将其赋值给 _b

5. const B& rb = aa3;

  • 隐式类型转换过程:基于类 B 的 B(const A& a) 构造函数,将 A 类型的 aa3 隐式转换为 B 类型的临时对象。由于 rb 是一个常量引用,它可以绑定到这个临时对象上,延长临时对象的生命周期。
  • 执行结果:创建一个 B 类型的临时对象,_b 的值为 4rb 引用这个临时对象。

总结

上述代码中通过不同的方式展示了隐式类型转换的应用,包括将内置类型转换为类类型对象,以及类类型对象之间的转换。需要注意的是,如果在构造函数前加上 explicit 关键字,这些隐式类型转换将被禁止,只能进行显式的对象构造。


http://www.kler.cn/a/579984.html

相关文章:

  • FPGA|Verilog-自己写的SPI驱动
  • 我们在开发时,什么时候用到虚函数和纯虚函数?
  • MacOS安装FFmpeg和FFprobe
  • 洛谷 P1433 吃奶酪
  • Spring Cloud 负载均衡器架构选型
  • 基于51单片机多功能防盗报警系统
  • vulnhub靶场之【digitalworld.local系列】的FALL靶机
  • K8S学习之基础二十:k8s的coredns
  • 全面解读 JavaScript 模块化:模块化工具与性能优化
  • WWDG窗口看门狗原理
  • Qwen/QwQ-32B 基础模型上构建agent实现ppt自动生成
  • 显示器长时间黑屏
  • 【基于手势识别的音量控制系统】
  • 1.1 双指针专题:移动零(easy)
  • 香港服务器深度测评:AWS vs 阿里云 vs GCP 技术选型指南
  • 20天 - TCP 和 UDP 有什么区别?说说 TCP 的三次握手?TCP 是用来解决什么问题?
  • Ubuntu 下 nginx-1.24.0 源码分析 - ngx_cycle_modules
  • C++设计模式中的单例模式:从原理、应用、实践指南与常见问题和解决方案深度解析
  • Node.js和Vue CLI 安装指南(Windows 系统)
  • Python 实现非对称加密的 A 端和 B 端软件的详细步骤及代码示例