万恶的VC -- 默认构造函数试看下面的代码C/C++ codestruct A{A(int InVal):Value(InVal){}int Value}str
万恶的VC -- 默认构造函数
试看下面的代码
C/C++ codestruct A{ A(int InVal):Value(InVal){} int Value;};struct B{ A a;};struct C{ B b;};int main(){ C c; return 0;}
然后在VC环境下编译, 编译器提示错误:
error C2512: 'C' : no appropriate default constructor available
奇怪了, 我们不禁要问, 为什么C需要提供一个default constructor, 我又没有在C中提供非VOID参数的构造函数? 但如果顺着编译器给出的提示, 我们手动为C添加默认构造函数, 再编译,这时又提示说B没有提供默认构造函数;如果我们再顺着编译器的思路为B添加默认构造函数, 再编译, 这时才会提示A需要提供默认构造函数. 到这里就真正对了.
?
由于A没有提供默认构造函数, 导致包含A的B无法默认构造, 因此又会进一步导致包含了B的C无法被默认构造, 但是编译器给出的错误居然包含了误导信息, 我认为这里应该提示A(而非C)需要提供默认构造函数. 但是VC的这种行为实在令我费解!
这是一个很令人深思的问题, 假设我们在管理VC项目时, 某些类有着多层has a包含关系, 其中某些类提供了默认构造函数, 而某些类的默认构造函数由编译器生成, 则, 当我们在比较底层的类中添加了一个类似A的成员, 则引发的编译错误对程序员来说是地狱般的噩梦.
同时, 也引发了一个编程习惯上的思考, 就是无论有没有必要, 最好都给类提供默认构造函数, 千万别偷懒! 以防止类似事件.
另外, GNU编译器在这个情形下的表现要比VC智能很多, 假设以上代码位于名为test2.cpp文件, 然后用命令
g++ test2.cpp -o test2
在linux环境下编译, 则给出如下提示:
test2.cpp: In constructor ‘B::B()’:
test2.cpp:10:1: error: no matching function for call to ‘A::A()’
test2.cpp:5:2: note: candidates are: A::A(int)
test2.cpp:4:1: note: A::A(const A&)
test2.cpp: In constructor ‘C::C()’:
test2.cpp:15:1: note: synthesized method ‘B::B()’ first required here
test2.cpp: In function ‘int main()’:
test2.cpp:22:4: note: synthesized method ‘C::C()’ first required here
错误提示明确指明了A需要提供默认构造函数, 这点非常不错.
PS: 楼主目前使用的VC版本是2008(9.0), 目前还不方便在VS2005, 及VS2010上做测试. 如果哪位有此条件的达官贵人帮忙测试下并把结果贴出来与大家分享, 在下将感激不尽!
[解决办法]学习了
[解决办法]这个不用测试的,你显式给出一个类的构造函数就会阻止编译器为他生成一个默认构造函数的行为,所以一个原则是你需要默认初始化的话,并且给一个类定义了一个构造函数,就一定要为这个类定义默认构造函数。
你这里给A定义了构造函数A(int InVal):Value(InVal){},自然会阻止A生成默认版本
[解决办法]楼主所碰到的情况是再正常不过了。这就是为什么如果你自己提供了一个构造函数,最好同时提供一个缺省的构造函数,因为如果自己提供了一个构造函数,编译器就不会再自动为你提供一个缺省的构造函数了。
其实道理,楼主自己已经理解得非常清楚了。A,B,C三个struct彼此之间没有继承和被继承的关系,因此,从上面的代码来看,C的缺省构造函数是存在的,但如果我们要构造一个C对象,有C中“有一个”B对象,而且写法是B b; 那么很显然要调用B的缺省构造函数,B的缺省构造函数应该是存在的,但问题是B中有一个A对象,而且写法是A a; 这就要求调用A的缺省构造函数,但A的缺省构造函数不存在,因此B对象无法构造成功,进而导致C对象无法构造成功。
要解决这个问题,就是在A中增加一个缺省构造函数。
编译器的提示的错误信息,是有点不准确的。
VS2010所遇到的情况,和楼主描述的情况一致。
另外,楼主给出代码,即A的构造函数应该是public的才好,在你的示例中尽管无关紧要,但如果你在A中增加一个缺省的构造函数,那么它就必须要是public的,否则下面的B和C都无法构造成功。
[解决办法]要做到“十恶不赦”已是万难,要做到“万恶”... ...