Как мне объявить массив с пользовательским классом? - PullRequest
13 голосов
/ 20 декабря 2011

Я пытаюсь объявить массив с пользовательским классом.Когда я добавил конструктор в класс, мой компилятор жалуется, что «нет подходящего конструктора для инициализации имени [3]».

Вот моя программа:

#include <iostream>

using namespace std;

class name {
  public:
    string first;
    string last;

  name(string a, string b){
    first = a;
    last = b;
  }
};

int main (int argc, const char * argv[])
{

  const int howManyNames = 3;

  name someName[howManyNames];

  return 0;
}

Что я могу сделать, чтобы запустить этот прогон, и что я делаю не так?

Ответы [ 6 ]

22 голосов
/ 20 декабря 2011

Вы должны предоставить конструктор по умолчанию.Пока вы работаете над этим, исправьте и другой конструктор:

class Name
{
public:
  Name() { }
  Name(string const & f, string const & l) : first(f), last(l) { }
  //...
};

В качестве альтернативы вы должны предоставить инициализаторы:

Name arr[3] { { "John", "Doe" }, { "Jane", "Smith" }, { "", "" } };

Последний концептуально предпочтителен, поскольку нетПричина, по которой ваш класс должен иметь представление о состоянии "по умолчанию".В этом случае вы просто имеете , чтобы обеспечить соответствующий инициализатор для каждого элемента массива.

Объекты в C ++ никогда не могут находиться в плохо определенном состоянии;если вы думаете об этом, все должно стать очень ясным.


Альтернативой является использование динамического контейнера, хотя это отличается от того, что вы просили:

std::vector<Name> arr;
arr.reserve(3);  // morally "an uninitialized array", though it really isn't

arr.emplace_back("John", "Doe");
arr.emplace_back("Jane", "Smith");
arr.emplace_back("", "");

std::vector<Name> brr { { "ab", "cd" }, { "de", "fg" } }; // yet another way
5 голосов
/ 20 декабря 2011

Для инициализации по умолчанию массива T s, T должен быть конструируемым по умолчанию. Обычно компилятор предоставляет вам конструктор по умолчанию бесплатно. Однако, поскольку вы объявили конструктор самостоятельно, компилятор не создает конструктор по умолчанию.

Ваши варианты:

  • добавить конструктор по умолчанию для name, если это имеет смысл (я так не думаю, но я не знаю проблемную область);
  • инициализировать все элементы массива при объявлении (вы можете сделать это, потому что name является агрегатом);

      name someName[4] = { { "Arthur", "Dent" },
                           { "Ford", "Prefect" },
                           { "Tricia", "McMillan" },
                           { "Zaphod", "Beeblebrox" }
                         };
    
  • используйте взамен std::vector и добавляйте элемент только тогда, когда вы его построили.

2 голосов
/ 20 декабря 2011

Чтобы создать массив объектов, объектам необходим конструктор, который не принимает никаких параметров (который создает форму объекта по умолчанию, например, с пустыми обеими строками).Это то, что означает сообщение об ошибке.Компилятор автоматически генерирует конструктор, который создает пустой объект , если только нет других конструкторов.

Если имеет смысл создать элементы массива пустыми (в этом случае члены получают своизначения по умолчанию, в данном случае пустые строки), вам следует:

-Написать пустой конструктор:

class name {
  public:
    string first;
    string last;

  name() { }
  name(string a, string b){
    first = a;
    last = b;
  }
};

-Или, если вам это не нужно, удалить существующий конструктор.

Если «пустая» версия вашего класса не имеет смысла, не существует хорошего решения для обеспечения параметров инициализации для всех элементов массива во время компиляции.Вы можете:

  • Сделать так, чтобы конструктор создал пустую версию класса, и функцию init(), которая выполняет реальную инициализацию
  • Использование vector, и при инициализациисоздайте объекты и вставьте их в vector, используя vector::insert или цикл, и поверьте, что не делать этого во время компиляции не имеет значения.
  • Если объект не может быть скопирован либоВы можете использовать массив / вектор умных указателей на объект и распределять их при инициализации.
  • Если вы можете использовать C ++ 11, я думаю (?), вы можете использовать списки инициализаторов для инициализации вектора и инициализацииэто (я не уверен, работает ли это с каким-либо конструктором или только если объект создается из одного значения другого типа).Например:.
 std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };

`

2 голосов
/ 20 декабря 2011

Ваш класс:

class name {
  public:
    string first;
    string last;

  name() { }  //Default constructor.

  name(string a, string b){
    first = a;
    last = b;
  }
};

Имеет явный конструктор, который требует двух строковых параметров.Классы без явно написанного конструктора получают конструкторы по умолчанию без параметров.Добавление явного не позволило компилятору сгенерировать этот конструктор по умолчанию для вас.

Итак, если вы хотите создать массив неинициализированных объектов, добавьте конструктор по умолчанию в ваш класс, чтобы компилятор знал, как их создавать безпредоставляя эти два строковых параметра - см. закомментированную строку выше.

2 голосов
/ 20 декабря 2011

вам просто нужно добавить конструктор по умолчанию в ваш класс, чтобы он выглядел так:

class name {
  public:
    string first;
    string last;

  name() {
  }

  name(string a, string b){
    first = a;
    last = b;
  }
};
2 голосов
/ 20 декабря 2011

Вам нужен конструктор без параметров , чтобы иметь возможность создать экземпляр вашего класса. Ваш текущий конструктор требует два входных строковых параметра.

Обычно C ++ подразумевает наличие такого конструктора (= конструктор по умолчанию без параметров), если не объявлен другой конструктор . Объявляя ваш первый конструктор с двумя параметрами, вы перезаписываете это поведение по умолчанию, и теперь вам нужно явно объявить этот конструктор.

Вот рабочий код:

#include <iostream> 
#include <string>  // <-- you need this if you want to use string type

using namespace std; 

class name { 
  public: 
    string first; 
    string last; 

  name(string a, string b){ 
    first = a; 
    last = b; 

  }

  name ()  // <-- this is your explicit parameterless constructor
  {}

}; 

int main (int argc, const char * argv[]) 
{ 

  const int howManyNames = 3; 

  name someName[howManyNames]; 

  return 0; 
}

(Кстати, вам нужно включить, чтобы сделать код компилируемым.)

Альтернативным способом является явная инициализация ваших экземпляров при объявлении

  name someName[howManyNames] = { {"Ivan", "The Terrible"}, {"Catherine", "The Great"} };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...