Inicialização de array de objects sem construtor padrão

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

Eu quero criar uma matriz de carro, mas recebo o seguinte erro:

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

Existe uma maneira de fazer essa boot sem tornar o construtor Car () público?

Não.

Mas eis! Se você usa std::vector , como você deveria (nunca use new[] ), então você pode especificar exatamente como os elementos devem ser construídos *.

* Bem tipo de. Você pode especificar o valor do qual fazer cópias.


Como isso:

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

Com a function 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 deve ser projetado de forma diferente, para aceitar dois iteradores denotando um intervalo.

Você pode usar o posicionamento novo 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; } 

Referência de Mais Eficaz C ++ – Scott Meyers:
Item 4 – Evite construtores padrão gratuitos

Você pode criar uma matriz de pointers.

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

ou

O construtor Car () não precisa ser público. Adicione um método estático à sua class que cria uma matriz:

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

Não há. A nova expressão só permite a boot padrão ou nenhuma boot.

A solução alternativa seria alocar o buffer de memory bruta usando o operator new[] e, em seguida, construir objects nesse buffer usando o novo posicionamento com o construtor não padrão.

Boa pergunta. Eu tive a mesma pergunta e encontrei aqui. A verdadeira resposta é, @ Dan-Paradox, não há maneira sintática padrão de fazê-lo. Então, todas essas respostas são uma variedade de alternativas para contornar o problema.

Eu mesmo li as respostas e não achei particularmente nenhuma delas perfeita para minha convenção pessoal. O método que provavelmente usarei é um construtor padrão e um método set :

 class 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 declarações únicas
   void set (int _x, int _y, int _z)
   {
     x = _x;
     y = _y;
     z = _z;
   }
 };

O construtor de boot padrão ainda está lá, então ainda posso inicializá-lo normalmente se não precisar de mais de um, mas, caso contrário, tenho um método set que define todas as variables ​​que são inicializadas no construtor. Assim eu poderia fazer algo assim:

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

Isso funciona bem e flui naturalmente, sem tornar o código confuso.


Essa é a minha resposta para aqueles que querem saber como declarar uma matriz de objects que precisam ser inicializados.

Para você especificamente, você está tentando dar uma matriz de identidades de carros, que eu suponho que você quer sempre ser único. Você poderia fazer isso com o meu método que eu expliquei acima, e então no loop for use i+1 como o argumento enviado para o método set - mas pelo que eu li nos seus comentários, parece que você quer os ids mais internamente iniciado, de modo que, por padrão, cada carro tenha um ID exclusivo, mesmo que outra pessoa use sua class Car .

Se é isso que você quer, você pode usar um membro estático:

 carro da class
 {
   static int current_id;
   int id;
 público:
   Car (): id (current_id ++) {}

   int getId () {ID de retorno;  }
 };
 int Car :: current_id = 1;

 ...

 int carros = 10;
 Carro * carlista = carro novo [carros];

 para (int i = 0; i 

Dessa forma, você não precisa se preocupar em iniciar as identidades, pois elas são gerenciadas internamente.

Você sempre pode criar uma matriz de pointers, apontando para objects de carro e, em seguida, criar objects, em um loop for, como você deseja e salvar seu endereço na matriz, por exemplo:

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

note novo método !!!

  printCarNumbers_new(mycars,userInput); return 0; } 

Tudo que você tem que mudar no novo método é manipular carros como pointers do que objects estáticos no parâmetro e ao chamar o método printNo () por exemplo:

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

no final da principal é bom para apagar toda a memory alocada dinamicamente como este

 for(i=0;i 

Espero ter ajudado, vivas!

No std::vector do C ++ 11 você pode instanciar elementos no local usando emplace_back :

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

Voila!

Construtor padrão Car () nunca chamado.

A exclusão ocorrerá automaticamente quando o mycars ficar fora do escopo.

Uma maneira de resolver é fornecer um método de fábrica estático para alocar a matriz se, por algum motivo, você desejar fornecer o construtor como privado.

 static Car* Car::CreateCarArray(int dimensions) 

Mas por que você está mantendo um construtor público e outro privado?

Mas de qualquer forma mais uma maneira é declarar o construtor público com valor padrão

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

Eu não acho que há um método seguro de tipo que pode fazer o que você quer.

Você pode usar o operador no local novo. Isso seria um pouco horrível, e eu recomendo manter em uma 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; } 

E defina um correspondente correspondente, de modo a coincidir com o novo usado neste.

O meu caminho

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