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

Mah*_*iya 5 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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

In Constructor Param
In Constructor Param
31.34
Run Code Online (Sandbox Code Playgroud)

谢谢你的参与.

rod*_*igo 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;
Run Code Online (Sandbox Code Playgroud)

值得注意的是,最后一行的演员阵容可能不是你想要的.那将是:

cout << ((Data<float*>)obj.val).val;
Run Code Online (Sandbox Code Playgroud)

或类似的.


Xeo*_*Xeo 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
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)

  • @Xeo:实际上它不是*在C++ 11中未定义; 在指向标准布局类的指针和指向其第一个成员的指针之间进行转换是很明确的.不是说我建议任何人都这样做. (2认同)

Mik*_*our 4

因为您正在创建三个对象。您的代码包含通过转换构造函数从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