为什么构造函数在C++中被调用了两次
Why is the constructor called twice in C++?
在这段代码中,构造函数被调用两次。
我该如何避免这种情况?
如果我取消对默认构造函数代码块的注释,则代码不会给出令人满意的输出。。
我还想要基于条件的模板实例化,所以我使用了void指针。
#include<iostream.h>
template<class Type>
class Data{
public:
Type val;
Data(Type v){
cout<<"In Constructor Param";
val = v;
}
Data(){
// cout<<"In Constructor Defa"; uncommnet this line
}
~Data(){}
};
int main(){
Data<void *> obj;
obj = new Data<float>(31.34f);
cout<<*(float*)obj.val;
}
输出:
In Constructor Param
In Constructor Param
31.34
谢谢你的参与。
第一个调用应该是显而易见的:在对new Data<float>(31.34f)
的调用中。
第二个是在下一行中构造的Data<void*>
类型的临时对象中。您的代码等效于以下内容:
Data<void *> obj;
Data<float> *t1 = new Data<float>(31.34f); //first!
void *t2 = t1;
Data<void *> t3(t2); //second!
Data<void *> t4(t3); //copy constructor (elided)
obj = t4; //operator=
cout<<*(float*)obj.val;
值得注意的是,最后一行的演员阵容可能不是你想要的。那就是:
cout << ((Data<float*>)obj.val).val;
或者类似的。
编译器为您隐式声明了一个复制构造函数。接下来,您的Data
可以从Type
隐式转换,在void*
的情况下,它可以从任何其他指针隐式转换。让我们来分解一下:
Data<void*> obj;
Data<float>* new_obj = new Data<float>(31.34f); // your call to new
// the constructor is called the first time here
void* conv1 = new_obj; // implicit conversion to void*
Data<void*> conv2 = conv1; // implicit conversion from 'Type' (aka 'void*')
// the constructor is called the second time here
obj = conv2; // copy constructor
此外,行cout<<*(float*)obj.val;
调用C++98/03中的未定义行为(您的编译器似乎比它老得多),因为您的val
实际上是Data<float>*
,而不是float*
。你应该把它作为
cout << static_cast<Data<float>*>(obj.val)->val;
因为您正在创建三个对象。您的代码包含通过转换构造函数Data<void*>::Data(void*)
从Data<float>*
到Data<void*>
的隐式转换,相当于
Data<void *> obj; // first object
Data<float> * temp = new Data<float>(31.34f); // second object
obj = Data<void *>((void*)temp); // third (temporary) object
我不知道如何避免这种情况,因为我不知道你的代码试图做什么。你可以通过声明构造函数explicit
来防止类似的奇怪转换,这样它就不允许隐式转换。
此外,你用来学习C++的任何一本书都已经过时了。自1998年(可能更早)以来,标准I/O头被称为<iostream>
,没有.h
,所有标准库的名称(如cout
)都在namespace std
中。
Data<void *> obj;
使用传递new Data
作为参数值的参数化构造函数构造一个Data对象以存储void *
类型。obj
本身需要是一个指针:
#include <iostream>
int main(){
Data<float> *obj = new Data<float>(31.34f);
std::cout << obj->val;
}
您的版本相当于:
Data<void *> objs; // no param constructor
/* Data<float>(31.34f); param constructor */
obj = Data<void *>(new Data<float>(31.34f)); // param constructor
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- C++析构函数调用两次,堆栈分配的复合对象
- Qt插槽调用了两次
- 对于优化级别为 0 的 std::vector,析构函数被调用两次
- 为什么转换运算符调用复制构造函数两次,而等效函数只调用它一次
- 调用一个小函数两次(例如在if条件和主体中)比将结果存储在局部变量中更可取
- 为什么这个自定义分配器的析构函数在 GCC/MSVS 的 stdlib 中被调用两次
- 插槽调用了两次qt
- 调用某个回调函数两次会导致分段错误:Nan
- 基于 MFC 对话框的应用程序无法调用对话框两次
- 重载运算符 new(),为什么构造函数被调用两次?
- 当 reset() 被unique_ptr调用两次时会发生什么?
- 为什么在C 中超载邮政增量运算符两次调用构造函数
- 现代C++编译器是否能够避免在某些条件下两次调用常量函数
- 如果我对async_read进行两次调用,那么只有在处理完第一次调用之后,才会处理第二次调用,这是否安全
- 如何正确地将对象添加到向量,而无需两次调用析构函数
- boost::asio vs. libpcap:避免两次调用关闭
- 为什么 DNSServiceProcessResult 两次调用我的回调
- 在资源管理器左窗格上两次调用Windows 7外壳扩展dll Initialize方法
- 通过连续两次调用boost::asio::read来检索正确的数据