Почему конструктор вызывается дважды в C ++? - PullRequest
5 голосов
/ 07 марта 2012

В этом коде конструктор вызывается дважды.

Как мне этого избежать?

Если я раскомментирую кодовый блок конструктора по умолчанию, то код не даст удовлетворительного вывода.

И я также хочу создание шаблона на основе условий, поэтому я использовал указатель 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 ]

6 голосов
/ 07 марта 2012

Первый вызов должен быть очевиден: находится в вызове 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;

или аналогичный.

5 голосов
/ 07 марта 2012

Компилятор неявно объявляет для вас конструктор копирования.Затем ваш 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;
4 голосов
/ 07 марта 2012

Потому что вы создаете три объекта.Ваш код содержит неявное преобразование из 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 года (и, возможно, ранее) стандартный заголовок ввода-вывода назывался <iostream> без .h, а все имена стандартных библиотек, такие как cout, были в namespace std.

4 голосов
/ 07 марта 2012

Data<void *> obj; создает объект данных для хранения типа void *, используя параметризованный конструктор, передавая 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...