又见C++诡异问题

用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

43 个评论 在 “又见C++诡异问题”

  1. WeAiM 说:

    我***。这个,要是没见过,不会想到这个。唉,一方面是对c++越来越不熟悉了,另一方面,这个实在太dt了。

    [回复]

  2. sw 说:

    看看这个:

    int b;
    C x1(C2(b));

    很遗憾的告诉你,这仍然是函数声明 :D

    [回复]

    Dante 回复:

    还真是。。。
    int b;
    C x1(C(b));

    [回复]

  3. 一念天堂 说:

    这个倒是一眼就看出来了,吃过这个亏,我也记得有大牛说过:这是语言的阴暗面之一,我们只能 live with it.

    [回复]

    Dante 回复:

    语义的二义性。。确实如此。。

    [回复]

  4. fanhe 说:

    c++ primer 说过了, 类类型的声明不能这样的初始化语法的.
    c++ 很多细节要注意的, 非常麻烦.

    [回复]

  5. dutor 说:

    倒不觉得奇怪,如果之前是写Java的话就另说了。
    从语法分析的角度来讲,C x1();本就可以有两种解释,只不过C++优先把它当成函数声明罢了。

    [回复]

    Dante 回复:

    我不用java。。
    嗯,语义出现二义性了。

    [回复]

    Fangzhen 回复:

    C++和java不一样,
    C x1()就是一个函数声明,C++中如果要使用默认构造函数(就是不带参数的构造函数)的时候不用加括号。如果要动态构造一个类的话加不加括号都一样,如:
    C * px=new C();
    和C *p=new C;
    是一样的

    [回复]

  6. DJ 说:

    还真遇到过,不过那时候立刻调试了,一下发现没进去就明白是当成声明了

    [回复]

  7. egmkang 说:

    哇,居然还有这个,倒真的没碰到过…………

    [回复]

  8. egmkang 说:

    C++真是到处都是坑啊

    [回复]

  9. Shiina Luce 说:

    ……这是Java写多了吧

    [回复]

    Dante 回复:

    我还真不用java。。

    [回复]

  10. sanitizer 说:

    隐约记得好像C++没参数的时候,推荐使用C(void)的吧?C()算是不规范写法。

    [回复]

    Dante 回复:

    C(void) 也是不行的。。你可以试试。
    void也可以看作是函数形参。

    [回复]

    dutor 回复:

    C里面C()原型可以传参,C++里面C()等价于C(void),这里面如果写成C(void)的话,就告诉编译器这就是原型,编译器就毫不犹豫咯。
    下面的“匿名”兄弟太有喜感了,哈哈哈

    [回复]

  11. 匿名 说:

    你不会用就别乱说,真是笑死人了!你怎么不用C x1=new C();这种方式去初始化C++代码?那岂不是更有喜剧效果?

    [回复]

    shade 回复:

    这位匿名的兄台~
    我觉得你更搞笑一些
    希望你能分享一些有营养的内容~

    [回复]

  12. 匿名 说:

    真搞笑,用其他语言的语法去要求C++

    [回复]

  13. 匿名 说:

    C()调用的是拷贝构造函数,不是无参构造函数。不要在这种基本的问题是误导新手。

    [回复]

    Dante 回复:

    这位朋友,虽然你的几个评论都有点尖锐,但我开始还是不打算回复你的帖子的,但是你非要说C()居然是调用拷贝构造函数这种误导性的话,我只能出来辟谣了。

    C x1;
    C x2(x1);
    C x3 = x1;
    x3 = x2;

    这几行代码,你能正确的说出都调用了什么函数吗?

    [回复]

    Sunday 回复:

    唉,不要和此种人一般见识,无知就算了,出来让别人笑话就是他的问题了 !

    [回复]

    Dante 回复:

    哈哈,多谢支持~~~~

    [回复]

  14. Huarong 说:

    一直都用new的飘过。

    [回复]

  15. niuniu 说:

    哈哈 还真是如此~
    如果C++滴水不漏,就不会有其他语言了~

    [回复]

  16. 1901 说:

    上帝保佑我以后不要遇到这个问题,我经常写AS的啊!

    [回复]

  17. dreamersdw 说:

    我写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 回复:

    确实如此,说C顶多砸到脚,C++不小心就会炸飞整条腿的比喻真是非常贴切。

    我现在写自己的东西都是python,简洁优雅。

    可惜公司代码只能用C++,无奈。。。

    [回复]

    springlie 回复:

    貌似这个问题在Effective 系列中提过。。。

    [回复]

    t.w. 回复:

    这个问题我也奇怪过
    原来果然是和函数声明一样啊

    [回复]

  18. 夜弓 说:

    嗯,在c++里面,一个语句如果可以是函数声明,那么它就是函数声明。

    [回复]

    Sunday 回复:

    应该是这么回事~C++时间越长,越觉得杯具~

    [回复]

  19. johnson 说:

    第一个你定义析构函数但是没有定义复制构造函数和赋值操作符,所以你无论你是 C x1(5),还是 C x1(1)值,对象的值是一样的。
    实验方法是
    你定义一个
    C x1(1)
    C x2(5)
    你销毁 X1,C对象也将被销毁
    x2也将不复存在
    第二个
    C x1(),无参数默认为空初始化,输出肯定为空啊
    为什么等于 7 和你 你此句代码有关printf(“%d\n”, __LINE__);

    [回复]

    Dante 回复:

    朋友,你还是再回去看看C++的书吧。

    [回复]

  20. t.w. 说:

    这个问题我也奇怪过,看了你的才理解原因,原来果然是和函数声明一样啊~

    [回复]

  21. t.w. 说:

    这个问题我也奇怪过,看了你的才理解原因,原来果然是和函数声明一样啊

    [回复]

  22. t.w. 说:

    这个问题我也奇怪过,
    看了你的才理解原因,
    原来果然是和函数声明一样啊

    [回复]

  23. xheruacles 说:

    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.

    [回复]

  24. Terrence 说:

    的确如此,有些时候人的视角和编译器的视角是不是不一致的。习惯就好~

    [回复]

  25. IMS 说:

    如果函数声明使用了C(void){}这样呢?

    [回复]

  26. cplusplusisapieceofshit 说:

    之前学过一点c++皮毛,然后学过java之后想再回头好好学习下c++,因为觉得c++还是很牛的,但每次看个开头就看不下去了,相比java,c++就是一坨屎一样的恶心。

    [回复]

  27. lssb 说:

    C++是一门优秀的语言,优秀不代表完美,总会存在或多或少的不习惯。但C++能流行30多年,足以说明一切问题了, ls的那个不懂就不要在那装B ,你说的话更相一坨屎

    [回复]

我要评论

*

*