Inicialización de matriz de objetos sin constructor predeterminado

#include  class Car { private: Car(){}; int _no; public: Car(int no) { _no=no; } void printNo() { std::cout<<_no<<std::endl; } }; void printCarNumbers(Car *cars, int length) { for(int i = 0; i<length;i++) std::cout<<cars[i].printNo(); } int main() { int userInput = 10; Car *mycars = new Car[userInput]; for(int i =0;i < userInput;i++) mycars[i]=new Car[i+1]; printCarNumbers(mycars,userInput); return 0; } 

Quiero crear una matriz de automóviles, pero me aparece el siguiente error:

 cartest.cpp: In function 'int main()': cartest.cpp:5: error: 'Car::Car()' is private cartest.cpp:21: error: within this context 

¿Hay alguna manera de hacer esta inicialización sin hacer que el constructor de Car () sea público?

Nop.

Pero lo! Si usa std::vector , como debería ser (nunca use new[] ), puede especificar exactamente cómo se deben construir los elementos *.

*Especie de. Puede especificar el valor para hacer copias de.


Me gusta esto:

 #include  #include  class Car { private: Car(); // if you don't use it, you can just declare it to make it private int _no; public: Car(int no) : _no(no) { // use an initialization list to initialize members, // not the constructor body to assign them } void printNo() { // use whitespace, itmakesthingseasiertoread std::cout << _no << std::endl; } }; int main() { int userInput = 10; // first method: userInput copies of Car(5) std::vector mycars(userInput, Car(5)); // second method: std::vector mycars; // empty mycars.reserve(userInput); // optional: reserve the memory upfront for (int i = 0; i < userInput; ++i) mycars.push_back(Car(i)); // ith element is a copy of this // return 0 is implicit on main's with no return statement, // useful for snippets and short code samples } 

