没有默认构造函数的对象数组初始化

时间:2011-01-21 02:08:50

标签: c++ arrays constructor

#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()构造函数公开的情况下进行初始化?

11 个答案:

答案 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)
    };
}