#include <iostream>
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 un coche de la matriz, pero me sale 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 una manera de hacer esta inicialización sin hacer de Coche() constructor público?

  • operator new [] siempre invoca el constructor por defecto. Pero C++11 tiene una solución, como se muestra siguiente.
InformationsquelleAutor Dan Paradox | 2011-01-21

11 Comentarios

  1. 37

    Nope.

    Pero ¡oh! Si utiliza std::vector<Car>, como debe ser (no usar nunca new[]), entonces usted puede especificar exactamente cómo los elementos deben ser construidas*.

    *Bien una especie de. Puede especificar el valor de que para hacer copias de.


    Como este:

    #include <iostream>
    #include <vector>
    
    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<Car> mycars(userInput, Car(5)); 
    
        //second method:
        std::vector<Car> 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 ser diseñado de manera diferente, para que acepte dos iteradores que denota un rango.

    • Esta realidad no lo necesito, pero utilizando el vector no es una opción. Se debe Coche porque tengo otro método que toma *Coche no std::vector<Auto>
    • Usted puede utilizar &mycars[0] para obtener un puntero a la base de la matriz. A pesar de que, generalmente, sólo útil para pasarlo a código heredado que no uso std::vector, usted debe actualizar ese requisito si se puede.
    • Bajo nivel de la API a menudo toman un tampón y a veces necesitan ser grandes (por ejemplo, la transferencia de datos desde un frame grabber). A veces no se puede evitar, pero tienes razón, en la gran mayoría de los casos +1
    • De hecho. Mi conjetura es que el requisito puede cambiar, sin embargo, porque dudo que el API realmente necesita Car*. Tal vez void*, sin embargo, y era sólo vagamente, dijo. 🙂
    • Las opciones son muy malas. Tengo que hacer el Coche() pública o cambiar el parámetro de entrada solo para definir un array de punteros
    • ¿De qué estás hablando? ¿Ven a lo que me dijo que usted puede utilizar &mycars[0]? Por qué no haces tu pregunta contener el todo problema lo podemos resolver toda la cosa?
    • lo siento por la confusión. He añadido una función printCarNumbers() que lo utiliza. Espero que aclara las cosas. No deseo cambiar los parámetros de printCarNumbers().
    • Bien. De hecho, he actualizado la respuesta.
    • He probado este ShareText.org/BFQ pero tengo un montón de bajo nivel de error
    • No hay nada malo con el código que has publicado. Editar tu pregunta con el código que se trató de y los errores que usted consigue. Tenga en cuenta que la línea debe ser de printCarNumbers(&mycars[0], mycars.size()); y no printCarNumbers(&mycars[0],userInput);. Mientras esto pasa a ser el mismo en este ejemplo, lo que queremos transmitir es el tamaño del vector, por lo que, simplemente porque pasan a ser el mismo valor en este caso en particular no significa que usted debe desviarse desde el enfoque más correcto.
    • He publicado el error y el código de
    • es completamente de mi error acerca de la compilación. Ya lo he conseguido. Gracias.
    • Hey vamos chicos tenemos c++11 ahora, en lugar de &mycars[0] vamos a utilizar el equivalente mycars.data() que es oh tan mucho más legible.

  2. 59

    Puede utilizar colocación de nuevo como esto:

    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<Car*>( 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;
    }

    La referencia de la Más Eficaz de C++ – Scott Meyers:

    Tema 4 – Evitar la gratuidad de los constructores predeterminados

    • Por qué destruir en el orden inverso?
    • Debido a que fue construido en enviar la orden. La última cosa construido debe ser la primera cosa que se destruye.
    • la regla de oro es necesario para asegurar el correcto orden de destrucción de los objetos que son dependientes los unos de los otros. En este caso particular, los objetos no tienen dependencias para que puedan ser destruido en el orden que debería ser un poco más rápido y caché de usar. La inversa de la iteración es generalmente de muy baja en términos de rendimiento en comparación con la de avance de la iteración.
    • ¿Cómo se puede hacer esta solución excepción segura? I. e., lo que si es un constructor de Coches lanza una excepción para algunos que yo? Supongo que uno tiene que atrapar la excepción, deconstruir todos los ya construidos del Coche en orden inverso, y rethrow…
    • qué va a pasar, si hago sólo delete [] ptr; al final?
    • Tengo curiosidad así. Qué tenemos que llamar a los destructores de forma manual, o a la delete[] ptr; llamada por nosotros?
    • De acuerdo a un experimento en el VS de 2015, que dará lugar a un bucle sin fin.
    • OMG. Eso es algo feo pieza de código. No hacer esto.
    • Dejar una cosa bien clara: incluso si delete[] ¿ trabajo – en caso de excepción durante la construcción, sería destruir el no ha creado objetos, también – un comportamiento indefinido…
    • que puede bloquearse en PowerPC / Itanium. Porque int requisito de alineación es de 4, y raw_memory no da mucho más de garantía en la que (depende de la asignación). Se da la circunstancia de que el stdlib del malloc alinea a 16 por lo que funciona con casi todo.
    • La ubicación de la memoria devuelto por malloc y operador de nuevo está garantizado para estar debidamente alineados, de modo que puede ser convertido a un puntero de cualquier objeto completo y acceder a ellos como matriz de objetos. En otras palabras, no hay ningún problema de alineación de aquí.

  3. 18

    Puede crear un array de punteros.

    Car** mycars = new Car*[userInput];
    for (int i=0; i<userInput; i++){
        mycars[i] = new Car(...);
    }
    
    ...
    
    for (int i=0; i<userInput; i++){
        delete mycars[i];
    }
    delete [] mycars;

    o

    Coche() constructor no necesita ser público. Agregar un método estático de la clase que construye una matriz:

    static Car* makeArray(int length){
        return new Car[length];
    }
    • Esto tiende a ser más limpio que el de la colocación de la nueva opción, PERO ¿qué hay de código que quiere un Car * ?
    • Me han seleccionado este como el derecho de respuesta +1
  4. 4

    No, No la hay. Nueva expresión sólo permite la inicialización predeterminada o no de inicialización en todo.

    La solución sería asignar primas búfer de memoria utilizando operator new[] y, a continuación, construir objetos en que búfer mediante la colocación de nuevo con los no-constructor predeterminado.

    • Por supuesto, debemos utilizar std::vector, que hace esto. Pero +1 por la corrección.
    • ¿Cómo puedo asignar primas de memoria con el operador new[] ? Cualquier enlace que explica que?
    • Paradoja: Hay un ejemplo en el Chan de la respuesta.
    • ITYM que la matriz nueva forma de expresión sólo se permite por defecto-inicialización, A *a = new A(args); está bien. También esta respuesta podría ser actualizado para C++11
  5. 4

    Buena pregunta. Yo tenía la misma pregunta, y la encontré aquí. La verdadera respuesta es, @Dan-Paradoja, no hay ninguna norma sintáctica manera de hacerlo. Así, todas estas respuestas son una variedad de alternativas para solucionar el problema.

    He leído las respuestas a mí mismo, y no particularmente a encontrar alguno de ellos perfecto para mi personal convención. El método que he probable que me quedo es con el uso de un constructor predeterminado y un set método:

    de la clase Miclase 
    { 
    int x,y,z; 
    público: 
    Miclase(): x(0), y(0), z(0) {} 
    Miclase(int _x,int _y,int _z): x(_x), y(_y), z(_z) {} //para una sola de las declaraciones 
    void set(int _x,int _y,int _z) 
    { 
    x=_x; 
    y=_y; 
    z=_z; 
    } 
    }; 
    

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

    int len=25; 
    Miclase lista = new Miclase[len]; 
    for(int i = 0; i < len; i++) 
    lista[i].set(1,2,3); 
    

    Esto funciona bien y fluye naturalmente, sin hacer que el código mirada confusa.


    Ahora esa es mi respuesta para los que se preguntan cómo declarar un array de objetos que deben ser inicializado.

    Específicamente para ti, que estás tratando de dar una gama de coches de identidades, que me gustaría suponga que desea ser siempre único. Podría hacerlo con mi método que he explicado anteriormente y, a continuación, en la for bucle de uso i+1 como el argumento que se envía a la set método – pero por lo que he leído en tus comentarios, parece que quieren que el ids más internamente iniciado, por lo que, por defecto, cada Coche tiene un identificador único, incluso si la otra persona usa su clase Car.

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

    de la clase de Coche 
    { 
    static int current_id; 
    int id; 
    público: 
    Coche(): id(current_id++) {} 
    
    int getId() { return id; } 
    }; 
    int Coche::current_id = 1; 
    
    ... 
    
    int coches=10; 
    Coche* carlista = new Coche[coches]; 
    
    for(int i = 0; i < coches; i++) 
    cout<<carlista[i].getId()<<" "; //imprime "1 2 3 4 5 6 7 8 9 10" 
    

    De esta manera, usted no tiene que preocuparse en absoluto acerca de la iniciación de las identidades, ya que se gestionan internamente.

    • Usted ha hecho su clase no-thread-safe mediante el uso de almacenamiento estático de la identidad de contador de bucle. Si sólo tienen que ser únicos dentro de cada colección, tiene más sentido utilizar una variable local para el bucle, por la eficiencia. Puede ser que no haya una manera correcta de expresar que en C++, sin embargo, esp. no con el incremento oculto en el interior del constructor.
  6. 3

    Siempre se puede crear un array de punteros , que apunta al carro de los objetos y, a continuación, crear objetos, en un bucle for, como quieras y guardar su dirección en la matriz , por ejemplo :

    #include <iostream>
    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];
      int i;
      for(i=0;i<userInput;i++)
          mycars[i] = new Car(i+1);

    nota nuevo método !!!

      printCarNumbers_new(mycars,userInput);
    
    
      return 0;
    }    

    Todo lo que tiene que cambiar en el nuevo método, es el manejo de los coches punteros de objetos estáticos
    en el parámetro y cuando se llama el método de printNo()
    por ejemplo :

    void printCarNumbers_new(Car **cars, int length)
    {
        for(int i = 0; i<length;i++)
             std::cout<<cars[i]->printNo();
    }

    al final de la principal que es bueno para eliminar todos los dynamicly memoria asignada como este

    for(i=0;i<userInput;i++)
      delete mycars[i];      //deleting one obgject
    delete[] mycars;         //deleting array of objects

    Espero ayudado, saludos!

  7. 3

    En C++11 std::vector puede crear instancias de los elementos en su lugar con emplace_back:

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

    Voila!

    Coche() constructor predeterminado nunca se invoca.

    Eliminación sucederá automáticamente cuando mycars sale del ámbito.

    • Me estoy enfrentando un problema similar como OP, pero mi mycars contiene una referencia, así que no puedo usar emplace_back (como es posible requiere el uso del operador de asignación, el cual no existe ya que las referencias son const). Así que, de vuelta a la OP de la pregunta original, no hay manera de crear instancias de cada uno de los elementos de una matriz, por no utilizar el constructor por defecto?
    • ¿Por qué necesita llamada al constructor de array de referencias
  8. 2

    Una forma de resolver es el de dar una fábrica estáticos método para asignar la matriz si por alguna razón usted desea dar constructor privado.

    static Car*  Car::CreateCarArray(int dimensions)

    Pero ¿por qué mantener 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);
    • Me hizo Coche() privado porque quiero evitar el constructor de copia
    • Pero eso no es un constructor de copia.
    • tienes razón, pero quiero evitar el constructor predeterminado de todos modos. Todos los vehículos deben tener un id
    • En ese caso, usted puede utilizar el método de fábrica con dimenions y la lista de inicialización. El método de fábrica sería la responsable de la creación y de la serie e inicializar el id de cada objeto. Función de inicialización también puede ser privado.
  9. 0

    Puede utilizar en lugar del operador new. Esto sería un poco horrible, y me gustaría recomendar el mantenimiento en una fábrica.

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

    Y definir correspondiente destruir tanto como para que coincida con el utilizado en el presente.

  10. 0

    Mi manera

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

Dejar respuesta

Please enter your comment!
Please enter your name here