Pass data from object in class A to class B - c++

New to classes and objects in c++ and trying to learn a few basics
I have the class TStudent in which the Name, Surname and Age of student are stored, also I have the constructor which is accessed in main and inserts in the data.
What I want to do is: having the class TRegistru, I have to add my objects data in it, in a way that I can store it there, then I could save the data in data.bin and free the memory from the data, then I want to put the data back in the class and print it out.
The question is: In what way & what is the best way to add my objects in the second class, so that I could eventually work with them in the way I've described in the comments, so that I won't have to change nothing in main
Here's my code so far:
#include <iostream>
using namespace std;
class TStudent
{
public:
string Name, Surname;
int Age;
TStudent(string name, string surname, int age)
{
Name = name;
Surname = surname;
Age = age;
cout <<"\n";
}
};
class TRegistru : public TStudent
{
public:
Tregistru()
};
int main()
{
TStudent student1("Simion", "Neculae", 21);
TStudent student2("Elena", "Oprea", 21);
TRegistru registru(student1);//initialising the object
registru.add(student2);//adding another one to `registru`
registru.saving("data.bin")//saving the data in a file
registru.deletion();//freeing the TRegistru memory
registru.insertion("data.bin");//inserting the data back it
registru.introduction();//printing it
return 0;
}

Hence the question is about passing data from A to B, I will not comment on the file handling portion.
This can be done in multiple ways, but here is one of the simplest and most generic. By calling TRegistru::toString() you serialize every TStudent added to TRegistru into a single string which then can be easily written to a file.
Demo
class TStudent
{
public:
std::string Name, Surname;
int Age;
std::string toString() const
{
return Name + ";" + Surname + ";" + to_string(Age);
}
};
class TRegistru
{
public:
void add(const TStudent& student)
{
students.push_back(student);
}
void deletion()
{
students.clear();
}
std::string toString() const
{
std::string ret{};
for(const auto& student : students)
{
ret += student.toString() + "\n";
}
return ret;
}
std::vector<TStudent> students;
};

Related

Can I create multiple constructors with the same arguments

Im new to C++ and I am curious to know if you can create multiple constructors with the same arguments. Say for example I have this class in which I have patients and I have their name and their age. I know I can create a constructor like this:
class hospital {
hospital(){
setname("John");
setage(24);
}
private:
string name;
int age;
};
but could I create another constructor just like I did above. Something like:
hospital patientBilly(){
setname("Billy");
setage(32);
}
The problem is that you redefine the constructor. Allowed is only one definition.
Simplified example:
void myFunc (){};
void myFunc (){};
int
main ()
{
myFunc ();
}
I whould make the Hospital class like this:
#include <string>
struct Hospital // struct here to signal we have no invariant. you could also use a class and make the member public
{
std::string name{}; // no setter and getter if you do not have invariant.
int age{};
};
int
main ()
{
auto hospital = Hospital{ .name = "John", .age = 42 }; //c++20 Designated Initializers so we can construct Hospital with a name and age without defining a constructor
}
I believe you are currently only a bit confused. So lets become the things sorted...
A class describes how objects should behave. The constructor is part of that description and equal to all the instances it will later on create. Your first step for understanding should be: There is a single class and multiple instances/objects of it.
So you write a single class and give for each of the instances/objects different parameters to get different objects.
Example:
class hospital {
public:
hospital(const std::string& name_, int age_ ):
name { name_ }, age{ age_ }{
}
void Print() const
{
std::cout << "Hospital" << name << ":" << age << std::endl;
}
private:
std::string name;
int age;
};
int main()
{
hospital hospital1{ "John", 24 };
hospital hospital2{ "Bill", 77 };
hospital1.Print();
hospital2.Print();
}
You can also create a different class for every of your later created objects, but I believe that is never what you want to do, especially not at the beginning of your C++ career!
If you want to create some kind of list of instances, you can store the objects in containers and act on the containers as you like.
int main()
{
std::vector< hospital > objs;
objs.emplace_back( "John", 24 );
objs.emplace_back( "Bill", 77 );
for ( const auto& hos: objs )
{
hos.Print();
}
}
In your problem you have two concepts, which you are trying to mix.
hospitals and patients. So it makes sense to model them as two distinct classes.
This way you can model a patient as something that has an age and a name.
And a hospital as something that "contains" patients.
Give the patient a contructor where you can pass age and name.
And give the hospital a method or methods to add patients.
In the example I show to variants of how you could add patients to a hospital.
I also have use unsigned variable types for numbers that can never be smaller then 0. And I use the const keyword a lot for places in the code where values must only be used, and should not be changed.
#include <iostream>
#include <string>
#include <utility>
#include <vector>
//---------------------------------------------------------------------------------------------------------------------
class patient_t
{
public:
// You need a constructor like this
patient_t(const unsigned int age, const std::string& name ) :
m_age{ age },
m_name{ name }
{
}
// getter function for observing private data
const unsigned int& age() const noexcept
{
return m_age;
}
// getter function for observing private data
const std::string& name() const noexcept
{
return m_name;
}
private:
unsigned int m_age;
std::string m_name;
};
// a useful output function to have (will make code later shorter)
std::ostream& operator<<(std::ostream& os, const patient_t& patient)
{
os << "Patient : " << patient.name() << ", age : " << patient.age() << std::endl;
return os;
}
//---------------------------------------------------------------------------------------------------------------------
class hospital_t
{
public:
void add_patient(const unsigned int age, const std::string& name)
{
m_patients.emplace_back(age,name); // will call patient constructor with two parameters age and name and puts it into vector
}
void add_patient(const patient_t& patient)
{
m_patients.push_back(patient); // store a copy of patient in the vector
}
const auto& patients() const
{
return m_patients;
}
private:
std::vector<patient_t> m_patients;
};
//---------------------------------------------------------------------------------------------------------------------
int main()
{
hospital_t hospital;
patient_t billy{ 42, "Billy" };
hospital.add_patient(billy);
hospital.add_patient(31, "Jane");
for (const auto& patient : hospital.patients())
{
std::cout << patient;
}
}
If I have understood correctly then what you need is to define two constructors
hospital( const std::string &name, int age )
{
setname( name );
setage( age );
}
hospital() : hospital( "John", 24 )
{
}
Then you will can write declaring an object of the class
hospital patientBilly( "Billy", 32 );

