C++雾中风景5:Explicit's better than implicit.聊聊Explicit.

关于Explicit还是Implicit一直是编程语言中能让程序员们干起架的争议。那些聪明的老鸟总是觉得Implicit的规则让他们能够一目十行,减少样板代码的羁绊。而很多时候,Implicit的很多规则会让新手或者是合作开发的搭档痛苦不堪。文章的标题也写明了笔者的态度,显式的在代码之中指明自己的意图,会让程序更加明晰。所以也借今天这篇文章,我们来聊聊Explicit关键字。

1.隐式类类型转换

好吧,先看一段代码: (为了简单起见,我这里就没有重载<<操作符了)

class A {
public:
    A(int s) {};
};

void printA(A a) {
    cout << "hello" << endl;
}

int main() {
    printA(10);
}

上面这段代码是可以通过编译运行的,可能有些小伙伴会比较困惑,为虾米这里printA函数明明需要接受的是一个A类型,但是传入的一个int类型仍然能够编译通过。

这就被称之为隐式类类型转换,它存在于自定义的类构造函数中。C++的编译器会对只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象。也就是说,上段代码其实可以翻译成下面的代码:

class A {
public:
    A(int s) {};
};

void printA(A a) {
    cout << "hello" << endl;
}

int main() {
    printA(A(10));
}

这里10作为int类型的参数,通过隐式的类类型转换,被默认构造了一个A类型的匿名对象,传入了函数printA,所以代码能够正常的编译运行。显然,这种类型的代码是十分Confused。所以我们来看看这么解决这个问题的。

有一个折衷的解决方案,将代码做下面的修改:

void printA(A &a) {
    cout << "hello" << endl;
}

这里通过引用类型就可以避开这个陷阱,因为编译器不会构造这个匿名对象的引用,所以此时的代码是无法通过编译的。

显然,这个方案改变了我们不使用引用类型的初衷,我们看看C++有木有更加优雅的解决方案。

2.Explicit关键字

explicit主要用于"修饰"构造函数,使得它不用于程序中需要通过此构造函数进行"隐式"转换的情况。指定此关键字,需要隐式转换方可进行的程序将不能编译通过。

class A {
public:
    explicit A(int s) {};
};

void printA(A a) {
    cout << "hello" << endl;
}

int main() {
    printA(10);  //无法通过编译
}

这里我们添加了explicit关键字,阻止了编译器的隐式类类型转换,让代码更加明晰了。当然,我们这里是可以使用static_cast关键字可以显式的类型转换,通过代码的编译。

int main() {
    printA(static_cast<A>(32));
}

explicit关键字只对一个参数的构造函数有效,需要多个实参的构造函数不能用于隐式类型转换。

3.讨论一下

  • Scala 类型系统几乎是Scala之中最复杂的内容,Scala设计的讨巧之处,是通过implicit关键字,显式的指定了隐式类类型转换。虽然隐式类类型转换减少了很多冗余的代码,但是这样的设计会降低代码的可读性。Scala也一直因为可读性被诟病,所以这样的设计,见仁见智。
  • Golang 如果是接口interface与Python是类似的鸭子类型,不需要什么隐式转换了。 而如果是struct类的话,那Golang就十分严格的执行强类型的判断。不符合是不行的。
  • Java Java一直是拒绝这种Confuse做法的语言,所以通过一大堆繁琐的样板代码规避这样的问题。

“Explicit's better than implicit”。Explicit保证了代码的可读性和维护性。这点对于一个系统的工程性是很有帮助的。Implicit的转换容易带来那种“看上去很美,但是非常容易出错”的 feature 。希望我们能够告别对它的依赖。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C语言及其他语言

【编程经验】printf专题:你可能不知道的printf用法【文末有福利】

你可能不知道的printf用法 ? 不少小伙伴反映C语言只会用printf函数,但一些参数、返回值什么的还不了解,所以今天总结一二,给大家总结和梳理一下...

29880
来自专栏web编程技术分享

小兔JS教程(三)-- 彻底攻略JS回调函数

48160
来自专栏斑斓

编程实践 | Scala亮瞎Java的眼(一)

这是我在11月15日成都OpenParty分享的一个题目,确有标题党的嫌疑。Scala自然不是无所不能,Java也没有这么差劲,我只希望给Java程序员提供另外...

35850
来自专栏AzMark

Python学习之面向对象

12530
来自专栏Android干货园

Kotlin初级(1)- - - 基础.md

使用package包可以将代码分割到各个命名空间内。所谓命名空间,就好比咱们的国内重名的地区非常多,如果单独将一个地名,很可能引起歧义,但如果按省来划分,就解决...

10230
来自专栏小詹同学

Leetcode打卡 | No.017 电话号码的字母组合

欢迎和小詹一起定期刷leetcode,每周一和周五更新一题,每一题都吃透,欢迎一题多解,寻找最优解!这个记录帖哪怕只有一个读者,小詹也会坚持刷下去的!

16230
来自专栏Java架构沉思录

关于Java序列化你不知道的事

您觉得自己懂 Java 编程?事实上,大多数程序员对于 Java 平台都是浅尝则止,只学习了足以完成手头上任务的知识而已。在本系列 中,Ted Neward 深...

10420
来自专栏程序员互动联盟

【编程基础】盖大楼地基要牢固

水之积也不厚,则其负大舟也无力。——庄子 上一篇讲了几个编译编辑器,大家都可以用用,新手掌握几个是没有坏处的。 学编程要从基础学起,就像盖大楼,先把地基打好,...

38090
来自专栏机器学习从入门到成神

设计模式之静态工厂、工厂方法和抽象工厂的联系与区别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

9420
来自专栏刘望舒

带你领略Kotlin的精髓

从谨慎地在项目中引入kotlin到全部转为kotlin开发我们用了大概半年的时间。这中间经历了从在一个小功能中尝试使用到完全使用kotlin完成了大版本开发的过...

12320

扫码关注云+社区

领取腾讯云代金券