Accessing a Private variable - c++

I'm trying to get my head around encapsulation in C++. I have this program working when everything is in public, but when I move the vector to private, I'm having trouble accessing the vector with my public functions. I've tried using a friend and I can't get it to work. How can I get my addElement function to see the vector?
#include <iostream>
#include <vector>
using namespace std;
class MySet{
private:
vector<int> elements;
public:
MySet();
friend void addElement(int value);
};
MySet::MySet (){
vector <int> elements;
}
void MySet::addElement(int value){
elements.push_back(value);
}
void Print(vector<int>& v) {
vector<int>::iterator it;
for(it = v.begin(); it != v.end(); ++it) {
cout << (*it) << '\n';
}
}
int main(int argc, char *argv[]){
int value;
MySet set;
cout << "Enter your numbers,(enter -1 to end)" << endl;
while(cin){
cin>> value;
if(value==-1)
break;
set.addElement(value);
}
Print(set.elements);
system("PAUSE");
}

Basically you want to make a Print a method instead of trying to access the private member variable. In general trying to access the private variable directly is usually a good sign that it shouldn't be private in the first place or that you need to change your design. In this case changing your design would most likely lead to the best outcome:
using namespace std;
class MySet{
private:
vector<int> elements;
public:
MySet();
friend void addElement(int value);
void print() {
vector<int>::iterator it;
for(it = this->elements.begin(); it != this_.elements.end(); ++it){
cout << (*it) << '\n';
}
}
};
Now you can print it like so:
set.print();
And this avoids the issues with using the private member.
Note that we no longer need to pass in the particular instance of MySet to the print function, this is because the class already has that information it needs via the this pointer.
The general idea is that you store the state as private then give a bunch of public functions for the users of the class the manipulate that state. The users shouldn't manipulate the state directly though, so if you find you are doing this step back and reconsider your design.

Related

Difficulty with map's find function

I am having trouble figuring out why this is not compiling. This is just the basic class declaration, constructor/destructor and other functions are left out. Message is also properly defined somewhere else.
#include <vector>
#include <map>
using namespace std;
class SmartCarrier {
map<string, vector <Message *>> accounts_map;
void SearchMessage() const;
};
When I try to assign m_iter with m_iter = accounts_map.find(account) I get the error no operator "=" matches these operands. I double checked to make sure the map iterator was the same type as the actual map which it is. I'm not sure what is incorrect.
void SmartCarrier::SearchMessage() const {
string account;
map<string, vector<Message *>>::iterator m_iter;
cout << "Enter an account: ";
cin >> account;
try {
m_iter = accounts_map.find(account);
if (m_iter != accounts_map.end) {
//code to display account information
} else {
throw 'e';
}
} catch (char e) {
cout << "Error: Account not found\n";
}
}
SearchMessage() is declared as const, so its this parameter is pointing at a const SmartCarrier object, so its accounts_map member is also const. When find() is called on a const map, it returns a const_iterator instead of an iterator.
Also, accounts_map.end needs to be accounts_map.end() instead.
Also, using an exception the way you are is just wasted overhead that you can (and should) get rid of.
Try this:
void SmartCarrier::SearchMessage() const {
string account;
cout << "Enter an account: ";
cin >> account;
map<string, vector<Message *>>::const_iterator m_iter = accounts_map.find(account);
if (m_iter != accounts_map.end()) {
//code to display account information
} else {
cout << "Error: Account not found\n";
}
}
If you are using C++11 or later, consider using auto instead of const_iterator explicitly, that would also fix the error:
auto m_iter = accounts_map.find(account);

Strange issue when iterating a STL set<CStudent> in C++

