Hi Jimbot,
I finally got around to looking into your questions:
This was because I misunderstood the way classes handle data. I thought that because I had made all my element methods which can talk to private members of the element class, that when I added objects of this class to a vector in another array then they could still be accessed and changed as usual. I didn't appreciate that once I add them to a private member of another class then they also become private. (I hope that makes some sense) |
Yes, everything within an object that is a private data member of a class will become private since the only way to access that member is through that class in which it is a member.
I wish to still keep this as I want to be able to edit element data during run time, and although I could add this functionality to the Collection class I think the code would lose some of its 'object orientated-ness' |
What I realised is that if you don't want an
Element
to have its
MyValue
member changed then just declare it
const
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
class Element
{
public:
Element(int i = 5)
: MyValue(i) {}
int GetValue() const {return MyValue;}
void SetValue(int NewValue) {MyValue = NewValue;}
private:
int MyValue;
};
int main()
{
const Element CElement(6);
CElement.SetValue(8);
return 0;
}
|
error: passing ‘const Element’ as ‘this’ argument of ‘void Element::SetValue(int)’ discards qualifiers |
However, if you append it to a non-const
Collection
and then try to alter it via an index operator, you can still
change its value of
MyValue
:
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
|
#include <iostream>
#include <vector>
#include <cstddef>
#include <stdexcept>
using std::vector; using std::istream;
using std::cout; using std::endl;
using std::cin; using std::domain_error;
class Element
{
public:
Element(int i = 5)
: MyValue(i) {}
int GetValue() const {return MyValue;}
void SetValue(int NewValue) {MyValue = NewValue;}
private:
int MyValue;
};
class Collection
{
public:
Collection(vector<Element>::size_type i = 0)
: AllElements(vector<Element>(i)) {}
Collection(istream& is) {read(is);}
istream& read(istream&);
Element& operator[](vector<Element>::size_type i)
{
if(i >= size())
throw std::domain_error("index exceeds maximum value!");
else
return AllElements[i];
}
const Element& operator[](vector<Element>::size_type i) const
{
if(i >= size())
throw std::domain_error("Element::operator[] - index exceeds maximum value!");
else
return AllElements[i];
}
void AddElement(const Element& NewElement = Element()) {AllElements.push_back(NewElement);}
vector<Element>::size_type size() const {return AllElements.size();}
private:
vector<Element> AllElements;
};
istream& Collection::read(istream& is)
{
AllElements.clear();
while(is)
{
int x;
cout << "Please Enter an int: ";
is >> x;
if(is)
AddElement(Element(x));
}
is.clear();
return is;
}
int main()
{
cout << "Creating a new (non-const) Collection object containing a const Element." << endl;
const Element CElement(6);
Collection NewCollection;
NewCollection.AddElement(CElement);
cout << NewCollection[0].GetValue() << endl;
NewCollection[0].SetValue(8);
cout << NewCollection[0].GetValue() << endl;
return 0;
}
|
Creating a new (non-const) Collection object containing a const Element.
6
8
|
However, if you declare a
const Collection
you will not be able to change its contents beyond construction:
1 2 3 4 5 6 7 8 9 10 11
|
int main()
{
cout << "Creating a new const Collection object containing 5 (default-initialised) Element objects." << endl;
const Collection MyConstCollection(5);
cout << "The value inside element 3 is: " << MyConstCollection[2].GetValue() << endl;
cout << "Trying (and failing) to change the value inside element 3 to 7...." << endl;
//MyConstCollection[2].SetValue(7); //if you try this the code won't compile because MyConstCollection is const
cout << endl;
return 0;
}
|
Creating a new const Collection object containing 5 (default-initialised) Element objects.
The value inside element 3 is: 5
Trying (and failing) to change the value inside element 3 to 7....
|
1 2 3 4 5 6 7 8 9
|
int main()
{
...
MyConstCollection[2].SetValue(7); //if you try this the code won't compile because MyConstCollection is const
cout << endl;
return 0;
}
|
error: passing ‘const Element’ as ‘this’ argument of ‘void Element::SetValue(int)’ discards qualifiers
|
As you can see from the code above, I have made some changes to the classes by including new constructors in
Collection
including a default that allows you to generate a
Collection
with a specified number of default-initialised
Element
objects (or none by default), and a constructor that allows you to read in integer values to initialise the
Element
objects from a specified input stream via the
read
function.
Also I have given
Collection
two index operators for
const
and
non-const
objects.
Here are some examples of the output using the above classes:
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
|
int main()
{
cout << "Creating a new (non-const) Collection object containing 5 (default-initialised) Element objects." << endl;
Collection MyCollection(5);
cout << "The value inside element 3 is: " << MyCollection[2].GetValue() << endl;
cout << "Trying to change the value inside element 3 to 7...." << endl;
MyCollection[2].SetValue(7);
cout << "The value inside element 3 is now: " << MyCollection[2].GetValue() << endl;
cout << endl;
cout << "Creating a new (non-const) empty Collection, initialised from the standard input stream." << endl;
Collection MyOtherCollection(cin);
cout << endl;
cout << "My new Collection contains " << MyOtherCollection.size() << " Elements." << endl;
vector<Element>::size_type x = 3;
if(x <= MyOtherCollection.size()) //to avoid throwing an exception due to access violation
{
cout << "The value inside element " << x << " is: " << MyOtherCollection[x-1].GetValue() << endl;
cout << "Trying to change the value inside element " << x << " to 7...." << endl;
MyOtherCollection[x-1].SetValue(7);
cout << "The value inside element " << x << " is now: " << MyOtherCollection[x-1].GetValue() << endl;
}
cout << endl;
return 0;
}
|
Creating a new (non-const) Collection object containing 5 (default-initialised) Element objects.
The value inside element 3 is: 5
Trying to change the value inside element 3 to 7....
The value inside element 3 is now: 7
Creating a new (non-const) empty Collection, initialised from the standard input stream.
Please Enter an int: 1
Please Enter an int: 2
Please Enter an int: 3
Please Enter an int: 6
Please Enter an int:
My new Collection contains 4 Elements.
The value inside element 3 is: 3
Trying to change the value inside element 3 to 7....
The value inside element 3 is now: 7
|
Sorry for the long post, I hope that helps with your first set of questions.