#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;
}
車の配列を作成したいのですが、次のエラーが表示されます。
cartest.cpp: In function ‘int main()’:
cartest.cpp:5: error: ‘Car::Car()’ is private
cartest.cpp:21: error: within this context
car()コンストラクタを公開せずにこの初期化を行う方法はありますか?
いや。
しかし、lo! std::vector<Car>
を使用する必要がある場合(new[]
を使用しないでください)、要素の作成方法を正確に指定できます*。
*まあまあ。コピーする値を指定できます。
このような:
#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
}
追加機能:
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());
}
注printCarNumbers
は、範囲を示す2つの反復子を受け入れるために、実際には異なる設計にする必要があります。
次のように、placement-newを使用できます。
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;
}
より効果的なC++からの参照-Scott Meyers:
項目4-不要なデフォルトコンストラクターを避ける
ポインターの配列を作成できます。
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;
または
Car()コンストラクターはパブリックである必要はありません。配列を構築するクラスに静的メソッドを追加します。
static Car* makeArray(int length){
return new Car[length];
}
いいえ、ありません。 New-expressionは、デフォルトの初期化のみを許可するか、初期化をまったく許可しません。
回避策は、operator new[]
を使用して生メモリバッファを割り当て、次に、デフォルト以外のコンストラクタを使用して、placement-newを使用してそのバッファにオブジェクトを構築することです。
良い質問。私は同じ質問をして、それをここで見つけました。本当の答えは、@ Dan-Paradoxです。これを行うための標準的な構文方法はありません。したがって、これらの答えはすべて、問題を回避するためのさまざまな選択肢です。
私は答えを自分で読みましたが、私の個人的な慣習に完璧なものは特に見つかりませんでした。おそらく私が固執するメソッドは、デフォルトのコンストラクターとset
メソッドを使用しています。
class MyClass { int x、y、z; public: MyClass():x(0)、y(0) 、z(0) {} MyClass(int _x、int _y、int _z):x(_x)、y(_y)、z(_z){}//単一宣言の場合 void set(int _x、int _y、int _z) { x = _x; y = _y; z = _z; } };
標準の初期化コンストラクターはまだ存在するため、複数必要ない場合は通常どおり初期化できますが、そうでない場合は、コンストラクターで初期化されるすべての変数を設定するset
メソッドがあります。したがって、私はこのようなことをすることができます:
int len = 25; MyClass list = new MyClass [len]; for(int i = 0; i <len; i ++) list [i ] .set(1,2,3);
これは、コードを混乱させることなく正常に機能し、自然に流れます。
これが、初期化する必要のあるオブジェクトの配列をどのように宣言するのか疑問に思う人への私の答えです。
具体的には、車のIDの配列を提供しようとしていますが、これは常に一意である必要があります。上記で説明した私の方法でそれを行うことができ、for
ループでi+1
はset
メソッドに送信される引数として-しかし、私があなたのコメントで読んだことから、IDをより内部的に開始したいようです。他の誰かがあなたのクラスCar
を使用している場合。
これが必要な場合は、静的メンバーを使用できます。
class Car { static int current_id; int id; public: Car():id(current_id ++) {} int getId(){return id; } }; int Car :: current_id = 1; ... int cars = 10; Car * carlist = new Car [cars]; for(int i = 0; i <cars; i ++) cout << carlist [i]。 getId()<< ""; // "1 2 3 4 5 6 7 8 9 10" を出力します
このように、IDは内部で管理されるため、IDの開始について心配する必要はありません。
いつでもポインタの配列を作成し、車のオブジェクトをポイントしてから、必要に応じてforループでオブジェクトを作成し、そのアドレスを配列に保存できます。
#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);
新しい方法に注意してください!!!
printCarNumbers_new(mycars,userInput);
return 0;
}
新しいメソッドで変更する必要があるのは、パラメータ内の静的オブジェクトよりもポインタとして車を処理することと、たとえばprintNo()メソッドを呼び出す場合です:
void printCarNumbers_new(Car **cars, int length)
{
for(int i = 0; i<length;i++)
std::cout<<cars[i]->printNo();
}
mainの最後で、このように動的に割り当てられたすべてのメモリを削除するとよい
for(i=0;i<userInput;i++)
delete mycars[i]; //deleting one obgject
delete[] mycars; //deleting array of objects
応援してくれてありがとう!
C++ 11のstd::vector
emplace_back
:
std::vector<Car> mycars;
for (int i = 0; i < userInput; ++i)
{
mycars.emplace_back(i + 1); // pass in Car() constructor arguments
}
出来上がり!
Car()デフォルトコンストラクターは呼び出されません。
mycars
が範囲外になると、削除が自動的に行われます。
解決方法の1つは、何らかの理由でコンストラクタをプライベートにしたい場合に、静的ファクトリメソッドを与えて配列を割り当てることです。
static Car* Car::CreateCarArray(int dimensions)
しかし、なぜ1つのコンストラクターをパブリックにし、他のコンストラクターをプライベートにしているのですか?
しかし、とにかくもう1つの方法は、パブリックコンストラクタをデフォルト値で宣言することです
#define DEFAULT_CAR_INIT 0
Car::Car(int _no=DEFAULT_CAR_INIT);
私はあなたが望むことを行うことができるタイプセーフな方法があるとは思わない。
私のやり方
Car * cars;
// else were
extern Car * cars;
void main()
{
// COLORS == id
cars = new Car[3] {
Car(BLUE),
Car(RED),
Car(GREEN)
};
}
インプレース演算子newを使用できます。これは少し恐ろしいことなので、工場に保管することをお勧めします。
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;
}
そして、これで使用される新しいものと一致するように、対応する破棄を定義します。