本帖最后由 wsmysyn 于 2018-10-26 21:07 编辑
如题,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的标准,但是并没有找到地方
网上暂时也没搜到这类的描述,(可能提问的姿势不对...)
代码:
运行结果:
- class CA
- {
- public:
- CA() { std::cout << "Class A" << std::endl; };
- ~CA() { std::cout << "Class A die..." << std::endl; };
- };
- class CB
- {
- public:
- CB(void* pVOID = NULL) { std::cout << "Class B" << std::endl; };
- ~CB() { std::cout << "Class B die..." << std::endl; };
- };
- class CC
- {
- public:
- CC(int* pLength = NULL) { std::cout << "Class C" << std::endl; }
- ~CC() { std::cout << "Class C die..." << std::endl; };
- };
- void Test(void)
- {
- CA a0;
- //CA a1 = new CA();
- CA* a2 = new CA();
- CB b0;
- CB b1 = new CB();
- CB* b2 = new CB();
- CC c0;
- //CC c1 = new CC();
- CC* c2 = new CC();
- delete a2;
- delete b2;
- delete c2;
- }
- int main(int argc, char* argv[])
- {
- Test();
- system("pause");
- return 0;
- }
复制代码
此帖出自
小平头技术问答
实际上是C++的一种隐式转换
CB b1 = new CB();
等同于 -->
CB* temp = new CB();
CB b1(temp);
因为CB的构造函数传入类型是void*,new 返回的也是void*类型,所以默认尝试做了一个隐式转换,将临时对象,作为构造函数的参数,传递进去了。并在栈上做了创建了一个对象,所以可以通过编译(可能并不是你想要的这种结果,但却是发生了)
所以,构造函数是4次,多了一次隐式的对象构造;在析构的时候,临时对象并没有被析构掉,造成了内存泄露
尤其是单参构造函数出现隐式转换的几率比较大,可能会有意想不到的bug。避免这种隐式的转换是在构造函数前加上explicit 禁止隐式转换。
一周热门 更多>