I have class CStudent and class CStudentGroup which has one member set<CStudent>. I populate the set of an object from the class CStudentGroup. I want to iterate this set and print via the getter of the CStudent class the points of all the students in the set. I do this by assigning the set to a new one. Then I iterate the set with an iterator it. However the compiler gives an error *the object has type qualifiers that are not compatible with the member function CStudent::getP; object type is const CStudent* I would like to ask how can I do this? Thank you in advance.
#include <iostream>
#include <string>
#include <set>
using namespace std;
class CStudent {
string m_strFN;
int m_iPoints;
public:
void setP(int p) {
m_iPoints = p;
}
void setFN(string f) {
m_strFN = f;
}
int getP() {
return m_iPoints;
}
string getFN() {
return m_strFN;
}
CStudent() {
m_strFN = "123456789";
m_iPoints = 70;
}
CStudent(const CStudent& stud) {
m_strFN = stud.m_strFN;
m_iPoints = stud.m_iPoints;
};
CStudent(int p) {
m_iPoints = p;
}
};
class CStudentGroup {
set<CStudent> m_setStudents;
public:
CStudentGroup(const CStudentGroup& grp) {
m_setStudents = grp.m_setStudents;
};
CStudentGroup(set<CStudent> st) {
m_setStudents = st;
}
CStudentGroup() {
CStudent s1(50), s2, s3(s2);
m_setStudents.insert(s1);
m_setStudents.insert(s2);
m_setStudents.insert(s3);
}
set<CStudent> gets() {
return m_setStudents;
}
};
int main()
{
CStudentGroup group;
set<CStudent> stt = group.gets();
for (set<CStudent>::iterator it = stt.begin(); it != stt.end(); it++) {
cout << it->getP() << endl;
}
}
std::set stores keys as constant value, as a change of a key can be a cause of change to its position in red-black tree (typical std::set implementation).
In other words, your CStudent object are considered const or unchangeable.
It's possible to problem here using std::set::const_iterator as a type of iterator inside the loop in combination with std::set::cbegin() and std::set::cend() calls.
Another possible solution is to use foreach-loop:
for (CStudent const& student : stt)
std::cout << student.getP() << '\n';
Moreover, you would need to change CStudent::getP() declaration to be a constant method.
Objects inside a std::set are always const. That is to protect them, in case you decide you change any key field, the sorting order changes and the set invariant is broken.
So basically the set<CStudent>::iterator is a const_iterator and you get a const CStudent& reference. Since your CStudent::getP is not a const member function, you cannot use it.
Solution, make it const:
int getP() const {
return m_iPoints;
}
Naturally, you want to mark as const any function that does not change the contents of your object, not only the ones std::set requires you to do so. This is sometimes called const-correctness and is always a good practice.

Reading data from a vector of class of vector - c ++

I have a class which made of a ints and strings, but I also have a vector inside that class. I have to read the records from a file and then after parsing each line, put the info in my vector of class. I have to get the basic package information like ID and name and then add the services which are offered with that package, so I can have 10 records that are from one package but they are different in type of services. For now I am trying to work out putting the data in each package and access the data from each element, but when I am trying to get the data from the vector inside the class, my compiled file crashes. It also prints out the 1233 and foo, but not the test. Any ideas why is that?
int main()
{
vector<package> packs;
package pack;
pack.ID = 1233;
pack.name = "foo";
packs.push_back(pack);
pack.putData("test",12);
cout << packs[0].name << endl;
cout << packs[0].ID << endl;
cout << packs[0].bservice[0].serviceID << endl; //[b]Crashes in this line[/b]
return 0;
}
Defined class is:
class package
{
public:
class aservice
{
public:
int serviceID;
string othername;
};
int ID;
string name;
vector<aservice> bservice;
void putData(string name1, int serviceID1)
{
aservice obj;
obj.serviceID = serviceID1;
obj.othername = name1;
bservice.push_back(obj);
}
};
Here you make a copy of pack when you push_back into the vector:
packs.push_back(pack);
And here you access pack, not the copy stored in your vector
pack.putData("test",12);
So the bservice vector you are trying to access is actually empty, which is why your code crashes when you try to access it here:
cout << patients[0].bservice[0].serviceID << endl; // patients[0].bservice is empty!!!
You can avoid this by pushing back after the call to putData:
vector<package> packs;
package pack;
pack.ID = 1233;
pack.name = "foo";
pack.putData("test",12);
packs.push_back(pack);
You can also avoid it by not trying to access a vector without first checking whether it is empty.
Ideally you should strive to design classes than can be constructed into a useful state, as opposed to default constructing them and adding data step by step via setters. This is particularly important if the data are inter-related and the class must maintain invariants.
packs.push_back(pack);
Is going to push a copy of pack into your vector. You will therefore have two specific instances : if you call putData on one of those, the other one will not be modified itself !
Therefore, when writing
patients[0].bservice[0]
your application crashes because you did not putData inside patients[0], only inside pack - which is, once again, a different object.
You should modify your vector so it stores pointers to package's, and push the adress of pack inside.
pack.push_back(pack);
Assuming the first pack is actually packs, this pushes a copy of pack onto the vector.
pack.putData("test",12);
This modifies the local variable pack, but not the copy you pushed onto the vector. That still contains an empty bservice vector.
cout << patients[0].bservice[0].serviceID << endl;
Assuming that patients is actually packs, this erroneously attempts to read from the empty bservice vector.
You either want to call putData before packs.push_back(pack), or call it on packs.back() rather than the local pack.
Try this:
#include <vector>
#include <iostream>
using namespace std;
class package
{
public:
package(int inID, const string& inName ) : ID(inID), name(inName)
{
}
void putData(string name1, int serviceID1)
{
aservice obj;
obj.serviceID = serviceID1;
obj.othername = name1;
bservice.push_back(obj);
}
void Print() const
{
cout << ID << endl;
cout << name << endl;
vector<aservice>::const_iterator iter;
iter = bservice.begin();
for (; iter != bservice.end(); ++iter)
{
cout << iter->serviceID << " " << iter->othername << endl;
}
}
private:
class aservice
{
public:
aservice() {};
int serviceID;
string othername;
};
int ID;
string name;
vector<aservice> bservice;
};
typedef vector<package> PackContainer;
typedef vector<package>::iterator PackContainerIterator;
typedef vector<package>::const_iterator PackContainerConstIterator;
void PrintAll(const PackContainer& packs)
{
PackContainerConstIterator iter = packs.begin();
for (; iter != packs.end(); ++iter)
{
iter->Print();
}
}
int main()
{
PackContainer packs;
package pack( 1233, "foo");
pack.putData("test",12);
packs.push_back(pack);
PrintAll(packs);
return 0;
}

