Making a constructor for class that contains other class

I'm making a constructor for a class "Check", that contains "CheckItems". CheckItems contains another class called "Article" in it.
The check class has a static(dynamic array is not an option) array of checkitems. The user has the option to add new checkitems into that array until the check is "done".

However, when I'm making the constructor for the class "Check", it expects me to initialize all the checkitems in the static array. Is there a good way to not have to initialize all of those checkitems to some default and worthless values and only initialize those that the user actually adds with proper values for that checkitem attributes.

Is it fine to use the default constructor for all the checkitems in the array? I added some default constructor for checkitems that just sets the amount to 0 and uses the deafult constructor I added for Article too. You can see I set the values of price, amount and other to 0 or NULL.

Should I not use a constructor for check class at all? How would you solve this?

Here's what the 3 classes look like:
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  class Article {
	char* _code;
	char* _name;
	double _price;
	int _amount;//in warehouse
public:
	Article() {
		_code = NULL;
		_name = NULL;
		_price = 0;
		_amount = 0;
	}
	Article(char* c, char* n, double c, int k) {
		_code = new char[strlen(c) + 1];
		strcpy_s(_code, strlen(c) + 1, c);
		_name = new char[strlen(n) + 1];
		strcpy_s(_name, strlen(n) + 1, n);
		_price = c;
		_amount = k;
	}
	~Article() {
		delete[] _code;
		delete[] _name;
		_code = NULL;
		_name = NULL;
	}
	void operator-= (int amo) {
		_amount -= amo;
		if (_amount < 0) _amount = 0;
	}
	Article operator++() {//preincrement
		_amount += 1;
		return *this;
	}
	Article operator++(int) {//postincrement
		_amount += 1;
		return *this;
	}
	Article operator--() {//predecrement
		if(_amount<0) _amount -= 1;
		return *this;
	}
	Article operator--(int) {//postdecrement
		if (_amount<0) _amount -= 1;
		return *this;
	}
	bool operator==(Article& other) {
		return strcmp(_code, other._code);
	}
	friend ostream& operator<<(ostream&, Article&);
ostream& operator<<(ostream& COUT, Article& obj) {
	cout << "Code: " << obj._code << endl << "Name: " << obj._name << endl << "Price: " << obj._price << endl << "Warehouse units: " << obj._amount<<endl;
	return COUT;
}

class CheckItem {	
	Article _article;
	int* _amount;//on the bill
public:
	CheckItem() {
		*_amount = 0;
	}
	CheckItem(int* a, char* c, char* n, double p, int amo):_article(c,n,p,amo) {
		_amount = new int;
		*_amount = *a;
	}
	~CheckItem() {
		delete _amount;
		_amount = NULL;
	}
};

class Check {
	int _checkNr;
	CheckItem _items[100];
	int _itemsNr; 
	double _subTotal;
	double _Total;
	bool _printed;
public: // this part of code is not finished
	Check(int brc) {
		_checkNr = brc;
	}
};
Last edited on
However, when I'm making the constructor for the class "Check", it expects me to initialize all the checkitems in the static array. Is there a good way to not have to initialize all of those checkitems to some default and worthless values and only initialize those that the user actually adds with proper values for that checkitem attributes.

No. If you have objects, then you have objects and they have some state. Default construction is fine. You will not "add" CheckItems later; you will modify items that exist in the array.

Should I not use a constructor for check class at all?

Every class has constructor(s). The compiler creates some implicitly. If the compiler generated constructors do the right thing, then you do save some typing.

However, your CheckItem manages dynamic memory. The compiler generated copy constructor and copy assignment will break your program, if they are invoked. Either prevent invoking them or provide explicit versions.

Same applies to the class Article.
Yes, just provide a default constructor that initializes the items. What you have is okay. Although it's possible to initialize the items only when needed, it isn't easy so I wouldn't recommend it for a beginner.

Some other comments:
Lines 2&3: consider using string instead of char*. It will remove the burden of memory management.

Lines 14-17: if you must use char * for the strings, you can use strdup() here. Just be sure to change the destructor to use free() instead of delete[]

Lines 40 & 44: You can only decrement the amount if it is less than zero?

Line 48: strcmp returns 0 when the strings are equal, so I think you want return strcmp(_code, other._code) == 0

Line 52: cout should be COUT. Also use '\n' instead of endl for efficiency.

Line 61 should be _amount = 0, not *_amount = 0. Actually, why is is the amount a pointer at all? Shouldn't it just be an int? Better yet, isn't the amount really just the amount of the Article? In that case you don't need a separate _amount member at all.
Oh okay thank you :)