Con la función adicional:

 void printCarNumbers(Car *cars, int length) { for(int i = 0; i < length; i++) // whitespace! :) std::cout << cars[i].printNo(); } int main() { // ... printCarNumbers(&mycars[0], mycars.size()); } 

Nota printCarNumbers realmente debe diseñarse de manera diferente, para aceptar dos iteradores que denotan un rango.

Puede usar placement-new como este:

 class Car { int _no; public: Car( int no ) :_no( no ) { } }; int main() { void* raw_memory = operator new[]( NUM_CARS * sizeof( Car ) ); Car* ptr = static_cast( raw_memory ); for( int i = 0; i < NUM_CARS; ++i ) { new( &ptr[i] )Car( i ); } // destruct in inverse order for( int i = NUM_CARS - 1; i >= 0; --i ) { ptr[i].~Car(); } operator delete[]( raw_memory ); return 0; } 

Referencia de C ++ más efectivo – Scott Meyers:
Punto 4 – Evita los constructores por defecto gratuitos

Puede crear una matriz de punteros.

 Car** mycars = new Car*[userInput]; for (int i=0; i 

o

El constructor de Car () no necesita ser público. Agregue un método estático a su clase que construye una matriz:

 static Car* makeArray(int length){ return new Car[length]; } 

No, no hay. Nueva expresión solo permite la inicialización predeterminada o ninguna inicialización.

La solución consistiría en asignar el búfer de memoria sin formato utilizando el operator new[] y luego construir objetos en ese búfer utilizando placement-new con un constructor no predeterminado.

Buena pregunta. Tenía la misma pregunta y la encontré aquí. La verdadera respuesta es, @ Dan-Paradox, no existe una forma sintáctica estándar de hacerlo. Entonces, todas estas respuestas son una variedad de alternativas para evitar el problema.

Leí las respuestas yo mismo, y no encontré particularmente ninguna de ellas perfecta para mi convención personal. El método con el que probablemente me quedaré es usar un constructor predeterminado y un método set :

 clase MyClass
 {
   int x, y, z;
 público:
   MyClass (): x (0), y (0), z (0) {}
   MyClass (int _x, int _y, int _z): x (_x), y (_y), z (_z) {} // para declaraciones individuales
   conjunto de vacíos (int _x, int _y, int _z)
   {
     x = _x;
     y = _y;
     z = _z;
   }
 };

El constructor de inicialización estándar todavía está allí, así que aún puedo inicializarlo normalmente si no necesito más de uno, pero si no, tengo un método de set que establece todas las variables que se inicializan en el constructor. Por lo tanto, podría hacer algo como esto:

 int len ​​= 25;
 MyClass list = new MyClass [len];
 para (int i = 0; i 

Esto funciona bien y fluye de forma natural, sin hacer que el código parezca confuso.


Ahora esa es mi respuesta para aquellos que se preguntan cómo declarar una matriz de objetos que deben inicializarse.

Específicamente para ti, estás tratando de dar una gran variedad de identidades de autos, lo que supongo que siempre deseas ser único. Podrías hacerlo con mi método que expliqué anteriormente, y luego en el ciclo for use i+1 como el argumento enviado al método set , pero por lo que he leído en tus comentarios, parece que quieres los identificadores internamente. iniciado, por lo que, de forma predeterminada, cada automóvil tiene una identificación única, incluso si otra persona usa su Car clase.

Si esto es lo que quiere, puede usar un miembro estático:

 clase coche
 {
   static int current_id;
   int id;
 público:
   Car (): id (current_id ++) {}

   int getId () {return id;  }
 };
 int Car :: current_id = 1;

 ...

 int cars = 10;
 Car * carlist = new Car [autos];

 para (int i = 0; i 

De esta forma, no tiene que preocuparse en absoluto por iniciar las identidades, ya que se administran internamente.

Siempre puede crear una matriz de punteros, señalar los objetos del automóvil y luego crear objetos, en un ciclo for, como desee y guardar su dirección en la matriz, por ejemplo:

 #include  class Car { private: Car(){}; int _no; public: Car(int no) { _no=no; } void printNo() { std::cout<<_no< 

nota nuevo método !!!

  printCarNumbers_new(mycars,userInput); return 0; } 

Todo lo que tiene que cambiar en el nuevo método es manejar los automóviles como punteros que los objetos estáticos en el parámetro y al llamar al método printNo (), por ejemplo:

 void printCarNumbers_new(Car **cars, int length) { for(int i = 0; iprintNo(); } 

al final de main es bueno borrar toda la memoria asignada dinámicamente como esta

 for(i=0;i 

Espero haber ayudado, ¡salud!

En std::vector C ++ 11 puede crear instancias de elementos en emplace_back usando emplace_back :

  std::vector mycars; for (int i = 0; i < userInput; ++i) { mycars.emplace_back(i + 1); // pass in Car() constructor arguments } 

Voila!

El constructor predeterminado de Car () nunca se invoca.

La eliminación se producirá automáticamente cuando mycars fuera del scope.

Una forma de resolverlo es dar un método de fábrica estático para asignar la matriz si por alguna razón desea dar al constructor privacidad.

 static Car* Car::CreateCarArray(int dimensions) 

¿Pero por qué estás manteniendo un constructor público y otro privado?

Pero de todos modos una forma más es declarar el constructor público con valor predeterminado

 #define DEFAULT_CAR_INIT 0 Car::Car(int _no=DEFAULT_CAR_INIT); 

No creo que haya un método de tipo seguro que pueda hacer lo que quieras.

Puede usar el operador in situ nuevo. Esto sería un poco horrible, y recomendaría quedarse en una fábrica.

 Car* createCars(unsigned number) { if (number == 0 ) return 0; Car* cars = reinterpret_cast(new char[sizeof(Car)* number]); for(unsigned carId = 0; carId != number; ++carId) { new(cars+carId) Car(carId); } return cars; } 

Y defina una destrucción correspondiente para que coincida con la nueva utilizada en esto.

Mi manera

 Car * cars; // else were extern Car * cars; void main() { // COLORS == id cars = new Car[3] { Car(BLUE), Car(RED), Car(GREEN) }; }