[求助] 一个C++有关构造函数的问题,没想明白

wsmysyn   2018-10-26 21:03 楼主
如题,C++高级特性不怎么经常用,一直当C来用,偶尔调用别人的C++ 类的API, 今天遇到一个没想明白的问题,如图。 我写了三个类CA、CB、CC 构造函数部分, CA采用无参构造 CB采用了一个void类型的指针参数,默认为NULL CC采用一个int类型的指针参数,默认为NULL 然后在Test函数中进行实例化 使用new和不使用new的区别是,new在堆上创建对象,没有new是在栈上创建对象 new创建的对象,可以全局访问,不需要时,需要用delete;栈上的对象,在离开作用域之后,自动销毁 使用new的时候,需要一个类的指针,来指向这个对象 我分别用三种语法来写, Cx cx; --> 1 Cx cx = new Cx(); --> 2 Cx* cx = new Cx(); --> 3 发现只有CB的类是可以支持这三种写法,其他都是不支持2的写法,提示没有相应的构造函数,是Cx*转换为Cx 这个我理解,new的实现是返回一个void类型的指针,和左值类型不符 我的问题: 1、为什么构造函数传入void类型指针之后就可以支持2这种操作呢? 2、从运行的结果上看,2这种实例化方式,调用了两次CB的构造函数,这是为什么呢? 3、在函数结尾,delete三个指针,销毁了这三个对象,分别调用了三个类的析构函数,以及函数结束后,栈上的对象也被销毁,同样分别调用了三个类的析构函数。但是为什么少了1次CB的析构函数呢?构造的时候调用了4次,为什么析构的时候,只有3次呢? 浏览了一下C++ 11的标准,但是并没有找到地方 网上暂时也没搜到这类的描述,(可能提问的姿势不对...) 代码: TIM截图20181026203531.png 运行结果: TIM截图20181026203937.png
  1. class CA
  2. {
  3. public:
  4. CA() { std::cout << "Class A" << std::endl; };
  5. ~CA() { std::cout << "Class A die..." << std::endl; };
  6. };
  7. class CB
  8. {
  9. public:
  10. CB(void* pVOID = NULL) { std::cout << "Class B" << std::endl; };
  11. ~CB() { std::cout << "Class B die..." << std::endl; };
  12. };
  13. class CC
  14. {
  15. public:
  16. CC(int* pLength = NULL) { std::cout << "Class C" << std::endl; }
  17. ~CC() { std::cout << "Class C die..." << std::endl; };
  18. };
  19. void Test(void)
  20. {
  21. CA a0;
  22. //CA a1 = new CA();
  23. CA* a2 = new CA();
  24. CB b0;
  25. CB b1 = new CB();
  26. CB* b2 = new CB();
  27. CC c0;
  28. //CC c1 = new CC();
  29. CC* c2 = new CC();
  30. delete a2;
  31. delete b2;
  32. delete c2;
  33. }
  34. int main(int argc, char* argv[])
  35. {
  36. Test();
  37. system("pause");
  38. return 0;
  39. }
本帖最后由 wsmysyn 于 2018-10-26 21:07 编辑
坐而言不如起而行

回复评论 (1)

后来搞明白了。。
实际上是C++的一种隐式转换

CB b1 = new CB();

等同于 -->
CB* temp = new CB();
CB b1(temp);

因为CB的构造函数传入类型是void*,new 返回的也是void*类型,所以默认尝试做了一个隐式转换,将临时对象,作为构造函数的参数,传递进去了。并在栈上做了创建了一个对象,所以可以通过编译(可能并不是你想要的这种结果,但却是发生了)

所以,构造函数是4次,多了一次隐式的对象构造;在析构的时候,临时对象并没有被析构掉,造成了内存泄露

尤其是单参构造函数出现隐式转换的几率比较大,可能会有意想不到的bug。避免这种隐式的转换是在构造函数前加上explicit 禁止隐式转换。

坐而言不如起而行
点赞  2018-10-29 12:48
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复