C++中的显式构造和隐式构造

文章目录

    • 一、概述
    • 二、显式构造函数的使用
    • 三、隐式构造函数的使用
    • 四、显式和隐式的适用场景

一、概述

在 C++ 中,构造函数可以分为 显式构造 和 隐式构造,它们的区别主要体现在构造函数的调用方式上。

1.显式构造(Explicit Constructor)
显式构造函数是使用 explicit 关键字声明的构造函数。它的作用是防止编译器在某些情况下进行隐式类型转换。
特点:

  • 禁止隐式类型转换:当一个类的构造函数被声明为 explicit 时,编译器不能使用该构造函数进行隐式类型转换(即自动将一个类型转换为另一个类型)。
  • 只允许显式调用:显式构造函数只能通过明确的构造函数调用来创建对象。

2.隐式构造(Implicit Constructor)
隐式构造函数是没有使用 explicit 关键字声明的构造函数。编译器可以根据需要自动调用这些构造函数进行隐式类型转换。
特点:

  • 允许隐式类型转换:如果构造函数没有 explicit 关键字,编译器就可以在适当的地方进行隐式类型转换
  • 可能导致意外的行为:因为编译器会自动进行类型转换,有时可能会引发难以发现的错误。

二、显式构造函数的使用

示例:

#include <iostream>
#include <string>using namespace std;class student {
public:explicit student(int _age) {m_age = _age;cout << "age=" << m_age << endl;}explicit student(int _age, const string _name) {m_age = _age;m_name = _name;cout << "m_age = " << m_age << ";name = " << m_name << endl;}
private:int m_age;string m_name;
};int main(int argc, const char * argv[]) {student xiaoM(18); //显式构造//student xiaoW = 18; //error:隐式构造student xiaoHua(19, "小花");//显式构造//student xiaoMei = {18, "小美"}; //error:隐式构造,初始化参数列表,C++11前编译不能通过,C++11新增特性return 0;

请添加图片描述

三、隐式构造函数的使用

class student {
public:student(int _age) {m_age = _age;cout << "age=" << m_age << endl;}student(int _age, const string _name) {m_age = _age;m_name = _name;cout << "m_age = " << m_age << ";name = " << m_name << endl;}private:int m_age;string m_name;
};int main(int argc, const char * argv[]) {student xiaoM(18); //显式构造student xiaoW = 18; //隐式构造student xiaoHua(19, "小花");//显式构造student xiaoMei = {18, "小美"}; //隐式构造,初始化参数列表,C++11前编译不能通过,C++11新增特性return 0;
}

请添加图片描述

四、显式和隐式的适用场景

1.显式构造函数(explicit)的适用场景
显式构造函数主要用于防止隐式类型转换,从而避免潜在的错误和不必要的复杂性。以下是使用显式构造函数的合适场景:

(1)避免隐式类型转换引发的错误
隐式类型转换可能会导致不易察觉的 bug,特别是当转换在函数调用时发生时。显式构造函数可以防止这种自动转换,从而避免潜在的问题。
示例:

class MyClass {
public:explicit MyClass(int x) { /* ... */ }
};void func(MyClass obj) { /* ... */ }int main() {func(10);  // 错误:编译器不会将 10 隐式转换为 MyClass
}

在这种情况下,explicit 会阻止隐式转换,确保参数是显式地传递给构造函数。

(2)避免不必要的类型转换
如果一个类仅用于存储一个数据成员(比如 int 或 double),那么你不希望编译器进行隐式转换,因为它可能会影响代码的行为或可读性。
示例:

class MyClass {
public:explicit MyClass(int x) : value(x) {}int getValue() { return value; }private:int value;
};int main() {MyClass a = 10;  // 错误:必须显式调用 MyClass(10)MyClass b(10);    // 正确:显式调用
}

(3)用于控制类型转换的精确性
在某些情况下,显式构造函数有助于你控制程序行为,确保类型转换只发生在明确的地方。例如,避免传递不匹配类型的对象给构造函数。
示例:

class MyClass {
public:explicit MyClass(double x) { /* ... */ }
};

如果构造函数是显式的,程序员必须明确传入 double 类型的参数,而不能将 int 自动转换成 double,从而减少不必要的类型转换。

2.隐式构造函数的适用场景
隐式构造函数适用于简化代码,尤其是在你希望类能够自然地与其他类型进行转换时。它的自动类型转换特性有时能提高代码的简洁性和灵活性。以下是使用隐式构造函数的合适场景:
(1) 进行合理的类型转换
当你希望一个类能够自动与其他类型进行转换,且这种转换在业务逻辑中是有意义的,可以考虑使用隐式构造函数。比如,当一个类表示某种数值类型时,允许类的构造函数从 int 或 double 自动转换过来。
示例:

class MyClass {
public:MyClass(int x) : value(x) {}int getValue() const { return value; }private:int value;
};int main() {MyClass obj = 10;  // 自动调用 MyClass(int x) 构造函数std::cout << obj.getValue() << std::endl;  // 输出 10
}

这种情况下,使用隐式构造函数的好处是让代码更简洁,10 直接被自动转换为 MyClass 类型。

(2) 提高代码的可读性和简洁性
隐式构造函数可以让代码看起来更加自然和简洁。特别是在一些简单的数据包装类中,自动转换通常不会引起误解,也不会导致隐式错误。
示例:

class Point {
public:Point(int x, int y) : x(x), y(y) {}int x, y;
};void move(Point p) {std::cout << "Moving to (" << p.x << ", " << p.y << ")" << std::endl;
}int main() {move({10, 20});  // 使用隐式构造函数将 {10, 20} 转换为 Point
}

(3)与 STL 或其他库兼容
如果你的类是作为某种数据结构的一部分(比如容器、算法的输入/输出等)并且你希望它支持标准的自动转换和初始化机制,使用隐式构造函数可能是合适的。例如,你可以让类在容器中直接与其他类型兼容。
示例:

std::vector<MyClass> vec;
vec.push_back(5);  // MyClass(int) 会被隐式调用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/68410.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【YOLOv11改进- 主干网络】YOLOv11+MobileNetV3(2019): 更快,更精准;

YOLOV11目标检测-主干网络改进实例与创新改进专栏 目录 YOLOV11目标检测-主干网络改进实例与创新改进专栏 本文介绍 1.完整代码获取 2.MobileNetv3介绍 文章摘要 3. MobileNetv3网络结构图 4. yolov11-MobileNetv3 yaml文件 5.MobileNetv3代码实现 6.MobileNetv3添加方…

A7. Jenkins Pipeline自动化构建过程,可灵活配置多项目、多模块服务实战

服务容器化构建的环境配置构建前需要解决什么下面我们带着问题分析构建的过程:1. 如何解决jenkins执行环境与shell脚本执行环境不一致问题?2. 构建之前动态修改项目的环境变量3. 在通过容器打包时避免不了会产生比较多的不可用的镜像资源,这些资源要是不及时删除掉时会导致服…

浅谈文献阅读(reference)对留学论文写作的重要性

很多留学生在写作留学论文时&#xff0c;拿到题目后就急于求成立马动笔写作。可是写着写着就会陷入非常迷惘的境地&#xff0c;不知道如何继续。当然这其中有很多原因&#xff0c;但其中最重要的一条&#xff0c;就是在写作英语论文之前&#xff0c;没有进行足够的知识积累&…

es6中关于let的使用以及案例,包括但不限于块级作用域,不允许重复声明,没有变量提升,暂存性死区,不与顶层对象挂钩

ES6 let 关键字完整指南 1. 块级作用域 1.1 let vs var 作用域对比 // var - 函数作用域 function varExample() {var x 1;if (true) {var x 2; // 同一个 xconsole.log(x); // 2}console.log(x); // 2 }// let - 块级作用域 function letExample() {let x 1;if (true…

提升企业内部协作的在线知识库架构与实施策略

内容概要 在当前快速变化的商业环境中&#xff0c;企业对于提升内部协作效率的需求愈显迫切。在线知识库作为信息存储与共享的平台&#xff0c;成为了推动企业数字化转型的重要工具。本文将深入探讨如何有效打造与实施在线知识库&#xff0c;强调架构设计、知识资产分类管理及…

网络工程师 (3)指令系统基础

一、寻址方式 &#xff08;一&#xff09;指令寻址 顺序寻址&#xff1a;通过程序计数器&#xff08;PC&#xff09;加1&#xff0c;自动形成下一条指令的地址。这是计算机中最基本、最常用的寻址方式。 跳跃寻址&#xff1a;通过转移类指令直接或间接给出下一条指令的地址。跳…

度小满Java开发面试题及参考答案 (上)

String 是基本类型吗?String、StringBuffer、StringBuilder 的区别是什么?拼接字符串有哪些做法? String 不是基本类型,它是 Java 中的一个类,属于引用类型。 下面来看看 String、StringBuffer、StringBuilder 的区别: 类型可变性线程安全性性能适用场景String不可变线程…

【数据结构】_以SLTPushBack(尾插)为例理解单链表的二级指针传参

目录 1. 第一版代码 2. 第二版代码 3. 第三版代码 前文已介绍无头单向不循环链表的实现&#xff0c;详见下文&#xff1a; 【数据结构】_不带头非循环单向链表-CSDN博客 但对于部分方法如尾插、头插、任意位置前插入、任意位置前删除的相关实现&#xff0c;其形参均采用了…

vue项目中,如何获取某一部分的宽高

vue项目中&#xff0c;如何获取某一部分的宽高 在Vue项目中&#xff0c;如果你想要获取某个DOM元素的宽度和高度&#xff0c;可以使用原生的JavaScript方法或者结合Vue的特性来实现。以下是几种常见的方法&#xff1a; 使用ref属性 你可以给需要测量宽高的元素添加一个ref属…

【Samba】Ubuntu20.04 Windows 共享文件夹

【Samba】Ubuntu20.04 Windows 共享文件夹 前言整体思路检查 Ubuntu 端 和 Windows 网络通信是否正常创建共享文件夹安装并配置 Samba 服务器安装 Samba 服务器创建 Samba 用户编辑 Samba 配置文件重启 Samba 服务器 在 Windows 端 访问 Ubuntu 的共享文件夹 前言 本文基于 Ub…

Linux初识——基本指令(2)

本文将继续从上篇末尾讲起&#xff0c;讲解我们剩下的基本指令 一、剩余的基本指令 1、mv mv指令是move&#xff08;移动&#xff09;的缩写&#xff0c;其功能为&#xff1a;1.剪切文件、目录。2.重命名 先演示下重命名&#xff0c;假设我想把当前目录下的di34改成dir5 那…

函数与方法

具名函数 具名函数是有名称的函数&#xff0c;可以在定义之前或之后调用。 特点 有函数名。定义后可以多次调用。便于调试&#xff0c;因为在调用栈中可以看到函数名。 function add(a, b) {return a b; }console.log(add(2, 3)); // 输出: 5 匿名函数 匿名函数没有名称…

定制Centos镜像(一)

环境准备&#xff1a; 一台最小化安装的干净的系统&#xff0c;这里使用Centos7.9,一个Centos镜像&#xff0c;镜像也使用Centos7.9的。 [rootlocalhost ~]# cat /etc/system-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]# rpm -qa | wc -l 306 [rootloca…

Android - 通过Logcat Manager简单获取Android手机的Log

由于工作需要&#xff0c;经常需要获取Android手机的Log。 平常都是通过adb命令来获取&#xff0c;每次都要写命令。 偶然的一个机会&#xff0c;我从外网发现了一个工具 Logcat Manager&#xff0c;只需要通过简单的双击即可获取Android的Log&#xff0c;这里也分享一下。 目…

c++学习第十三天

创作过程中难免有不足&#xff0c;若您发现本文内容有误&#xff0c;恳请不吝赐教。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、vector 1.介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样&#xff0c;vector也采用的连续存储空…

「数学::质数」分解质因子 / LeetCode 2521(C++)

概述 由算数基本定理&#xff0c;我们知道任意一个大于1的自然数可以表示为一些质数的乘积&#xff1a; LeetCode 2521&#xff1a; 给你一个正整数数组 nums &#xff0c;对 nums 所有元素求积之后&#xff0c;找出并返回乘积中 不同质因数 的数目。 注意&#xff1a; 质数 是…

docker-compose Zookeeper 集群搭建

文章目录 前言docker-compose Zookeeper 集群搭建1. Zookeeper下载2. 制作Dockerfile文件3. 构建镜像4. docker-compose 管理5. docker-compose构建/启动6. 验证6.1 docker ps6.2 使用 zkCli.sh 连接并验证集群 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0…

Vue.js 使用 Vuex 管理组件间的共享状态

Vue.js 使用 Vuex 管理组件间的共享状态 今天咱们来聊聊如何用 Vuex 来管理 Vue.js 应用中各个组件之间的共享状态。如果你曾经在项目中为了让组件共享数据而头疼&#xff0c;那么这篇文章就是为你准备的。 什么是 Vuex&#xff1f; 简单来说&#xff0c;Vuex 就是 Vue.js 的…

WIN11 UEFI漏洞被发现, 可以绕过安全启动机制

近日&#xff0c;一个新的UEFI漏洞被发现&#xff0c;可通过多个系统恢复工具传播&#xff0c;微软已经正式将该漏洞标记为追踪编号“CVE-2024-7344”。根据报告的说明&#xff0c;该漏洞能让攻击者绕过安全启动机制&#xff0c;并部署对操作系统隐形的引导工具包。 据TomsH…

R语言学习笔记之高效数据操作

一、概要 数据操作是R语言的一大优势&#xff0c;用户可以利用基本包或者拓展包在R语言中进行复杂的数据操作&#xff0c;包括排序、更新、分组汇总等。R数据操作包&#xff1a;data.table和tidyfst两个扩展包。 data.table是当前R中处理数据最快的工具&#xff0c;可以实现快…