I am planning to use json c++ at https://github.com/nlohmann/json#examples . After reading its simple examples, I still have no idea how to use it with my own object? For example, I have a class
class Student
{
public:
Student(int id, string const& name)
: m_id(id), m_name(name)
{}
private:
int m_id;
string m_name;
};
How to use json to read and write (deserialize and serialize) a Student object?
this is another way to do the conversion from json to custom class, that actually fits the best practices defined in the official repo from nlohmann here
https://github.com/nlohmann/json#arbitrary-types-conversions
h:
#ifndef STUDENT_H
#define STUDENT_H
#include<string>
#include "json.hpp"
class Student
{
public:
Student();
Student(int id, const std::string &name);
int getId() const;
void setId(int newId);
std::string getName() const;
void setName(const std::string &newName);
private:
int m_id;
std::string m_name;
};
//json serialization
inline void to_json(nlohmann::json &j, const Student &s)
{
j["id"] = s.getId();
j["name"] = s.getName();
}
inline void from_json(const nlohmann::json &j, Student &s)
{
s.setId((j.at("id").get<int>()));
s.setName(j.at("name").get<std::string>());
}
#endif // STUDENT_H
cpp:
#include "Student.h"
#include<string>
Student::Student() : Student(0, "")
{
}
Student::Student(int id, const std::string &name) : m_id{id}, m_name{name}
{
}
int Student::getId() const
{
return this->m_id;
}
void Student::setId(int newId)
{
m_id = newId;
}
std::string Student::getName() const
{
return this->m_name;
}
void Student::setName(const std::string &newName)
{
this->m_name = newName;
}
example:
Student s{0, "x"};
nlohmann::json studentJson = s;
std::cout << "Student from object: " << s.getId() << std::endl;
std::cout << "Student from json: " << studentJson.at("id").get<int>() << std::endl;
//String
std::string jSt = studentJson.dump(); //{"id":0,"name":"x"}
Student s2 = studentJson;
Student s3 = nlohmann::json::parse(jSt);
This library doesnt seems to have any interaction with a class for serialization and deserialization.
But you can implement it yourself with a constructor and a getter.
using json = nlohmann::json;
class Student
{
public:
Student(int id, string const& name)
: m_id(id), m_name(name)
{}
Student(json data)
: m_id(data["id"]), m_name(data["name"])
{}
json getJson()
{
json student;
student["id"] = m_id;
student["name"] = m_name;
return student;
}
private:
int m_id;
string m_name;
};
Related
Let us look at the following class:
ProjectManager.hh
#ifndef INPUT_CPP_FILES_PROJECT_MANAGER_HH
#define INPUT_CPP_FILES_PROJECT_MANAGER_HH
#include <string>
#include "Employee.hh"
#include "Programmer.hh"
#include "Tester.hh"
namespace OrganizationNamespace {
class ProjectManager : public Programmer, public Tester {
public:
ProjectManager():Employee(), Programmer(), Tester()
{}
explicit ProjectManager(const std::string& id):Employee(id), Programmer(), Tester()
{}
ProjectManager(std::string&id, std::string &name):Employee(id, name), Programmer(), Tester()
{}
ProjectManager(std::string &id, std::string &name, std::string &programming_language):Employee(id, name), Programmer(programming_language), Tester()
{}
ProjectManager(std::string &id, std::string &name, std::string &programming_language, std::string &tool):Programmer(programming_language), Tester(tool),Employee(id, name)
{}
ProjectManager(ProjectManager const & pm)
{
this->id_ = pm.id_;
this->name_ = pm.name_;
this->programming_language_ = pm.programming_language_;
this->tool_ = pm.tool_;
}
void print() const {
std::cout << "(" << Employee::id_ << ", " << Employee::name_ << ", " << Programmer::programming_language_ << "," << Tester::tool_ << ")"
<< std::endl;
}
};
}
#endif //INPUT_CPP_FILES_PROJECT_MANAGER_HH
main.cpp
#include "Employee.hh"
#include "Programmer.hh"
#include "ProjectManager.hh"
int main()
{
std::string id = "id";
std::string name = "name";
std::string programming_language = "programming-language";
std::string testing_tool = "testing-tool";
OrganizationNamespace::ProjectManager pm(id, name, programming_language, testing_tool);
pm.print();
}
Output
C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe
(id, name, ,)
Process finished with exit code 0
As we can see the program is not giving the correct output.
The expected output is:
C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe
(id, name, programming-language, testing-tool)
Process finished with exit code 0
How can I implement constructors in ProjectManager so that they give the correct output?
Additional Source Code
Employee.hh
#ifndef INPUT_CPP_FILES_EMPLOYEE_HH
#define INPUT_CPP_FILES_EMPLOYEE_HH
#include <iostream>
#include <string>
namespace OrganizationNamespace {
class Employee {
protected:
std::string id_;
std::string name_;
public:
Employee() : id_ (""), name_("") {}
Employee(const std::string &id) : id_(id), name_("") {}
Employee(const std::string &id, const std::string &name) : id_(id), name_(name) {}
Employee(Employee const & emp)
{
this->id_ = emp.id_;
this->name_ = emp.name_;
}
void print() const
{
std::cout << "(" << id_ << ", " << name_ << ")" << std::endl;
}
};
}
#endif //INPUT_CPP_FILES_EMPLOYEE_HH
Programmer.hh
#ifndef INPUT_CPP_FILES_PROGRAMMER_HH
#define INPUT_CPP_FILES_PROGRAMMER_HH
#include "Employee.hh"
namespace OrganizationNamespace {
class Programmer : public virtual Employee {
protected:
std::string programming_language_;
public:
Programmer() : Employee(), programming_language_("") {}
Programmer(std::string id) : Employee(id) {}
Programmer(std::string id, std::string name) : Employee(id, name) {}
Programmer(std::string id, std::string name, std::string programming_language) : Employee(id, name),
programming_language_(
programming_language) {}
void print() const {
std::cout << "(" << id_ << ", " << name_ << ", " << programming_language_ << ")" << std::endl;
}
};
}
#endif //INPUT_CPP_FILES_PROGRAMMER_HH
Tester.hh
#ifndef INPUT_CPP_FILES_TESTER_HH
#define INPUT_CPP_FILES_TESTER_HH
#include <string>
#include "Employee.hh"
namespace OrganizationNamespace {
class Tester : public virtual Employee {
protected:
std::string tool_;
public:
Tester() : Employee(), tool_("") {}
Tester(std::string id) : Employee(id) {}
Tester(std::string id, std::string name) : Employee(id, name) {}
Tester(std::string id, std::string name, std::string tool) : Employee(id, name), tool_(tool) {}
void print() const {
std::cout << "(" << id_ << ", " << name_ << ", " << tool_ << ")" << std::endl;
}
};
}
#endif //INPUT_CPP_FILES_TESTER_HH
The problem is that when you call the ProjectManger cosntructor you also call the overloaded cosntructors of Programmer and Tester, the versions you are calling are those which take as parameter one std::string, those constructors change the value of Employee::id_, actually you never changed other values.
For fixing the problem you must change
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer(programming_language),
Tester(tool)
{}
in
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer("","",programming_language),
Tester("","",tool)
{}
Your 4-parameter ProjectManager constructor calls the 1-parameter Programmer constructor, which does not set the programming_language_ member. The same for the Tester constructor.
So neither of the member variables for your two classes get anything other than default initialized to empty strings.
The solution is to pass the proper values in the proper parameters, and construct the base classes in the correct order.
namespace OrganizationNamespace {
class ProjectManager : public Programmer, public Tester {
public:
// ...
ProjectManager(std::string &id, std::string &name, std::string &programming_language):
Employee(id, name), Programmer(id, name, programming_language), Tester()
{}
ProjectManager(std::string &id, std::string &name, std::string &programming_language, std::string &tool):
Employee(id, name), Programmer(id, name, programming_language), Tester(id, name, tool)
{}
// ...
};
Even though the id and name parameters won't be used by the Programmer or Tester constructors (because the Employee base class they are passed to is virtual and will be constructed by the most derived object, ProjectManager), we still pass in those values. There are a couple of reasons for that.
Because we already have these string objects, and the constructors take their parameters as references, we avoid the overhead of constructing temporary string objects that will be unused.
The code does not rely on the assumption that the id and name paramaters are unused. It is possible that a future change to the constructors will make use of one or both parameters. By passing in the expected values that can avoid future bugs.
I have some problem with overloading += operator
I want to add a item to vector (getAuthorList) with += operator
How can I do it in main ?
Code snippet (header file) :
class Author {
public:
Author(std::string firstName, std::string lastname, std::string affiliation);
std::string getFirstName();
std::string getLastName();
std::string getAffiliation();
void setFirstName(std::string);
void setLastName(std::string);
void setAffiliation(std::string);
void printFullName();
friend std::ostream& operator<<(std::ostream& output, const Author& author);
private:
std::string firstName;
std::string lastname;
std::string affiliation;
};
class Publication {
public :
Publication(std::string tiltle, Date publishDate, std::string publisher);
vector<Author> getAuthorList();
Author& operator+=(Author);
private:
vector<Author> authorList;
};
You can overload += operator like this
void operator+=(Author);
Change the operator return type to void as you are storing it in Publication class so it does not make any sense to return The same author from this operator.
you can write the operator definition like this
void Publication::operator+=(Author auth){
this->authorList.push_back(auth);
}
here is the working example:
#include <string>
#include <vector>
#include <iostream>
class Author {
public:
Author(const std::string& name):
Name(name){
}
const std::string& getName() const{
return Name;
}
private:
std::string Name;
};
class Publication {
public :
Publication(){
}
void operator+=(Author);
void getAuthorList(){
for (const auto& author: authorList){
std::cout << author.getName() << std::endl;
}
}
private:
std::vector<Author> authorList;
};
void Publication::operator+=(Author auth){
this->authorList.push_back(auth);
}
int main(){
Publication pub;
Author auth("Alice");
pub += auth;
Author auth2("Mark");
pub += auth2;
pub.getAuthorList();
}
Note: I just tried to make simple.
You could use the std::vector method called push_back inside the implementation block of your overloaded operator.
I've done the Harvard CS50 Course and worked with python a fair bit. I'm now doing a C++ course (Microsoft's) and the learning exercise has me creating a few classes. The exercise specifically tasks me to instantiate a few objects in main and return some values;
#include <iostream>
#include "School.h"
int main()
{
Student student1("Joe", "Bloggs", 31, "123 Fake Street", "London");
Student student2("Fred", "Adams", 24, "95 Something Avenue", "Manchester");
Student student3("John", "Doe", 90, "44a Old Man Lane", "Kettering");
Course course1("Introduction to Psychology");
course1.addStudent(student1);
course1.addStudent(student2);
course1.addStudent(student3);
Teacher teacher1("Helen", "Professorson", 48, "15 Teacher Way", "Kent");
course1.addTeacher(teacher1);
std::cout << course1.getCourseName() << std::endl;
teacher1.GradeStudent();
}
I'm using a header file and cpp file to define the classes, School.h:
#pragma once
#include <string>
class Person
{
public:
// Constructors and Destructors
Person();
Person(std::string, std::string); // First and Last Name
Person(std::string, std::string, int, std::string, std::string, std::string); // fName, lName, Age, Address, City, Phone
~Person();
// Member functions
std::string getFirstName();
void setFirstName(std::string);
std::string getLastName();
void setLastName(std::string);
int getAge();
void setAge(int);
std::string getAddress();
void setAddress(std::string);
std::string getCity();
void setCity(std::string);
std::string getPhone();
void setPhone(std::string);
private:
std::string _fName;
std::string _lName;
int _age;
std::string _address;
std::string _city;
std::string _phone;
};
class Student : public Person
{
public:
// Constructors and Destructors
// Member Functions
void SitInClass();
};
class Teacher : public Person
{
public:
// Member Functions
void SitInClass();
void GradeStudent();
};
class Course
{
public:
// Constructors and Desctructors
Course();
Course(std::string); // course name
~Course();
// Member functions
void addStudent(Student);
void addTeacher(Teacher);
// Getters and Setters
std::string getCourseName();
void setCourseName(std::string);
private:
// Member variables
std::string _courseName;
Student _students[30];
Teacher _teacher;
};
School.cpp:
#include "School.h"
#include <iostream>
#include <string>
// Constructors
Person::Person()
{
std::string _fName{};
std::string _lName{};
int _age{};
std::string _address{};
std::string _city{};
std::string _phone{};
}
Person::Person(std::string fName, std::string lName)
{
std::string _fName{ fName };
std::string _lName{ lName };
int _age{};
std::string _address{};
std::string _city{};
std::string _phone{};
}
Person::Person(std::string fName, std::string lName, int age, std::string address, std::string city, std::string phone)
{
std::string _fName{ fName };
std::string _lName{ lName };
int _age{ age };
std::string _address{ address };
std::string _city{ city };
std::string _phone{ phone };
}
// Destructor
Person::~Person()
{
}
std::string Person::getFirstName()
{
return this->_fName;
}
void Person::setFirstName(std::string fName)
{
this->_fName = fName;
}
std::string Person::getLastName()
{
return this->_lName;
}
void Person::setLastName(std::string lName)
{
this->_lName = lName;
}
int Person::getAge()
{
return this->_age;
}
void Person::setAge(int age)
{
this->_age = age;
}
std::string Person::getAddress()
{
return this->_address;
}
void Person::setAddress(std::string address)
{
this->_address = address;
}
std::string Person::getCity()
{
return this->_city;
}
void Person::setCity(std::string city)
{
this->_city = city;
}
std::string Person::getPhone()
{
return this->_phone;
}
void Person::setPhone(std::string phone)
{
this->_phone = phone;
}
void Student::SitInClass()
{
std::cout << "Sitting in main theater" << std::endl;
}
void Teacher::SitInClass()
{
std::cout << "Sitting at front of class" << std::endl;
}
void Teacher::GradeStudent()
{
std::cout << "Student Graded" << std::endl;
}
Course::Course()
{
Student* _students;
Teacher* _teacher;
std::string _name{};
}
Course::Course(std::string name)
{
Student* _students[30];
Teacher* _teacher;
std::string _name{ name };
}
Course::~Course()
{
}
void Course::addStudent(Student student)
{
// TODO: Loop through _students and insert new student in
}
void Course::addTeacher(Teacher teacher)
{
this->_teacher = &teacher;
}
std::string Course::getCourseName()
{
return this->_name;
}
void Course::setCourseName(std::string name)
{
this->_name = name;
}
I actually haven't been taught inheritance yet, but since both Student and Teacher needed the same variables (name, age, address etc.) I decided it'd be sensible.
Having a few problems though:
My instantiations of Student and Teacher in main.cpp aren't correct. I think because they are inheriting from Person(?). How do I create a constructor within these derived classes? I googled this but the solutions didn't seem to work.
The Course Class requires an array of Students. Do I have to specify a size of the array in the header file? It seems silly that I've specified 30 in both the header file and the cpp file, but VSstudio complains if I don't.
I'm using strings here. I have previously learned from a different course about char* and memory regarding strings. How many chars are assigned to all of these string class variables? If I instantiate a Students with name "Joe" and then want to later change his name to "Joseph" using student1.SetFirstName, is that going to cause segmentation faults?
Thanks, I figured it out mostly...
I needed to create constructors in Student and Teacher with the same input variables as the Person class, and then call the Person constructor in the Student consturctor:
Student::Student()
{
}
Student::Student(std::string fName, std::string lName)
: Person(fName, lName)
{
}
Student::Student(std::string fName, std::string lName, int age, std::string address, std::string city, std::string phone)
: Person(fName, lName, age, address, city, phone)
{
}
You do not need to specify array size in the constructor:
Header file looks like this:
class Course
{
...
private:
// Member variables
std::string _name;
Student* _students[30];
Teacher* _teacher;
};
And the constructor looks like this:
Course::Course()
: _students{ 0 }, _teacher{ 0 }, _name{}
{
}
To initialise every array item to 0.
Not so sure on still...
I have a class CPerson and I want to initialize a vector of type CPerson with object variables. However the compiler says that type name is not allowed. I would like to ask why is that?
class CPerson {
protected:
string m_strName;
Sex m_Sex;
Titles m_Title;
public:
CPerson() {
m_strName = "Peter Petrov";
m_Sex = male;
m_Title = bachelor;
}
//добавяме параметричен к-р
CPerson(string n,Sex s,Titles t) {
m_strName = n;
m_Sex = s;
m_Title = t;
}
~CPerson() {}
void SetName(string strName) {
m_strName = strName;
}
void SetSex(Sex sex) {
m_Sex = sex;
}
void SetTitle(Titles title) {
m_Title = title;
}
string GetName() const {
return m_strName;
}
};
int main(){
vector <CPerson> perr = { CPerson p1,
CPerson p2("I.Ivanov", male, professor),
CPerson p3("A.Stoyanova", female, assistant),
CPerson p4("A.Dimitrova", female, assistant)}
return 0;
}
There are a lot of problems in your code. Here is a version of the code that compiles successfully:
// Example program
#include <iostream>
#include <string>
#include <vector>
enum class Sex {
male, female
};
enum class Titles {
bachelor,
assistant,
professor
};
class CPerson {
protected:
std::string m_strName;
Sex m_Sex;
Titles m_Title;
public:
CPerson() {
m_strName = "Peter Petrov";
m_Sex = Sex::male;
m_Title = Titles::bachelor;
}
//добавяме параметричен к-р
CPerson(std::string n,Sex s,Titles t) {
m_strName = n;
m_Sex = s;
m_Title = t;
}
void SetName(std::string strName) {
m_strName = strName;
}
void SetSex(Sex sex) {
m_Sex = sex;
}
void SetTitle(Titles title) {
m_Title = title;
}
std::string GetName() const {
return m_strName;
}
};
int main(){
std::vector <CPerson> perr({
CPerson(),
CPerson("I.Ivanov", Sex::male, Titles::professor),
CPerson("A.Stoyanova", Sex::female, Titles::assistant),
CPerson("A.Dimitrova", Sex::female, Titles::assistant)
});
return 0;
}
Besides the missing types for Sex and Titles, the main problem was in the syntax of your vector initializer. I assume that you were trying to use an initializer list, but your syntax was all wrong. It looks like you were just copying variable declaration / initialization statements into it, but you need to create new instances of your CPerson class. These instances will then be copied into the vector.
CPerson p2("I.Ivanov", male, professor)
Declares and initializes a variable named p2 of class CPerson on the stack, but this syntax is not valid inside an initializer list, since you're not permitted to declare variables there. Instead use
CPerson("I.Ivanov", Sex::male, Titles::professor)
This creates an instance of CPerson, and this instance is then copied into the vector.
My problem is just i dont know what to paste where i writed HELP_HERE(see the code above class Dog in function bool operator==) in order to get he comparation between the type Animal of two Dogs. Each dog is an Animal so i need to be able to return the variable that represents "the animal inside the dog". In java i could just use super() and it works what do i need in c++?
`
#include "Animal.h"
class Dog : public Animal
{
private:
char _name;
int _age;
int _hps;
float _peso; // peso is Weight
public:
Dog(char name,int age, float peso, int hps) : Animal(name,age),_peso(peso),_hps(hps) {}
void roar(std::ostream &os) const {
os << "O cao " << _name << " esta a ladrar\n.";
}
int Vidas() const {
return _hps;
}
float Peso() const {
return _peso;
}
int returnAnimal() {
return animal.Age();
}
bool operator==(const Dog &dog) {
return HELP_HERE.operator==(dog.HELP_HERE) &&
dog.Vidas() == _hps && dog.Peso() == _peso;
}
friend std::ostream &operator<<(std::ostream &os, const Dog &dog) {
dog.roar(os);
return os;
}
};`
Class Animal:
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
class Animal {
int _age;
char _name;
public:
Animal(int age) : _age(age),_name('-') {}
Animal(int age, char name) : _age(age), _name(name) {}
int Age() const { return _age; }
char Name() const { return _name; }
friend std::ostream &operator<<(std::ostream &os, const Animal &animal) {
animal.sleep(os);
return os;
}
void sleep(std::ostream &os) const {
os << "the animal " << Name() << " is sleeping.\n";
}
void Age(int age) { _age = age; }
bool operator==(const Animal &animal) {
return _age == animal.Age() && _name == animal.Name();
}
};
#endif // ANIMAL_H
Change HELP_HERE.operator==(dog.HELP_HERE) to:
Animal::operator==(dog)
In general you can get an Animal reference with: Animal &a = *this; . C++ doesn't have a keyword which indicates "the parent class", however you can always make your child class contain typedef Animal super; and then you can use super::operator==, or super &a = *this; etc.