#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()构造函数公开的情况下进行初始化?
答案 0 :(得分:59)
您可以像这样使用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项 - 避免无偿的默认构造函数
答案 1 :(得分:36)
不。
但是!如果您使用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 :(得分:18)
您可以创建一个指针数组。
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];
}
答案 3 :(得分:4)
不,没有。 New-expression只允许默认初始化或根本不进行初始化。
解决方法是使用operator new[]
分配原始内存缓冲区,然后使用placement-new和非默认构造函数在该缓冲区中构造对象。
答案 4 :(得分:4)
好问题。我有同样的问题,在这里找到了。真正的答案是,@ 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) {} // for single declarations 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);
这样可以很好地自然流动,而不会让代码看起来很混乱。
现在,对于那些想知道如何声明需要初始化的对象数组的人来说,这是我的答案。
具体来说,你是在尝试给出一系列汽车身份,我想你总是想要独一无二。你可以用我上面解释过的方法做到这一点,然后在for
循环中使用i+1
作为发送到set
方法的参数 - 但是我从中读到了您的评论,似乎您希望ID更多地在内部启动,因此默认情况下,每个Car都有唯一的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()<<" "; // prints "1 2 3 4 5 6 7 8 9 10"
通过这种方式,您不必担心启动身份,因为它们是在内部管理的。
答案 5 :(得分:3)
您可以随时创建一个指针数组,指向汽车对象,然后在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;
}
所有你必须改变的新方法是将汽车作为指针处理而不是静态对象 in参数和调用方法时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
希望我帮助,欢呼!
答案 6 :(得分:3)
在C ++ 11&#39; 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
超出范围时,将自动删除。
答案 7 :(得分:2)
解决的一种方法是给出一个静态工厂方法来分配数组,如果由于某种原因你想给构造函数私有。
static Car* Car::CreateCarArray(int dimensions)
但是你为什么要将一个构造函数保持为公共和其他私有?
但无论如何还有一种方法是使用默认值
声明公共构造函数#define DEFAULT_CAR_INIT 0
Car::Car(int _no=DEFAULT_CAR_INIT);
答案 8 :(得分:1)
我不认为有类型安全的方法可以做你想要的。
答案 9 :(得分:0)
您可以使用新的就地操作员。这会有点可怕,我建议你留在工厂里。
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;
}
并定义相应的destroy以匹配此中使用的新内容。
答案 10 :(得分:0)
我的方式
Car * cars;
// else were
extern Car * cars;
void main()
{
// COLORS == id
cars = new Car[3] {
Car(BLUE),
Car(RED),
Car(GREEN)
};
}