How to design c++ class in a way to have a base attributes and add attributes for few cases

I have a basic class ContactDetails which has a private variables as string name and string address. This ContactDetails data structure is used in my program for all entities. For some entities, I need other info on top of name and address, such as phone number, pin code etc. How to design the class.
class ContactDetails {
private:
std::string name;
std::string address;
public:
ContactDetails() {
this->name = "";
this->address = "";
}
std::string getName() { return name; }
std::string getAddress() { return address; }
void setName(std::string n) { name = n; }
void setAddress(std::string n) { address = n; }
}
class ContactDetailsHelper {
public:
ContactDetails getX() {
ContactDetails obj;
obj.setName("X");
obj.setAddress("New York");
return obj;
}
ContactDetails getY() {
//Y has phone number, pin code, county code etc details available.
ContactDetails obj;
obj.setName("Y");
obj.setAddress("Chicago");
//need to set more details in the object
return obj;
}
If we take phone number, pin code, county code as a private member in ContactDetails class, most of the time it would be empty. So how to design the class in such a way like extra details we could put it in another class and if needed for any entity we could use them.

C++: how to make getters and setters work with an empty constructor

First of all, I have only learned a little bit of Java before. It's been only a few days since I started getting friendly with C++ so please don't take this question so basic and please don't degrade my question.
I made a simple source code as follows:
#include <iostream>
using namespace std;
class Car {
public:
void setBrand(string name);
void setPrice(double price);
string getBrand();
double getPrice();
Car();
Car(string name);
Car(string name, double price);
private:
string name;
double price;
};
Car::Car() {
}
Car::Car(string name) {
name = name;
}
Car::Car(string name, double price) {
name = name;
price = price;
}
void Car::setBrand(string name) {
name = name;
}
void Car::setPrice(double price) {
price = price;
}
string Car::getBrand(void) {
return name;
}
double Car::getPrice(void) {
return price;
}
int main() {
Car car;
car.setBrand("Nissan");
car.setPrice(30000);
cout << "Brand: " << car.getBrand() << endl;
cout << "Price: " << car.getPrice() << endl;
return 0;
}
I wanted to make a code that creates an empty instance of a class called Car, set the field values later and print them out on the console.
The code did not make any errors during the compile, but the result I see was totally different from what I expected. It didn't show the brand name and the price was looking even weird, as follows.
Brand:
Price: 6.95322e-310
Somebody help me out! Thank you very much indeed in advance.
The problem you have is that you override the member names with function parameters. You can use this-> to make it explicit or name the member differently.
For example:
void Car::setBrand(string name) {
this->name = name;
}
Or:
void Car::setBrand(string new_name) {
name = new_name;
}
In your constructor and setters, you make no differentiation between the local parameter and the class member.
name = name;
Both the function parameter and the class member are called name. Currently the compiler is assigning the parameter value to itself, and not affecting the class member at all. This is because the function parameter is in a more immediate scope.
Possible solutions:
Specify this when referring to the class member: this->name = name;.
Rename the function parameter: name = _name;.
For the constructor, use initializer lists:
Car::Car(string name, double price)
: name(name)
, price(price)
{ }
There's too much wrong with your code to describe it in prose, so let me present a fixed implementation, and I leave it to you to spot the difference:
#include <string>
class Car
{
private:
static constexpr double kNoPrice = -1.0;
static constexpr const char* kNoName = "[no name]";
public:
// Main constructor: constructs a car with the given name and price.
Car(std::string name, double price)
: name_(std::move(name))
, price_(price)
{}
// Convenience constructors:
Car() : Car(kNoName, kNoPrice) {}
Car(std::string name) : Car(std::move(name), kNoPrice) {}
// Accessors:
const std::string& getBrand() const { return name_; }
void setBrand(std::string name) { name_ = std::move(name); }
double getPrice() const { return price_; }
void setPrice(double price) { price_ = price; }
private:
std::string name;
double price;
};
Some random notes, in no particular order:
Use correct names. It's std::string, not string, mate or buddy. Never ever be abusing namespace std.
Include headers for external names that you need.
Reading uninitialized values is undefined behaviour, so none of your constructors should leave fields uninitialized (like price_).
Give private members consistent names (e.g. foo_ in my example).
Accessors should be const-correct.
Convenience constructors should delegate to one single work-horse constructor.
Pick sensible defaults for initial values of defaulted fields and make them discoverable.
Use move semantics when taking ownership of dynamically managed data (strings, dynamic containers, etc.).

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

Polymorphism constructor function

My code compiles fine but I am having issues with a particular section not displaying the correct output.
Here is my base class
class Item
{
protected:
//int count;
string model_name;
int item_number;
public:
Item();
Item(string name, int number);
string getName(){return model_name;}
int getNumber(){return item_number;}
and here is my derived class:
class Bed : public Item
{
private:
string frame;
string frameColour;
string mattress;
public:
Bed();
Bed(int number, string name, string frm, string fclr, string mtres);
Function definitions:
Bed::Bed(int number, string name, string frm, string fclr, string mtres)
{
model_name=name;
item_number=number;
frame=frm;
frameColour=fclr;
mattress=mtres;
cout<<model_name<<item_number<<frame<<frameColour<<mattress<<endl;
}
Main section that is causing the problem:
Item* item= new Bed(number, name, material, colour, mattress);
cout<<"working, new bed"<<endl;
v.push_back(item);
cout<<"working pushback"<<endl;
cout<<" this is whats been stored:"<<endl;
cout<<v[count]->getName<<endl;
cout<<v[count]->getNumber<<endl;
count++;
when the programme executes, the cout within the constructor shows the correct output, but when I call getname and getnumber from the main function the programme prints '1' for both , no matter what's stored in there.
I thought that derived classes could use base class methods, what have I missed?
Any help would be great
thanks
Hx
Well, you example is not related to polymorphism. The reason here is that you are not using any virtual functions. Here is the code that you can use.
class Item
{
protected:
std::string model_name;
int item_number;
public:
Item();
Item(std::string& name, int number) : model_name(name), item_number(number) {};
std::string getName(){return model_name;}
int getNumber(){return item_number;}
};
class Bed : public Item
{
private:
std::string frame;
std::string frameColour;
std::string mattress;
public:
Bed();
Bed(int number, std::string& name, std::string& frm, std::string& fclr, std::string& mtres) : Item(name, number),
frame(frm),
frameColour(fclr),
mattress(mtres) {};
};
int main()
{
int count = 0;
std::vector<Item*> v;
Item* item = new Bed(2, std::string("MyBed"), std::string("wood"), std::string("red"), std::string("soft"));
std::cout << "working, new bed" << std::endl;
v.push_back(item);
std::cout << "working pushback" << std::endl;
std::cout << " this is whats been stored:" << std::endl;
std::cout << v[count]->getName() << std::endl;
std::cout << v[count]->getNumber() << std::endl;
++count;
getchar();
}
This looks incorrect (and I am unsure how this even compiled):
cout<<v[count]->getName<<endl;
cout<<v[count]->getNumber<<endl;
as getName and getNumber are methods. Change to:
cout<<v[count]->getName()<<endl;
cout<<v[count]->getNumber()<<endl;
Additionally, the initialisation of count is not posted: ensure it is zero.
count appears to be the size of your vector. After you push back the last element, you're not incrementing count, so you're printing an older element.
Why don't you try:
cout<<v[v.size()-1]->getName<<endl;
cout<<v[v.size()-1]->getNumber<<endl;
Also, you should start using initialization lists in your constructors:
Bed::Bed(int number, string name, string frm, string fclr, string mtres) :
Item(name,number),
frame(frm),
frameColour(fclr),
mattress(mtres)
{
}
You have not called the base class's constructor from the derived class... Where as it should be the first line... update the code, I am sure it will start working..
EDIT
If it doesn't than you should probably also check the way you are handling count variable... as pointed out by others..