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

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.kler.cn/a/519749.html

相关文章:

  • docker设置开机自启操作
  • YOLO目标检测3
  • ShardingJDBC私人学习笔记
  • 【fly-iot飞凡物联】(20):2025年总体规划,把物联网整套技术方案和实现并落地,完成项目开发和课程录制。
  • 2025数学建模美赛|C题成品论文|第一问
  • WPS数据分析000006
  • [C++技能提升]插件模式
  • 低代码系统-氚云、简道云表单控件对比
  • Typesrcipt泛型约束详细解读
  • 实现宿主机(Windows 10 Docker Desktop)和Linux容器之间的数据挂载的三种方法
  • 【力扣每日一题】LeetCode 2412: 完成所有交易的初始最少钱数
  • Oracle之开窗函数使用
  • Vue编程式路由跳转多次执行报错
  • go入门Windows环境搭建
  • doris: CSV导入数据
  • (一)HTTP协议 :请求与响应
  • Android Toast在指定的Display里面显示
  • TLF35584 基本介绍
  • JAVASE入门十脚-红黑树,比较器,泛型
  • 校园商铺管理系统设计与实现(代码+数据库+LW)