How to build a class for all the for loops in main() (Just to reduce code in the main function)

For loop iterates through the vector and show all strings on the console successfully:
int main(int argc, const char * argv[])
{
vector<string>stringVector;
string newStringEntry;
cin>>newStringEntry;
stringVector.push_back(newStringEntry);
cin>>newStringEntry;
stringVector.push_back(newStringEntry);
for (vector<string>::iterator i = stringVector.begin(); i != stringVector.end(); ++i)
{
cout<<*i<<endl;
}
}
But this makes the code hard to read (said our teacher) now we have to build a class for the for loop and the main should look like this after the change:
int main(int argc, const char * argv[])
{
vector<string>stringVector;
string newStringEntry;
cin>>newStringEntry;
stringVector.push_back(newStringEntry);
cin>>newStringEntry;
stringVector.push_back(newStringEntry);
showStrings();
}
The problem I see is that I cannot just copy paste the for loop to an own class because
the vector name I declare in the main is not known in the class so I get an error.
How can I get this working?
My class so far looks like this:
class VectorHelp {
void showStrings() const
{
for (vector<string>::iterator i = vectorName.begin();
i != vectorName.end();
++i)
{
cout << *i << endl;
}
}
};
You should store your vector in your class, or pass it to your function.
You need to pass your vector<strings> as a method parameter:
VectorHelp::showStrings(stringVector);
...
static void showStrings(const vector<string>& stringVector)
Note that the name of your formal and actual parameter do not need to be the same. Also note that showStrings should be a class member function (i.e. static), not an instance member function.
Finally, note that printing without loops can be done using facilities of the standard C++ library:
ostream_iterator<string> out_it (cout, "\n");
copy (stringVector.begin(), stringVector.end(), out_it);
I bet you mean something like this:
class VectorHelp
{
private:
std::vector<std::string> stringVector
public:
void add(const string& str)
{
stringVector.push_back(str);
}
void printStrings()
{
for (vector<string>::iterator i = stringVector.begin(); i != stringVector.end(); i++)
{
cout << *i << endl;
}
}
}
Not sure though if the for loop you provided is the correct one, I don't really use iterators and rather just use indexes.
But the above class is a class that you can instatiate and add strings to to print them out later!

map inheritance

I have a parent class which holds a map and n the child class i have used to inherit that class with for some reason can't access the map which i can't under stand why, i want to access the values inside the map.
my code is as follows
//HEADER FILE
#include <iostream>
#include <map>
using namespace std;
//////PARENT CLASS
struct TTYElementBase
{
//some code here
};
class element
{
public:
std::map<char,std::string> transMask;
std::map<char,std::string>::iterator it;
void populate();
};
//////CHILD CLASS .HPP
class elementV : public element
{
public :
std::string s1;
std::string s2;
elementV();
friend ostream &operator<< (ostream &, const elementV &);
void transLateMask();
};
//CPP FILE
#include "example.h"
#include <iostream>
elementV::elementV()
{
}
void elementV::transLateMask()
{
for ( it=transMask.begin() ; it != transMask.end(); it++ )
cout << (*it).first << endl;
}
int main()
{
elementV v;
v.transLateMask();
}
// ' OUTPUT IS NOTHING I DONT KNOW WHY?'
output is nothing but i need to acces the map fron the parent class, what am i doing wrong?
any help i will be very gratefull
Thanks
Does the map contain an entry for 'D' when you call transLateMask()? You'll get undefined behaviour (perhaps a runtime error) if it doesn't, since you don't check the result of find(). Something like this would be more robust:
auto found = transMask.find('D');
if (found == transMask.end()) {
// handle the error in some way, perhaps
throw std::runtime_error("No D in transMask");
}
std::string str = found->second;
(If you're not using C++11, then replace auto with the full type name, std::map<char,std::string>::const_iterator).
Alternatively, C++11 adds an at() method which throws std::out_of_range if the key is not found:
std::string str = transMask.at('D')->second;
The find() method of the std::map can return an iterator that is "one beyond the end" of the map, i.e. equals to result of end(). This means there's no such entry in the map. You have to check for that:
typedef std::map<char,std::string> mymap;
mymap::const_iterator i = transMask.find('D');
if ( i == transMask.end()) {
std::cerr << "'D' not found" << std::endl;
} else {
...
}