You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

标记为explicit的已删除构造函数是否有实际作用?

给已删除的构造函数添加explicit修饰符是否有效果?

有细微但确实存在的效果,核心差异体现在重载决议的候选范围和编译器错误提示上:

1. 不带explicit的已删除构造函数

编译器会将其纳入隐式转换的候选构造函数列表。不管是显式调用(如MyClass(1))还是隐式转换(如MyClass a = 1;),只要触发了这个构造函数的调用,都会直接抛出「调用已删除函数」的错误。

比如这段代码:

class MyClass {
public:
    MyClass(int) = delete;
};

int main() {
    MyClass a = 1; // 错误:调用已删除的构造函数 MyClass::MyClass(int)
    MyClass b(2);  // 错误:同样触发已删除函数调用
}

2. 带explicit的已删除构造函数

这个构造函数不会参与隐式转换场景的重载决议。也就是说:

  • 显式调用(如MyClass(1))依然会触发「调用已删除函数」的错误;
  • 隐式转换场景(如MyClass a = 1;)下,编译器根本不会考虑这个构造函数,如果没有其他可行的转换路径,会抛出「无法从'int'转换到'MyClass'」的错误。

举个更明显的对比例子:

class MyClass {
public:
    explicit MyClass(int) = delete;
};

void func(MyClass) {}

int main() {
    func(1);       // 错误:无法将参数 1 从“int”转换为“MyClass”
    MyClass a(1);  // 错误:调用已删除的构造函数 MyClass::MyClass(int)
}

如果存在其他重载构造函数,这种差异还会影响最终的重载决议结果。比如:

class MyClass {
public:
    MyClass(double) {}
    // 不带explicit的已删除构造函数
    MyClass(int) = delete;
};

void func(MyClass) {}

void test() {
    func(1); // 错误:调用已删除的MyClass(int),因为int直接匹配int参数,不会转double
}

而改成explicit MyClass(int) = delete;后:

class MyClass {
public:
    MyClass(double) {}
    explicit MyClass(int) = delete;
};

void func(MyClass) {}

void test() {
    func(1); // 正常编译:int隐式转double,调用MyClass(double)
}

总结

虽然两种写法最终都禁止了通过int直接构造MyClass的行为,但explicit修饰符会改变该构造函数在重载决议中的参与范围,进而影响错误提示和某些场景下的重载结果。

内容的提问来源于stack exchange,提问作者einpoklum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 12:33:22