在此代码中,构造函数被调用两次。
我该如何避免?
如果我取消注释默认的构造函数代码块,那么代码就不会给出令人满意的输出..
我还想要基于条件的模板实例化,所以我使用了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
感谢您的参与。
答案 0 :(得分:6)
第一个电话应该是显而易见的:正在调用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;
或类似。
答案 1 :(得分:5)
编译器为您隐式声明了一个复制构造函数。接下来,您的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;
答案 2 :(得分:4)
Data<void *> obj;
使用参数化构造函数传递void *
作为参数值,构造一个Data对象来存储new Data
类型。 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
答案 3 :(得分:4)
因为您正在创建三个对象。您的代码包含从Data<float>*
到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
我不知道如何避免这种情况,因为我不知道你的代码试图做什么。您可以通过声明构造函数explicit
来阻止这种奇怪的转换,这样它就不允许隐式转换。
此外,无论您使用哪本书来学习C ++都已经过时了。自1998年(可能更早)以来,标准I / O标头被称为<iostream>
而没有.h
,所有标准库的名称(如cout
)都在namespace std
中