Как создать несколько объектов с циклом for В C++?

Я пытаюсь создать несколько объектов с помощью цикла for, так как в конечном итоге я хочу, чтобы эта программа создавала разные номера класса в зависимости от моего ввода. Я попытался написать это, используя ответ на предыдущий вопрос. Однако, когда я пытаюсь скомпилировать, я получаю ошибку "нет функции соответствия для вызова" Genes:: Genes ()"

#include <iostream>
#include <cstdlib>
#include <ctime> 

using namespace std;

float random();

class Genes{
 public:
 double cis;
 double coding;
 double effect;
 Genes(double a, double b, double c);
};

Genes::Genes(double a, double b, double c) 
{
  cis=a;
  coding=b;
  effect=c;
};

int main()
{
  int geneno, i;

  srand(time(NULL));

  geneno=4; //this will probably be cin later

  Genes *genes=new Genes[10]

  for(i=0;i<=geneno;i++){
    double d,e,f;

    d=random();
    e=random();
    f=random();

    genes[i]=Genes(d,e,f);

    cout<<"cis is "<<genes.cis<<'n';
    cout<<"coding is "<<genes.coding<<'n';
    cout<<"Effect for gene is "<<genes.effect<<'n';

    }
 delete[] genes;
 }


float random(){

  float decRANDMAX;

 decRANDMAX=RAND_MAX*1.0;

 return rand()%(RAND_MAX+1)/decRANDMAX;

}  

6 ответов


в C++ создание массива с помощью new[] инициализирует все объекты с помощью конструктора по умолчанию / без параметров.

Итак, эта строка: (точка с запятой добавлена)

 Genes *genes=new Genes[10];

приведет к десяти вызовам Genes:: Genes().

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

Genes::Genes(double a, double b, double c)

предупреждает компилятор от создания конструктора по умолчанию для вас, что в свою очередь предотвращает создание массива объектов Genes.


существует два разумных решения этой проблемы:

  1. вы можете добавить конструктор аргументов по умолчанию/no в класс Genes. Это просто, но лишено некоторой элегантности. Что такое объект генов по умолчанию? Если бы такой объект имел смысл, вы, вероятно, объявили бы конструктор по умолчанию уже.

  2. посмотрите на использование std:: vector вместо массива:http://www.cplusplus.com/reference/stl/vector/ . Хотя это более сложное исправление в краткосрочной перспективе, знакомство со стандартной библиотекой шаблонов (которая предоставляет класс vector) будет ценным в долгосрочной перспективе. Тем не менее, если вы только изучаете C++ и раньше не видели шаблонов, это может быть немного подавляющим, и вы можете сначала прочитать немного о шаблонах. (например, at http://www.learncpp.com/cpp-tutorial/143-template-classes/ )

класс vector позволяет объявить емкость, для сколько объектов вы поместите в свой массив (или вы не можете объявить емкость, что приводит к более медленной вставке). Затем он будет создавать объекты только тогда, когда они помещаются в вектор. Ваш код будет выглядеть примерно так:

#include <vector> // to get the vector class definition
using std::vector; // to 

vector<Genes> genes;
genes.reserve(geneno); // optional, but speeds things up a bit

for(i = 0; i <= geneno; i++) {
    double d = random();
    double e = random();
    double f = random();

    genes.push_back(Genes(d, e, f));
}

последнее утверждение (грубо) эквивалентно кому:

Genes temp(d, e, f);
genes.push_back(temp);

vector:: push_back добавляет элемент в заднюю часть вектора и увеличивает векторную емкость на 1:http://www.cplusplus.com/reference/stl/vector/push_back/

вы можете впоследствии получить доступ к элементам в векторе так же, как и к массиву:

cout << "The third gene's coding is " << genes[3].coding << endl;

и вы можете запросить размер вектора с помощью vector:: size ():

cout << "The vector has " << genes.size() << "elements" << endl;

используйте idiomatic C++ и выберите правильный контейнер для задания (а именно vector):

#include <vector>

const std::size_t num_genes; // your data here

//...

std::vector<Genes> v;
v.reserve(num_genes);

for (std::size_t i = 0; i != num_genes; ++i)
{
  v.push_back(Genes(random(), random(), random()));  // old-style
  v.emplace_back(random(), random(), random());      // modern (C++11)
}
у вас есть свои элементы в v[0], v[1], etc.

Genes *genes=new Genes[10] создает массив из 10 пустых "генов", но у вас нет конструктора по умолчанию для генов - нет способа создать "гены" без предоставления a,b, c.

вам нужен пустой ctor или укажите аргумент по умолчанию для a,b, C

Genes::Genes() : cis(0),coding(0),effect(0)

or 

Genes::Genes(double a=0, double b=0, double c=0) 

как только вы напишете параметризованный конструктор,

Genes::Genes(double a, double b, double c);

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

у вас есть два варианта:

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

Genes::Genes():cis(0),coding(0),effect(0)
{
}

или

. Вместо конструктора по умолчанию используется конструктор paramertized(с аргументами по умолчанию).

Genes::Genes(double a=0, double b=0, double c=0) 
{
}

это потому, что вы сначала создаете массив генов, используя конструктор по умолчанию в Genes* genes = new Genes[10]. Вместо этого вам нужно использовать стандартный контейнер для хранения генов, например std::vector или std::list.


существует ряд решений, простейших для реализации с учетом того, что у вас есть (т. е. без изменения генов класса и без использования класса-контейнера):

geneno = 4;
Genes** genes = new Genes*[geneno] ;

затем в цикле:

genes[i] = new Genes(d,e,f);

это имеет преимущество избежать переполнения буфера, если geneno > 10.

ваш код доступа (материал cout) недействителен в любом случае. Учитывая предлагаемое изменение, доступ к объекту будет выглядеть так:

cout<<"cis is "<<genes[i]->cis<<'\n';
cout<<"coding is "<<genes[i]->.coding<<'\n';
cout<<"Effect for gene is "<<genes[i]->.effect<<'\n';

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