Lines 40 and 44 were > 0 before, but I changed them for some reason while editting out some other error...

I actually have to use char*(for what reason our professor forces us to use it idk), because I will have to use it in the exam too, so it's best to practice doing it now.

Why does it have to be COUT?

How is it _amount = 0 when we're talking about a pointer? doesn't _amount = 0 set the pointer to point at 0 memory address?

I think I should've only added _amount = new int above that line... right?
Why does it have to be COUT?

Q: What is wrong in this:
1
2
3
4
5
ostream& operator<<( ostream& foo, Article& obj )
{
  BAR << "fubar";
  return foo;
}

A: It does not compile, because BAR is unknown, but at logical level the function should surely write to stream foo?

Your code is worse. It compiles without warning, despite same logical problem.
How is it _amount = 0 when we're talking about a pointer? doesn't _amount = 0 set the pointer to point at 0 memory address?

Yes it does. Is that not what you intended?

I think I should've only added _amount = new int above that line... right?

If _amount is a pointer and it always points to an integer that the class instance owns, then why use a pointer at all? Why not just do:
1
2
3
4
class CheckItem {	
	Article _article;
	int _amount;//on the bill
	...

Well what I intended for that default constructor is just to set a new int to the pointer whose value becomes 0.

I don't know, that's how it was laid out in the assignment and I have to go with it - if it was me I would've done the same thing you're suggesting.

Tell me though, in which cases would I WANT the _amount to be a pointer instead of a standard int.

Tell me though, in which cases would I WANT the _amount to be a pointer instead of a standard int.

- When it points to an int in another class
- When it can point to nullptr
- When it's not an int, but rather something very large and you don't want to local instances of the class to overflow the size of the stack.

Can you post the assignment? The data that you have is oddly structured and if we can see the assignment, we might suggest better structures. Then again, this wouldn't be the first time that an instructor has required a backward data structure.
Then again, this wouldn't be the first time that an instructor has required a backward data structure.

Perhaps an extensive exercise on the Rule of three:
https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
Here's what it looks like:

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
43
44
45
46
47
48
49
//class holds data about an article
class Article {
	char* _code;
	char* _name;
	double _price;//Without VAT
	int _amount;//Warehouse amount
public:
	//Needed constructor and destructor
	//Overload -= operator so that the specified amount is substracted from the warehouse amount
	//Overload ++ operator so that the warehouse amount increases by 1
	//Overload -- so that the warehouse amount decreases by 1  
	//Overload == to compare articles based on their code
	//Overload operator for outputting data about an article
};  

class CheckItem {	
	Article _article;
	int* _amount;
public:
	//Needed constructor and destructor functions
	//Overload needed operators based on what is needed to accomplish the assignment
};

class Check {
	int _checkNr;
	CheckItem _items[100];
	int _itemsNr; 
	double _totalWithoutVAT;
	double _totalWithVAT;
	bool _printed;
public:
	//Operator() - adds new articles in checkitems (input parameters are article and amount), količina nije obavezni parametar;
	//pay attention to whether the check was already paid
	//if there is not enough articles in warehouse, print out the appropriate message 
	//if the article is already added on the check, increase the article amount instead of             //adding a new article on the check
	//after adding each article, update the price values(with and without VAT)
	//Operator -= removes an article based on it's code
	//Operator[] returns a checkitem based on it's article code
	//Operator/ calculates a discount on the price
	//Operator+ Forms a new check based on the checks involved in the + operation 
	//Again, if an article is already there, change only the amount
	//Implement the operator+ as a global function              
	//PrintCheck function prints out all the checkitems as well as the total prices
        //Enable the user to enter the amount of money that the client has paid, and as a //return value return the change. double PrintCheck();
};

void main() {
	//test all the available functionalities
}
Last edited on
*BUMP*
I think I understand this better now. I was having trouble because I thought this was a "check" like a bank check, but it appears to be a "check" like the check you get in a restaurant.

Here are some thoughts:
- Article's default constructor should set _code and _name to an empty string instead of NULL. That way you're guaranteed that they are always valid and you don't have to check for NULL each time you use them.

keskiverto is right: this is an extensive exercise in the Rule of Three. Read the link he shared.

I still don't understand what CheckItem::_amount is vs Article::_amount. It sounds like one represents the quantity of the item on the check, and the other is the quantity in inventory, but then now do you initialize the quantity in inventory? And since Article is ultimately a member of the check, changing the inventory amount there isn't helpful since it doesn't update any sort of global inventory value.
Topic archived. No new replies allowed.