在此代码中,构造函数被调用两次.
我该如何避免?
如果我取消注释默认构造函数代码块,那么代码不会给出令人满意的输出.
而且我也想要基于条件的模板实例化,所以我使用了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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
In Constructor Param
In Constructor Param
31.34
Run Code Online (Sandbox Code Playgroud)
谢谢你的参与.
第一个电话应该是显而易见的:在电话中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;
Run Code Online (Sandbox Code Playgroud)
值得注意的是,最后一行的演员阵容可能不是你想要的.那将是:
cout << ((Data<float*>)obj.val).val;
Run Code Online (Sandbox Code Playgroud)
或类似的.
编译器为您隐式声明了一个复制构造函数.接下来,您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
Run Code Online (Sandbox Code Playgroud)
此外,该行在C++ cout<<*(float*)obj.val;98/03中调用未定义的行为(并且您的编译器似乎比它更老),因为您val 实际上是a Data<float>*,而不是a float*.你应该那样做
cout << static_cast<Data<float>*>(obj.val)->val;
Run Code Online (Sandbox Code Playgroud)
因为您正在创建三个对象。您的代码包含通过转换构造函数从Data<float>*to 的隐式转换,并且相当于Data<void*>Data<void*>::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
Run Code Online (Sandbox Code Playgroud)
我不知道如何避免这种情况,因为我不知道你的代码想要做什么。您可以通过声明构造函数来防止类似的奇怪转换explicit,这样它就不允许隐式转换。
而且,无论你用来学习 C++ 的哪本书都已经过时了。自 1998 年(可能更早)以来,标准 I/O 标头已<iostream>使用 no进行调用.h,并且所有标准库的名称cout都已在 中namespace std。