简体   繁体   中英

Why is the constructor called twice in C++?

In this code the constructor is called twice.

How do I avoid that?

If I uncomment the default constructor code block then code does not give satisfactory output..

And I also want conditional based instantiation of template so I used void pointer.

#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;
}

Output:

In Constructor Param
In Constructor Param
31.34

Thanks for involving.

The first call should be obvious: is in the call to new Data<float>(31.34f) .

The second one is in a temporary object of type Data<void*> that is constructed in the next line. Your code is equivalent to the following:

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;

It is worth noting that the last line does a cast that is not probably what you want. That would be:

cout << ((Data<float*>)obj.val).val;

Or similar.

The compiler implicitly declares a copy constructor for you. Next, your Data is implicitly convertible from Type , which in case of void* is implicitly convertible from any other pointer. Let's break this down:

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

Also, the line cout<<*(float*)obj.val; is invoking undefined behaviour in C++98/03 (and your compiler seems to be much older than that), as your val actually is a Data<float>* , and not a float* . You should have that as

cout << static_cast<Data<float>*>(obj.val)->val;

Data<void *> obj; constructs a Data object to store void * type using the parameterized constructor passing new Data as the parameter value. obj itself needs to be a pointer:

#include <iostream>

int main(){
    Data<float> *obj = new Data<float>(31.34f);
    std::cout << obj->val;
}

Your version is equivalent to:

Data<void *> objs; // no param constructor
/* Data<float>(31.34f); param constructor */
obj = Data<void *>(new Data<float>(31.34f)); // param constructor

Because you are creating three objects. Your code contains an implicit conversion from Data<float>* to Data<void*> , via the conversion constructor Data<void*>::Data(void*) , and is equivalent to

Data<void *> obj;                              // first object
Data<float> * temp = new Data<float>(31.34f);  // second object
obj = Data<void *>((void*)temp);               // third (temporary) object

I've no idea how to avoid that, because I've no idea what your code is trying to do. You could prevent weird conversions like that by declaring the constructor explicit , so that it doesn't allow implicit conversions.

Also, whichever book you're using to learn C++ is very outdated. Since 1998 (and possibly earlier), the standard I/O header has been called <iostream> with no .h , and all the standard library's names like cout have been in namespace std .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM