Using a vector of objects, can I?

I'm working on something where I have objects that I don't know how many will exist (it's going to be a child support calculator, adults and children would be dynamically added amongst other objects).

I've done this in php, but my intention is to write a version for windows rather than the web.

Anyway arrays, unlike in php can't be extended, so the advice appears to be to use vectors. So that's what I am trying.

I have a class, a pretty simple one :-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class cs_carerates {
    public:
        cs_carerates(int carenights);
        ~cs_carerates();
        int getcarerate();
        int getcostrate();
    protected:
    int levelofcare;
    int carerate;
    int costrate;
};
// Constructor which takes the level of care in nights
// and then
cs_carerates::cs_carerates(int carenights) {
    levelofcare = carenights;
    // Set the carerate (i.e. actual percentage of care)
    float cn = ((float)carenights / 365) * 100;
    if (cn < 50) {
        carerate = (int)floor(cn);
    }
    else {
        carerate = (int)ceil(cn);
    }

    // set the cost rate
    if (carerate <= 13) { costrate=0; }
	if (carerate >= 14 & carerate <= 34) { costrate = 24; }
	if (carerate >= 35 & carerate <= 47) { costrate = 25 + ((carerate - 35) * 2); }
	if (carerate >= 48 & carerate <= 52) { costrate = 50; }
	if (carerate >= 53 & carerate <= 65) { costrate = 51 + ((carerate - 53) * 2); }
	if (carerate >= 66 & carerate <= 86) { costrate = 76; }
	if (carerate >= 87) { costrate = 100; }
}
//destructor (does nothing)
cs_carerates::~cs_carerates() {
}
int cs_carerates::getcarerate() {
    return carerate;
}
int cs_carerates::getcostrate() {
    return costrate;
}


I want to have a dynamic number of instances/objects.

I have the following code, which compiles and runs (although with improper results the output from getcarerate() is not as expected) if the 4th line is commented out. The problem I appear to have is construction of the instance. Can anyone say where I'm going wrong.

1
2
3
4
5
6
    vector<cs_carerates> crv;
    for (int i = 0;i < 10;i++) {
        crv.push_back(1);
        crv[i].cs_carerates(60);
        cout << "Nights Care=" << crv[i].getcarerate() << endl;
    }

Last edited on
On lines 27 - 31 you need &&, not &
cs_carerates is the constructor, you can't call it that way. Why don't you call push back like this? crv.push_back(60);
And notice that if you need many insertions in crv, a deque should be more efficient than a vector
operator & is bitwise AND, you want to use &&, the logical AND operator.

EDIT : I really should refresh the page before posting :D
Last edited on
1
2
3
4
5
6

vector<cs_carerates> crv;
    for (int i = 0;i < 10;i++) {
        crv.push_back(cs_carerates(60)); // crv is a vector of cs_carerates so pushback that
        cout << "Nights Care=" << crv[i].getcarerate() << endl;
    }
since cs_carerates constructor isn't explicit you can simply pass '60'
Thank you Bazzy, that was new to me.
Thanks for the replies, the problem I had , was a) I'm an idiot :), b) instead of int i=0 I had i=1 in line two, so I was always accessing the wrong vector. (and the results were telling me that) After amending this I must have forgetten to compile or I didn't spot an error when compiling and reran the version with int=1 yet again.

I'll check out deque (I looked around and saw something that said vectors were good for what I thought were my needs, the primary one would likely to be to access the objects by their vector index (my words so sorry if my terminology is incorrect)).

To elaborate on what will be required. When one starts there would be a drop down to select a year, the years will be defined likely from a file, a line per year, each includes 5 other values specific to the year. The class for handling the data (which includes a complex process of handling the 5 values) has been setup and is working as expected. As the number grows annually I'd use a vector/deque for this, however there will simply be the one time creation of these objects at run time, with the selected one being referenced when the calculation takes place.

The next section, will initially have 2 adults, the minimum required, but others can be added due to a number of reasons (other CS cases as these can impact the "core"case, non-parent carers). Adults may be added or deleted (never less than 2 though). There will be an instance for each adult. It would be easy for their to be 5 adults, more even.

The next section is for children, initially 1, the minimum, but children could be added/deleted. Children are more complex, as for each adult a relationship exists between the child and the adult (parent, non-parent carer, other, deceased parent or overseas parent). So if you add an adult then all children have to updated to allow the input for the extra adult, deleting an adult needs the reverse. There will be an instance for each child, and for each relationship.

When all input has been gathered then the real processing takes place and will at times read through all instances, at others there will be direct/indexed access to the instances. New objects will be used a CS case object, basically for each child that has a case (2 parents or 1 parent an non-parent carer). In the online version I also had a second adult type object that is specific to the case and holds intermediate and final values. There will be 1 or more overall case objects (basically a combination of 1 or more of the CS case objects (e.g. for 3 children with the same parents there would be 3 instances of the per child objects, held/referenced by the main/overall instance).

If you're really interested (and I expect not) the online version is here http://www.csacalc.ath.cx/ACSCalcv3.0.html) (note that you get no idea whatsover of the underlying processing that is done)



Oh and thanks for the tip about && I'll implement that.

The issue I have now is that this was what I thought as a simple class. I have other classes in which the constructor (as set up now) takes multiple values. It would appear that I can only pass a single value directly via push_back, so it looks as though I either need to setup a constructor (overload it) to take a string (say comma delimited) and to then split that string within the constructor or that I have the constructor take one value and then have another function to complete the subsequent construction after the initial constructor has done it's job. (I believe that latter would be the simplest). If anyone thinks that's not the way to go then please say so.

Bazzy I'm not sure how you make a constructor explicit (not even sure what it really means), so that's something that I'm going to try to find out and will perhaps ask about later (i.e. I'm a firm believer in RTFM)
I'll check out deque (I looked around and saw something that said vectors were good for what I thought were my needs, the primary one would likely to be to access the objects by their vector index (my words so sorry if my terminology is incorrect)).
The deque allows subscripting [ ] as vector but it is more efficient in allocating memory for new elements

It would appear that I can only pass a single value directly via push_back, so it looks as though I either need to setup a constructor (overload it) to take a string (say comma delimited) and to then split that string within the constructor or that I have the constructor take one value and then have another function to complete the subsequent construction after the initial constructor has done it's job. (I believe that latter would be the simplest). If anyone thinks that's not the way to go then please say so.
You can call push_back as anilpanicker showed, so you can pass every argument you need to the constructor
eg: crv.push_back( cs_carerates( any, value, you, need ) );

Bazzy I'm not sure how you make a constructor explicit (not even sure what it really means), so that's something that I'm going to try to find out and will perhaps ask about later (i.e. I'm a firm believer in RTFM)
You just need to add explicit to the constructor declaration, here is an example on what it means:
1
2
3
4
5
6
7
8
9
10
11
12
13
class A
{
   A(int); // Not explicit
};
class B
{
  explicit B(int); // explicit
};

A a = 1; // OK
A a(1);  // OK
B b = 1; // WRONG, constructor needs to be explicit
B b(1);  // OK 
OK, I've got explicit now, also passing multiple arguments to the constructor and also I've tried out deque.

So to summarise the solution.

I have two classes cs_carerates and cs_adults. I use a vector (named crv) to hold multiple instances of objects of the class cs_carereates and a deque (named cad) to hold multiple instances of objects of the class cs_adults.

The constructor for cs_carerates takes one argument and is not explicit so you can use either crv.push_back(60) or crv.push_back(cs_carerates(60)); to construct the vector instance.

The constructor for cs_adults requires 3 arguments, therefore (I believe explicit is implied) only the latter method of using push_back, with a call to the construction function as the argument can be used e.g. cad.push_back(cs_adults("Fred",50000,1));

Thanks Bazzy for pointing out what I missed from anilpanicker, sorry to anilpaniker for missing your input.

So here's the code for the solution :-

The cs_carerates class definition :-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Constructor which takes the level of care in nights
// and then
cs_carerates::cs_carerates(int carenights) {
    levelofcare = carenights;
    // Set the carerate (i.e. actual percentage of care)
    float cn = ((float)carenights / 365) * 100;
    if (cn < 50) {
        carerate = (int)floor(cn);
    }
    else {
        carerate = (int)ceil(cn);
    }

    // set the cost rate
    if (carerate <= 13) { costrate=0; }
	if (carerate >= 14 && carerate <= 34) { costrate = 24; }
	if (carerate >= 35 && carerate <= 47) { costrate = 25 + ((carerate - 35) * 2); }
	if (carerate >= 48 && carerate <= 52) { costrate = 50; }
	if (carerate >= 53 && carerate <= 65) { costrate = 51 + ((carerate - 53) * 2); }
	if (carerate >= 66 && carerate <= 86) { costrate = 76; }
	if (carerate >= 87) { costrate = 100; }
}
//destructor (does nothing)
cs_carerates::~cs_carerates() {
}
int cs_carerates::getcarerate() {
    return carerate;
}
int cs_carerates::getcostrate() {
    return costrate;
}



The cs_adult class definition :-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Class to hold basic adult information
class cs_adult {
    public:
    cs_adult(string adults_name, int adults_ati, int adults_aid);
    ~cs_adult();
    string getaname();
    int getati();
    int getaid();
    private:
    string aname;
    int aid;
    int ati;
};
// Constructor
cs_adult::cs_adult(string adults_name, int adults_ati, int adults_aid) {
    aname = adults_name;
    ati = adults_ati;
    aid = adults_aid;
}
// Destructor (does nothing)
cs_adult::~cs_adult() {
}
// Getaname (returns adults name as string)
string cs_adult::getaname() {
    return aname;
}
// getati (returns adutls ati (Adjusted Taxable Income))
int cs_adult::getati() {
    return ati;
}
// getaid ( returns adults id ( unique identifier))
int cs_adult::getaid() {
    return aid;
}


The relevant code :-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <vector>
#include <deque>


.....


    vector<cs_carerates> crv;       // define vector to hold an unknown # of cs_carerates instances
    for (int i = 0;i < 40;i++) {    // loop to create 40 instances
        crv.push_back(i * 5);       // create the current instance with an implicit call to the
                                    // constructor
                                    
        // output the values to check that all is OK.
        cout << "Nights Care=" << i * 5;    
        cout << " Care Rate=" << crv[i].getcarerate();
        cout << " Cost Rate=" << crv[i].getcostrate() << endl;
    }

    deque<cs_adult> cad;            // define deque to hold unknown # of cs_adult instances
    for (int i=0; i < 10; i++) {    // loop to create 10 instances
        cad.push_back(cs_adult("Fred",50000+(i*10),i)); // create current instance with explicit call
                                                        // to the multi-argument constructor
                                                        
        // output values to check that all is OK.
        cout << "Adult is=" << cad[i].getaname();
        cout << " ATI=" << cad[i].getati() << endl;
    }
Just a thing I've noticed:
You can simplify the code of 'set the cost rate' -Line 14 1st code snippet of last post-
1
2
3
4
if (carerate <= 13) costrate=0; // single statement = don't need braces 
else if (carerate <= 34) costrate = 24; // else => previous conditions have already been checked and resulted false
else if ( carerate <= 47)  costrate = 25 + ((carerate - 35) * 2);
    //... 
Yet again thanks Bazza, I've made the changes to not use braces.

I have to admit that I do have a tendency to overcode, especially when using constructs, due to a habit of always trying to close an open construct before coding within the construct. This was before there were editors that are nice enough to recognise and highlight such things.
Topic archived. No new replies allowed.