IT TIP

기본 생성자없이 객체 배열 초기화

itqueen 2020. 12. 10. 21:34
반응형

기본 생성자없이 객체 배열 초기화


#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 () 생성자를 공개하지 않고이 초기화를 만드는 방법이 있습니까?


아니.

하지만 보라! 를 사용하는 경우 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정말 범위를 나타내는 두 반복자에 동의 다르게 설계되어야한다.


다음과 같이 새 배치를 사용할 수 있습니다.

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

좋은 질문. 저도 같은 질문을했는데 여기서 찾았습니다. 진짜 대답은 @ Dan-Paradox입니다. 표준 구문 론적 방법이 없습니다. 따라서이 모든 답변은 문제를 해결할 수있는 다양한 대안입니다.

나는 답을 직접 읽었고 특별히 내 개인 대회에 딱 맞는 답을 찾지 못했습니다. 내가 고수 할 방법은 기본 생성자와set 방법 메서드를 .

클래스 MyClass
{
  int x, y, z;
공공의:
  MyClass () : x (0), y (0), z (0) {}
  MyClass (int _x, int _y, int _z) : x (_x), y (_y), z (_z) {} // 단일 선언 용
  무효 세트 (int _x, int _y, int _z)
  {
    x = _x;
    y = _y;
    z = _z;
  }
};

표준 초기화 생성자는 여전히 거기에 있으므로 둘 이상이 필요하지 않으면 정상적으로 초기화 할 수 있지만 그렇지 않은 경우 set생성자에서 초기화되는 모든 변수를 설정 하는 메서드가 있습니다. 따라서 다음과 같이 할 수 있습니다.

int len ​​= 25;
MyClass 목록 = new MyClass [len];
for (int i = 0; i <len; i ++)
  목록 [i] .set (1,2,3);

이것은 코드를 혼동하지 않고 잘 작동하고 자연스럽게 흐릅니다.


이제 초기화해야 할 객체 배열을 선언하는 방법을 궁금해하는 사람들에 대한 대답입니다.

구체적으로 말하면, 당신은 자동차에 대한 일련의 신원을 부여하려고하는데, 저는 당신이 항상 독특하고 싶어한다고 생각합니다. 위에서 설명한 내 방법으로 할 수 있으며 for루프 i+1에서 set메서드로 보낸 인수로 사용할 수 있습니다. 하지만 귀하의 의견에서 읽은 내용에서 ID를 더 내부적으로 시작하려는 것 같습니다. 다른 사람이 클래스를 사용하더라도 기본적으로 각 Car에는 고유 한 ID가 있습니다 Car.

이것이 원하는 경우 정적 멤버를 사용할 수 있습니다.

클래스 자동차
{
  static int current_id;
  int id;
공공의:
  자동차 () : id (current_id ++) {}

  int getId () {반환 ID; }
};
int Car :: current_id = 1;

...

int cars = 10;
Car * carlist = 새 자동차 [자동차];

for (int i = 0; i <자동차; i ++)
  cout << carlist [i] .getId () << ""; // "1 2 3 4 5 6 7 8 9 10"인쇄

이렇게하면 ID가 내부적으로 관리되기 때문에 시작에 대해 전혀 걱정할 필요가 없습니다.


아니, 없습니다. New-expression은 기본 초기화 만 허용하거나 초기화를 전혀 허용하지 않습니다.

해결 방법은를 사용하여 원시 메모리 버퍼를 할당 operator new[]한 다음 기본이 아닌 생성자와 함께 place-new를 사용하여 해당 버퍼에서 객체를 생성하는 것입니다.


언제든지 car 객체를 가리키는 포인터 배열을 만든 다음 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

내가 도왔 으면 좋겠다, 건배!


In C++11's std::vector you can instantiate elements in-place using emplace_back:

  std::vector<Car> mycars;

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

Voila!

Car() default constructor never invoked.

Deletion will happen automatically when mycars goes out of scope.


One way to solve is to give a static factory method to allocate the array if for some reason you want to give constructor private.

static Car*  Car::CreateCarArray(int dimensions)

But why are you keeping one constructor public and other private?

But anyhow one more way is to declare the public constructor with default value

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

I don't think there's type-safe method that can do what you want.


My way

Car * cars;

// else were

extern Car * cars;

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

You can use in-place operator new. This would be a bit horrible, and I'd recommend keeping in a factory.

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

And define a corresponding destroy so as to match the new used in this.

참고URL : https://stackoverflow.com/questions/4754763/object-array-initialization-without-default-constructor

반응형