用C++越久,越是觉得C++太多陷阱,真是防不胜防。
我们看这样一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> using namespace std; class C { public: C(int a) { printf("%d\n", __LINE__); } virtual ~C() {} }; int main(int argc, char **argv) { C x1(1); return 0; } |
编译执行正常,结果是:
7
然后我们改一下,把构造函数变成无参数的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> using namespace std; class C { public: C() { printf("%d\n", __LINE__); } virtual ~C() {} }; int main(int argc, char **argv) { C x1(); return 0; } |
继续编译执行,输出居然是空了!?
实在找不到任何原因,于是gdb了一下,发现根本就没有到构造函数里面。
再仔细看了一下,想起来一般无参数的类初始化都是没有括号的,于是换了一下调用方法:
1 2 3 4 5 | int main(int argc, char **argv) { C x1; return 0; } |
结果正常了~
这是神马坑爹的语法?!有参数的时候就要有括号?没参数的时候连个空括号都不能有?
抱怨归抱怨,我们跳出来看一下:
1 | C x1(); |
这行语句根本就是一行函数声明啊。。。
试想一下,有一天一个类的构造函数从一个参数变成空参数,于是你在调用的时候只是把括号里的参数删了,而括号还留着的话。。估计够你调几个小时了。。
原创文章,版权所有。转载请注明:转载自Vimer的程序世界 [ http://www.vimer.cn ]
本文链接地址: http://www.vimer.cn/?p=2359
我***。这个,要是没见过,不会想到这个。唉,一方面是对c++越来越不熟悉了,另一方面,这个实在太dt了。
[回复]
看看这个:
int b;
C x1(C2(b));
很遗憾的告诉你,这仍然是函数声明
[回复]
Dante 回复:
九月 29th, 2011 at 9:50 上午
还真是。。。
int b;
C x1(C(b));
[回复]
这个倒是一眼就看出来了,吃过这个亏,我也记得有大牛说过:这是语言的阴暗面之一,我们只能 live with it.
[回复]
Dante 回复:
九月 29th, 2011 at 9:50 上午
语义的二义性。。确实如此。。
[回复]
c++ primer 说过了, 类类型的声明不能这样的初始化语法的.
c++ 很多细节要注意的, 非常麻烦.
[回复]
倒不觉得奇怪,如果之前是写Java的话就另说了。
从语法分析的角度来讲,C x1();本就可以有两种解释,只不过C++优先把它当成函数声明罢了。
[回复]
Dante 回复:
九月 29th, 2011 at 9:47 上午
我不用java。。
嗯,语义出现二义性了。
[回复]
Fangzhen 回复:
五月 15th, 2012 at 3:54 下午
C++和java不一样,
C x1()就是一个函数声明,C++中如果要使用默认构造函数(就是不带参数的构造函数)的时候不用加括号。如果要动态构造一个类的话加不加括号都一样,如:
C * px=new C();
和C *p=new C;
是一样的
[回复]
还真遇到过,不过那时候立刻调试了,一下发现没进去就明白是当成声明了
[回复]
哇,居然还有这个,倒真的没碰到过…………
[回复]
C++真是到处都是坑啊
[回复]
……这是Java写多了吧
[回复]
Dante 回复:
九月 29th, 2011 at 9:44 上午
我还真不用java。。
[回复]
隐约记得好像C++没参数的时候,推荐使用C(void)的吧?C()算是不规范写法。
[回复]
Dante 回复:
九月 29th, 2011 at 9:43 上午
C(void) 也是不行的。。你可以试试。
void也可以看作是函数形参。
[回复]
dutor 回复:
九月 30th, 2011 at 9:45 上午
C里面C()原型可以传参,C++里面C()等价于C(void),这里面如果写成C(void)的话,就告诉编译器这就是原型,编译器就毫不犹豫咯。
下面的“匿名”兄弟太有喜感了,哈哈哈
[回复]
你不会用就别乱说,真是笑死人了!你怎么不用C x1=new C();这种方式去初始化C++代码?那岂不是更有喜剧效果?
[回复]
shade 回复:
九月 29th, 2011 at 10:35 上午
这位匿名的兄台~
我觉得你更搞笑一些
希望你能分享一些有营养的内容~
[回复]
真搞笑,用其他语言的语法去要求C++
[回复]
C()调用的是拷贝构造函数,不是无参构造函数。不要在这种基本的问题是误导新手。
[回复]
Dante 回复:
九月 29th, 2011 at 9:43 上午
这位朋友,虽然你的几个评论都有点尖锐,但我开始还是不打算回复你的帖子的,但是你非要说C()居然是调用拷贝构造函数这种误导性的话,我只能出来辟谣了。
C x1;
C x2(x1);
C x3 = x1;
x3 = x2;
这几行代码,你能正确的说出都调用了什么函数吗?
[回复]
Sunday 回复:
九月 30th, 2011 at 9:26 上午
唉,不要和此种人一般见识,无知就算了,出来让别人笑话就是他的问题了 !
[回复]
Dante 回复:
九月 30th, 2011 at 9:38 上午
哈哈,多谢支持~~~~
[回复]
一直都用new的飘过。
[回复]
哈哈 还真是如此~
如果C++滴水不漏,就不会有其他语言了~
[回复]
上帝保佑我以后不要遇到这个问题,我经常写AS的啊!
[回复]
我写C++代码时,只能每增加一行,就运行一次g++。对了,还要打开http://en.cppreference.com/w/cpp 方便查找函数名,头文件。还有当写下 template 后,只能祈求苍保佑不要出错,否则我会被淹没在上千字节的错误信息中。开发效率可想而知。
《Effective C++》、《More Effective C++》、《Exceptional C++》、《More exceptional C++》、《Effective STL》、《Imperfect C++》、《Essential C++》….. 这个书单可以很长很长。有人说十年才可以学会C++,可要真是花十年在一门语言上,你还有多少时间研究算法。研究设计。
C++ 的确开发出了很多重要的软件,但这并不足以说这门语言有多好,要知道WordPress 还是用PHP写的呢。
当我学习过 Haskell 之后,才发现C++中的精华——STL,只是在模仿函数式语言中最基础的部分,而且还没有模仿好(甚至每写一个foreach 都要写一个对应的 functor,鬼才知道那个functor 还能不能复用)
用Python, Ruby, Haskell,也许是 Java 写程序,必要时调用 C++ 的 library 或许是当下不错的选择。
用的时间越长,对这种语言越反感,只想说 I hate C++
[回复]
Dante 回复:
九月 29th, 2011 at 1:17 下午
确实如此,说C顶多砸到脚,C++不小心就会炸飞整条腿的比喻真是非常贴切。
我现在写自己的东西都是python,简洁优雅。
可惜公司代码只能用C++,无奈。。。
[回复]
springlie 回复:
九月 29th, 2011 at 2:29 下午
貌似这个问题在Effective 系列中提过。。。
[回复]
t.w. 回复:
十月 4th, 2011 at 6:52 下午
这个问题我也奇怪过
原来果然是和函数声明一样啊
[回复]
嗯,在c++里面,一个语句如果可以是函数声明,那么它就是函数声明。
[回复]
Sunday 回复:
九月 30th, 2011 at 9:27 上午
应该是这么回事~C++时间越长,越觉得杯具~
[回复]
第一个你定义析构函数但是没有定义复制构造函数和赋值操作符,所以你无论你是 C x1(5),还是 C x1(1)值,对象的值是一样的。
实验方法是
你定义一个
C x1(1)
C x2(5)
你销毁 X1,C对象也将被销毁
x2也将不复存在
第二个
C x1(),无参数默认为空初始化,输出肯定为空啊
为什么等于 7 和你 你此句代码有关printf(“%d\n”, __LINE__);
[回复]
Dante 回复:
十月 4th, 2011 at 11:01 上午
朋友,你还是再回去看看C++的书吧。
[回复]
这个问题我也奇怪过,看了你的才理解原因,原来果然是和函数声明一样啊~
[回复]
这个问题我也奇怪过,看了你的才理解原因,原来果然是和函数声明一样啊
[回复]
这个问题我也奇怪过,
看了你的才理解原因,
原来果然是和函数声明一样啊
[回复]
Declaring a class instance using a default constructor that has parameters, you should pass the arguments to let the compiler to correctly construct the object. Declaring a class instance using a default construtor that has no parameters is the same as declaring a variable, since the compiler already knows which constructor to run for you. Overloading allows the flexibilities at the cost of attention of class users to specify the exact function to run.
[回复]
的确如此,有些时候人的视角和编译器的视角是不是不一致的。习惯就好~
[回复]
如果函数声明使用了C(void){}这样呢?
[回复]
之前学过一点c++皮毛,然后学过java之后想再回头好好学习下c++,因为觉得c++还是很牛的,但每次看个开头就看不下去了,相比java,c++就是一坨屎一样的恶心。
[回复]
C++是一门优秀的语言,优秀不代表完美,总会存在或多或少的不习惯。但C++能流行30多年,足以说明一切问题了, ls的那个不懂就不要在那装B ,你说的话更相一坨屎
[回复]