龙空技术网

面试题:C++ explicit关键字

CyberPunk 299

前言:

现在朋友们对“关键字不能作为什么来使用”大致比较看重,大家都想要学习一些“关键字不能作为什么来使用”的相关资讯。那么小编在网上收集了一些对于“关键字不能作为什么来使用””的相关内容,希望我们能喜欢,看官们快快来学习一下吧!

前言:

C++ explicit关键字

在 C++ 中,explicit 关键字用于限制构造函数的隐式转换。当声明一个带有 explicit 关键字的单参数构造函数时,它就不能被用于隐式的类型转换。这对于防止意外的类型转换非常有用,特别是在类的设计中,可以避免因构造函数被误用而导致的潜在问题。

隐式构造 vs 显式构造

隐式构造:是指在不需要显式调用构造函数的情况下,编译器自动进行的类型转换。例如,从一个类型到另一个类型的自动转换。

显式构造:是指显式调用构造函数来创建对象的过程。这通常是通过构造函数名后面跟括号 () 或初始化列表 {} 来完成的。

explicit用法

explicit 关键字用于单参数构造函数前,如下所示:

class MyClass {public:    explicit MyClass(int value)     {        // 构造函数实现    }};

示例

#include <iostream>class MyClass {public:    explicit MyClass(int value) {        data = value;    }    void printData() const {        std::cout << "Data: " << data << std::endl;    }private:    int data;};int main() {    // 显式构造    MyClass obj1(10);    obj1.printData(); // 输出: Data: 10    // 隐式构造将导致编译错误    // MyClass obj2 = 20; // 错误: explicit 关键字禁止了隐式转换    // 显式构造    MyClass obj3(30);    obj3.printData(); // 输出: Data: 30    return 0;}

在这个例子中,MyClass 的构造函数带有 explicit 关键字,这意味着不能使用它来进行隐式的类型转换。例如,代码27行 MyClass obj2 = 20; 这样赋值会导致编译错误。

都说关键字 explicit 只对一个实参的构造函数有效。其实也有例外:

多参数构造函数

对于多参数构造函数,如果只有一个参数没有默认值,那么这样的构造函数也可以被用作单参数构造函数。在这种情况下,explicit 关键字可以用于该构造函数,以防止隐式转换。

示例

#include <iostream>class MyClass {public:    // 多参数构造函数,其中一个参数有默认值    explicit MyClass(int value, double precision = 0.0)        : data(value), precision(precision)     {        std::cout << "Initialized with value: " << value << " and precision: " << precision << std::endl;    }    void printData() const     {        std::cout << "Data: " << data << ", Precision: " << precision << std::endl;    }private:    int data;    double precision;};int main() {    MyClass obj1(10); // 显式构造    obj1.printData(); // 输出: Data: 10, Precision: 0    // 编译错误:explicit 关键字禁止了隐式转换    MyClass obj2 = 20; // 错误: explicit 关键字禁止了隐式转换    MyClass obj3(20, 0.5); // 显式构造    obj3.printData(); // 输出: Data: 20, Precision: 0.5    getchar();    return 0;}

在这个例子中,构造函数 MyClass(int value, double precision = 0.0) 可以通过一个参数来调用,因为 precision 参数有默认值。通过使用 explicit 关键字,可以防止该构造函数被用于隐式类型转换。示例当中代码25行会报错。

使用复制列表初始化,explicit也能生效

示例

#include <iostream>class MyClass {public:    // 多参数构造函数    explicit MyClass(int value, double precision): data(value), precision(precision)     {        std::cout << "Initialized with value: " << value << " and precision: " << precision << std::endl;    }        void printData() const     {        std::cout << "Data: " << data << ", Precision: " << precision << std::endl;    }    private:    int data;    double precision;};int main() {    MyClass obj1{ 20, 0.5 }; // 显式 直接初始化构造    obj1.printData(); // 输出: Data: 20, Precision: 0.5    MyClass obj2 = { 20, 0.5 }; //报错 初始化    obj2.printData();    MyClass obj3(20, 0.5); // 显式构造 直接初始化    obj3.printData(); // 输出: Data: 20, Precision: 0.5    getchar();    return 0;}

示例代码27行报错

错误  C3445  "MyClass" 的复制列表初始化不能使用显式构造函数  0710  E:\src_20220311\1027\0710\0710.cpp  27 

可以看到,加上explicit关键字做修饰,同样可以起到【禁止类型转换】的作用。

这里还有个小知识点:只能在类内声明构造函数时使用 explicit 关键字,在类外部定义时不应重复

//mya.hclass MyA{public:  explicit MyA(int k);};
//mya.cpp#include "MyA.h"explicit MyA::MyA(int k){}

报错:

错误  C2178  不能使用“explicit”说明符声明“MyA::{ctor}”  

题外话:

我个人一直都比较讨厌C++的这种隐式转换,有时候会出现和你想的不一样的情况,增加了学习成本。(高手写的代码应该是新手都能很清晰的看懂,但是实际情况是高手各种炫技,写的你看不懂才能显示出他是高手)

google的c++规范中提到explicit的优点是可以避免不合时宜的类型变换,缺点。所以google约定所有单参数的构造函数都必须是显示的,只有极少数情况下拷贝构造函数可以不声明称explicit。例如作为其他类的透明包装器的类。(缺点无 不能再同意了

effective c++中说:被声明为explicit的构造函数通常比其non-explicit兄弟更受欢迎。因为它们禁止编译器执行非预期(往往也不被期望)的类型转换。除非有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit。

标签: #关键字不能作为什么来使用