What is the proper encapsulation syntax? - c++

I have publication and library two classes and in publication class. How to manipulate(as encapsulation) genre, media, and target_age, If I want them to be separate classes. It's not class inside another class.
The genre have more type's as (fiction, non-fiction, self-help, performance) as well as media and age. I have done my research I'm serchin for the proper syntax for it.
class Publication {
private:
string title;
string authore;
string copyright;
Genre genre;
Media media;
Age target_age;
string isbn;
bool checked_out;
string patron_name;
string patron_phone;
public:
void check_out(string patron_name, string patron_phone ){}
void check_in(){}
bool is_checked_out(){}
string to_string(){}
};

The best way to encapsulate is to keep everything private. Create constant getters for stuff that might be read from the outside, and initialize everything in the constructor. After all, things like author/title/etc. should not ever change for an instance of a real book right? Have a look at the following snippet:
class Publication {
private:
string _title;
string _author;
Genre _genre;
public:
void check_out(string patron_name, string patron_phone );
void check_in();
bool is_checked_out() const;
string to_string() const;
string get_title() const { return _title; }
string get_author() const { return _author; }
const Genre& get_genre() const { return _genre; }
Publication(string author, string title, Genre genre) : _author(auth), _title(title), _genre(genre)
{ }
};

Related

Getter Setter for class

