Lisa
Lisa

Reputation: 331

How can I create multiple objects with for loop in C++?

I am trying to create multiple objects using a for loop, as eventually I will want this program to create different numbers of the class depending on my input. I tried to write this using an answer to a previous question. However, when I try to compile I get the error 'no matching function for call to '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;

}  

Upvotes: 13

Views: 60208

Answers (6)

Clifford
Clifford

Reputation: 93476

There a number of solutions, the simplest to implement given what you have (i.e. without changing the class Genes, and without using a container class) is:

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

Then in the loop:

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

This has the advantage of avoiding a buffer overrun if geneno > 10.

Your access code (the cout stuff) is invalid in any case. Given the suggested change, accessing the object would look like:

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

The clean-up code would now also have to delete each object in the genes array before deleting the array itself. One reason why a container class may be more appropriate.

Upvotes: 0

Martin Beckett
Martin Beckett

Reputation: 96109

Genes *genes=new Genes[10] creates an array of 10 empty 'Genes' but you don't have a default constructor for Genes - there is no way of creating a 'Genes' without supplying a,b,c.

You need an empty ctor or supply a default arguement for a,b,c

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

or 

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

Upvotes: 3

Aria Buckles
Aria Buckles

Reputation: 943

In C++, creating an array with new[] initializes all the objects with their default/no-parameter constructor.

So this line: (semicolon added)

 Genes *genes=new Genes[10];

Will result in ten calls to Genes::Genes().

That would normally seem fine, since C++ will give you a default constructor when you don't declare any. However, for this to happen, you must not declare any constructors. Your constructor:

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

Prevents the compiler from creating a default constructor for you, which in turn prevents you from making an array of Genes objects.


There are two reasonable solutions to this problem:

  1. You could add a default/no argument constructor to the Genes class. This is simple, but lacks some elegance. What is a default Genes object? If such an object made sense, you probably would have declared a default constructor already.

  2. Look into using std::vector instead of an array: http://www.cplusplus.com/reference/stl/vector/ . While this is a more complicated fix in the short term, being familiar with the Standard Template Library (which supplies the vector class) will be valuable in the long term. That said, if you are just learning C++ and haven't seen templates before, this might be a bit overwhelming and you might want to read a bit about templates first. (for example, at http://www.learncpp.com/cpp-tutorial/143-template-classes/ )

The vector class allows you to declare a capacity, for how many objects you will put into your array (or you may not declare a capacity, resulting in a slower insert). Then, it will only construct objects when they are placed into the vector. Your code would look something like this:

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

The last statement is (roughly) equivalent to:

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

vector::push_back adds an item to the back of the vector and increases the vector capacity by 1: http://www.cplusplus.com/reference/stl/vector/push_back/

You can subsequently access elements in the vector the same way as you would the array:

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

And you can query the size of the vector with vector::size():

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

Upvotes: 12

Kerrek SB
Kerrek SB

Reputation: 476990

Use idiomatic C++ and pick the right container for the job (namely 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)
}

Now you have your elements in v[0], v[1], etc.

Upvotes: 11

Alok Save
Alok Save

Reputation: 206518

Once you write a parameterized constructor,

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

the compiler does not generate the no parameter default constructor for your class, You need to provide it yourself.

You have two options:

. You need to define a default constructor for your class explicitly:

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

Or

. You use the paramertized constructor(with default arguments) instead of the default constructor.

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

Upvotes: 1

Zeenobit
Zeenobit

Reputation: 5194

This is because you're first creating an array of Genes using the default constructor in the Genes* genes = new Genes[10]. What you need to do is use a standard container instead to store the genes in, such as std::vector or std::list.

Upvotes: 0

Related Questions