为什么构造函数在C ++中调用了两次?

时间:2012-03-07 15:35:40

标签: c++ templates

在此代码中,构造函数被调用两次。

我该如何避免?

如果我取消注释默认的构造函数代码块,那么代码就不会给出令人满意的输出..

我还想要基于条件的模板实例化,所以我使用了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

感谢您的参与。

4 个答案:

答案 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