I was working on homework that my instructor wanted me to write a class named Species with setter and getter functions. I wrote that code but I can't set or get any value when I run it. Can you help me?
class Species
{
private:
string name;
string country;
int population;
int growthrate;
public:
int year;
void setName(string NameS){
NameS=name;
}
void setCountry(string CountryS){
CountryS=country;
}
void setPopulation(int pop){
pop=population;
}
void setGrowthRate(int GrowRth){
GrowRth=growthrate;
}
void setYear(int syear){
syear=year;
}
string getName() {
return name;
}
string getCountry() {
return country;
}
int getPopulation() {
return population;
}
int getGrowthrate() {
return growthrate;
}
double e=2.71828182;
double calculatePopulation() {
int b=growthrate*year;
int a=pow(e,b);
return population*a;
}
};
First of all. Your class has fields like:
string name;
string country;
int population;
int growthrate;
And your methods are like:
void setName(string NameS){
NameS=name;
}
So you want to set NameS value to the name which makes no sense.
You should assign the field like name to be equal to nameS not the opposite.
Generally, a setter should look like this.
void setVariable(const VariableType& var){
this->var=var;
}
What you did was var=this->var.
Btw, you should make your getter-s const
You should use "this" keyword to set the value to object of the class.
this: to refer current class instance variable. The this keyword can be used to refer current class instance variable.
for example:
void setName(string name){
this.name=name;
}
void setGrowthRate(int growthrate){
this.growthrate=growthrate;
"this" is very helpful in please learn more about it.

Inheritance and small number of parameters

Uncle Bob in his Clean Code suggests that no more than 3 arguments should a function get:
Functions that take three arguments are significantly harder to
understand than dyads. The issues of ordering, pausing, and ignoring
are more than doubled. I suggest you think very carefully before
creating a triad.
But what about CTOR arguments in class inheritance hierarchy? What if each class in hierarchy adds a new field and you should initialize them in CTOR. See an example below:
class Person
{
private:
std::string m_name;
int m_age;
public:
Person(const std::string& name, const int age);
std::string getName() const { return m_name; }
int getAge() const { return m_age; }
~Person();
};
class Student : public Person
{
private:
std::string m_university;
int m_grade;
public:
Student(const std::string& name, const int age, const std::string& university, const int grade);
std::string getUniversity() const { return m_university; }
int getGrade() const { return m_grade; }
~Student();
};
See how Student gets 4 arguments, while Person gets only 2 and Student adds two more. So how we should handle this?
There are several ways.
Combine multiple parameters into a struct
struct PersonInfo {
std::string name;
int age;
};
struct StudentInfo {
PersonInfo person_info;
std::string university;
int grade;
};
Person::Person(const PersonInfo &info) :m_name(info.name), m_age(info.age) {}
Student::Student(const StudentInfo &info) : Person(info.person_info), m_university(info.university), m_grade(info.grade) {}
Default initialize data members and set them with setter utilities
Person::Person() : m_age(0) {}
void Person::set_age(int age) { m_age = age; }
Student() : m_grade(0) {} // Person is default constructed.
void Student::set_grade(int grade) { m_grade = grade; }
i'd say this was just a suggestion. it's fully up to you - how many arguments should your functions get.
but if you prefer to follow the rule, make some sort of parameters holder, like:
class Student
{
public:
struct StudentParameters
{
...
};
Student(name, age, const StudentParameters &sp);
...
};
You're confusing two distinct meanings of the word function.
The first meaning is more related to the original mathematical meaning of the word. In this case, function is a named relation between one or more inputs and exactly one output. The "Clean Code" rules refers to this meaning, and tells you that more should be limited to 3 inputs.
The alternative meaning in C++ refers to a block of code, which may or may have inputs, which may or may have an output, which may or may have a name.
And yes, even in the latter sense, constructors are unusual functions. They never have a return type, not even void, and they don't have names. So you can rationalize that they're also special when it comes to their number of input arguments.

How to serialize this class into XML or JSON

I have a list of objects derived from a class named "Campus" which contains two strings, one int and two lists : one for "Students", the other is for "Teachers", before closing the program, I want to save the campus objects and of course the "Student" and "Teachers" objects contained on their lists, I want to serialize those data in an XML or JSON format or even anything else then store the result in a file.
Can somebody give me the fastest way to do the serialization with a library (that is not heavy as boost) in XML or JSON or another solution. When it comes to deal with JSON or XML serialization, I don't know what to do !
EDIT: is this feasible with RapidJSON ?
class Campus
{
private:
std::string city;
std::string region;
int capacity;
std::list<Student> students;
std::list<Teacher> teachers;
}
class Student
{
private:
int ID;
std::string name;
std::string surname;
}
class Teacher
{
protected:
int ID;
std::string name;
std::string surname;
};
You can use this C++ serialization library : Pakal persist
#include "XmlWriter.h"
class Campus
{
private:
std::string city;
std::string region;
int capacity;
std::list<Student> students;
std::list<Teacher> teachers;
public:
void persist(Archive* archive)
{
archive->value("city",city);
archive->value("region",region);
archive->value("capacity",capacity);
archive->value("Students","Student",students);
archive->value("Teachers","Teacher",teachers);
}
}
class Student
{
private:
int ID;
std::string name;
std::string surname;
public:
void persist(Archive* archive)
{
archive->value("ID",ID);
archive->value("surname",surname);
archive->value("name",name);
}
}
class Teacher
{
protected:
int ID;
std::string name;
std::string surname;
public:
void persist(Archive* archive)
{
archive->value("ID",ID);
archive->value("surname",surname);
archive->value("name",name);
}
};
Campus c;
XmlWriter writer;
writer.write("campus.xml","Campus",c);
Unfortunately C++ doesn't support reflection, so it can't automagically figure out the parameter names.. but check out this answer which looks like it'll be close to what you want: https://stackoverflow.com/a/19974486/1715829

How to manage one to many relationship between objects? ( move related )

First of all I wanna say that I am very new to CPP (I started with cpp11) :)
Considering the following entities: Student(first name + last name) and Group (description + more students).
I created the following 2 classes in C++:
class Student
{
private:
std::string firstName;
std::string lastName;
Student(const Student &student);
Student& operator=(const Student &student);
public:
Student():firstName(""), lastName("") { }
Student(std::string firstName, std::string lastName):firstName(firstName), lastName(lastName) { }
Student(const Student &&student):firstName(student.firstName), lastName(student.lastName) { }
Student& operator=(const Student &&student) { this->firstName=student.firstName; this->lastName=student.lastName; return *this; }
std::string GetFirstName() const { return this->firstName; }
std::string GetLastName() const { return this->lastName; }
};
class Group
{
private:
std::string description;
std::vector<std::shared_ptr<Student>> students;
Group(const Group &group);
Group& operator=(const Group &group);
public:
explicit Group():description(""), students(std::vector<std::shared_ptr<Student>>()) { }
explicit Group(std::string description) :description(description), students(std::vector<std::shared_ptr<Student>>()) { }
void NewStudent(Student &&student) { students.push_back(std::make_shared<Student>(std::move(student))); }
std::vector<std::shared_ptr<Student>> GetStudents() const { return students; }
};
In main I have this:
Student s1("fn1","ln1");
Student s2("fn2","ln2");
//Student s3("fn3","ln3");
Group cppGroup("C plus plus");
cppGroup.NewStudent(std::move(s1));
cppGroup.NewStudent(std::move(s2));
cppGroup.NewStudent(Student("fn3", "ln3"));
//cppGroup.NewStudent(s3);
std::vector<std::shared_ptr<Student>> cppStudents=cppGroup.GetStudents();
My question is related to NewStudent method.
In the first 2 cases the parameter is move(s) and in the third case is Student(...).
My guess is that Student("fn3", "ln3") is the same as Student s3("fn3, "ln3") but if i pass s3 to the function it just won't compile with the following error: cannot convert from Student to Student&&
PS: I would appreciate if you helped me understand how to make the example I considered ideal.
Thank you very much.
LE: I think I understand what is happening, Visual Studio shows the following error: cannot convert an lvalue to a rvalue so my guess is that if I pass to NewStudent s3 it doesn't know how to convert it to a rvalue but if i pass it Student("fn3", "ln3") if will call the move constructor.
If that is really your design, you can simplify it a lot and do away with all the smart pointers and custom structors:
class Student
{
private:
std::string firstName;
std::string lastName;
public:
Student(std::string firstName, std::string lastName):firstName(firstName), lastName(lastName) { }
std::string GetFirstName() const { return this->firstName; }
std::string GetLastName() const { return this->lastName; }
};
class Group
{
private:
std::string description;
std::vector<Student> students;
public:
explicit Group(std::string description) :description(description) { }
void NewStudent(Student student) { students.push_back(student); }
std::vector<Student> GetStudents() const { return students; }
};
Student("fn3", "ln3") is a temporary object which does not posses a name. The compiler decides it can give it away because you have no chance of using it again. In the case of Student s2("fn2","ln2")
you are keeping a reference to the object in the variable s2. So you must explicitly give it away with the move statement.
I suggest changing your design and using smart pointers.
Have one container for all of the students.
A Group of students would have one or more smart pointers to students in the "all students" container.
This design allows you to have different themed groups without copying the student objects. The Group contain would contain copies of the smart pointers.
Using this design, you can also create indexes to order your students by differing criteria. For example, you could have an index of students sorted by first name and another index of students sorted by last name.

an error within context

can somebody please explain my mistake, I have this class:
class Account
{
private:
string strLastName;
string strFirstName;
int nID;
int nLines;
double lastBill;
public:
Account(string firstName, string lastName, int id);
friend string printAccount(string firstName, string lastName, int id, int lines, double lastBill);
}
but when I call it:
string reportAccounts() const
{
string report(printAccountsHeader());
for(list<Account>::const_iterator i = listOfAccounts.begin(); i != listOfAccounts.end(); ++i)
{
report += printAccount(i->strFirstName, i->strLastName, i->nID, i->nLines, i->lastBill);;
}
return report;
}
I receive error within context, can somebody explain why?
I imagine the full error has something to do with "These members are private within context" and some line numbers.
The issue is that i->strFirstName is private from the perspective of the reportAccounts() function. A better solution may be:
class Account{
private:
string strLastName;
string strFirstName;
int nID;
int nLines;
double lastBill;
public:
Account(string firstName, string lastName, int id);
string print() const
{
return printAccount(this->strLastName, this->strFirstName, this->nID,
this->nLines, this->lastBill);
}
};
And then
string reportAccounts() const {
string report(printAccountsHeader());
for(list<Account>::const_iterator i = listOfAccounts.begin(); i != listOfAccounts.end(); ++i){
report += i->print();
}
return report;
}
Another option is to make printAccount take a reference to an Account (friend printAccount(const Account& account)), and it can then access the private variables through the reference.
However, the fact that the function is called print Account suggests that it might be better as a public class function.
You're declaring that function printAccount is friend of class Account. But in the example, you're accessing the members of the class (i->strFirstName ...) in the function reportAccounts. This latter is not declared as friend.
You are missing a semicolon in the class definition.
class Account{
private:
string strLastName;
string strFirstName;
int nID;
int nLines;
double lastBill;
public:
Account(string firstName, string lastName, int id);
friend string printAccount(string firstName, string lastName, int id, int lines, double lastBill);
};
^--- see the semicolon here?
That shouldn't be the whole error.. there should be something more..
by the way your friend syntax seems correct, but in reportAccounts you seem to use all the fields of Account class that are private, like strFirstName and the name of the function is reportAccounts not printAccounts so probably you just made a method friend but you are trying to access private fields with another one.