重载在工程实践中的价值一直备受争议,却一直很受面试官青睐。本文不评论派系问题,只探讨主流语言的现状。主旨在于阐明重载的核心原理,助力面试;同时希望大家以后不要滥用重载。更多想法,可以评论、可以私聊,进一步探讨,此文尽量派系中立。
直观定义:函数名相同,但参数不同的多个函数体,调用时,智能选择使用哪个函数
void func_do_sth(int i) {
std::cout
std::cout
void func_do_sth(int i) {
std::cout
std::cout
void func_do_sth(int i, int j=0) {
}
func_do_sth(1);
func_do_sth(1, 2);
如果是 java 如何实现上述功能?
void func_do_sth_int(int i);
void func_do_sth_string(std::string s);
void func_do_sth_1(int i);
void func_do_sth(int i, int j) ;
java 不支持这种语义
void func_do_sth(int i) {
func_do_sth(i, 0); // 转接到 func_do_sth(int i, int j);
}
void func_do_sth(int i, int j);
如果是 c 如何实现上述功能?
手工实现重载
void func_do_sth_int(int i);
void func_do_sth_string(std::string s);
void func_do_sth_1(int i);
void func_do_sth(int i, int j) ;
那么 golang 是怎么做的?
golang 采用 c 的思路,完全不支持重载。
func func_do_sth_int_1(i int) {}
func func_do_sth_int_2(i, j int) {}
What ?! 这么现代化的语言,竟然不支持这么经典的语法?!
是的,而且你应该注意到,java 还阉割了 c 的 default。
这其实是在编码便利与工程可维护性的一种妥协,只不过 golang 比较激进!代码在什么样的角度去取舍,可以衡量一个工程师的素养。c 、java、go 等语法开放程度,可以认为是语言设计者对使用者 “工程素养” 的信任程度,笔者更喜欢 golang。 这是一段插曲,2年以下工作经验尽量不要人云亦云地在面试中评论这些;比较有经验的可以视面试官能力探讨,这是一个很好的加分项(把握不好就是送命,就像不要在面试中讨论: 4个空格 vs Tab)。
回答完上面这些基本点,有可能针对此项的考查就结束了。你可以完美的拿到 60分!切记,这是在浪费机会!!
为什么 c 做不到,c 能做到? 同样是一个 a.out 二进制,怎么 C 就可以重载,C 就不行呢。同样是 0101 你 C 凭什么得瑟!
那么我们就来看下 a.out 的表象
// a.cpp
void func_do_sth(int i) {
}
void func_do_sth(int i, int j) {
}
// b.c
void func_do_sth_1(int i) {
}
void func_do_sth_2(int i, int j) {
}
这段代码变成了什么
g -c a.cpp -o a.o
nm a.o # 输出 a.o 中的符号
------
0000000000000000 T __Z11func_do_sthi
0000000000000010 T __Z11func_do_sthii
gcc -c b.c -o b.o && nm b.o
------
0000000000000000 T _func_do_sth_1
0000000000000010 T _func_do_sth_2
__Z11func_do_sthi
这个鬼符是什么? 试试 c filt __Z11func_do_sthi
。 其实就是 _func_do_sth_1
,只不过编译器帮我们实现了区分。
g 相比于 gcc 更加智能(机械)地做了这个事情。—— 结论很简单,g 只是变了个魔术而已。
那么我们来看看 java
// a.java
class a{
void func_do_sth(int i) {}
void func_do_sth(int i, int j) {}
void test() {
func_do_sth(1);
func_do_sth(2, 4);
}
}
javac a.java; javap -verbose a.class |grep func_do_sth
----
#2 = Methodref #4.#17 // a.func_do_sth:(I)V
#3 = Methodref #4.#18 // a.func_do_sth:(II)V
java 编译器做了一个类似 g 的魔术,将 func_do_sth
进行了机械的包装。
java 不支持默认值,通过 _func_do_sth_1
调用 _func_do_sth_2
的思路来实现的,也就是利用了上面原理。
那么,c 默认值又是怎么回事
void func_do_sth(int i, int j=0) {}
nm a.o
-------
0000000000000000 T __Z11func_do_sthii
什么情况!没有 __Z11func_do_sthi
,那 func_do_sth(1)
可怎么活啊!!
void func_do_sth(int i, int j=2) {
}
void test() {
func_do_sth(1, 3);
func_do_sth(1);
}
g -S a.cpp -o a.s && cat a.s
----
movl $1, 您可能感兴趣的文章:
参与评论
手机查看
返回顶部