Polymorphism constructor function - c++

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..

Related

Pass data from object in class A to class B

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;
};

How to serialize the data in Binary I/O?

Here is my C++ class and code snip. Data does not gets properly loaded in objects which gives me memory access error. What can i do?
Base Class
using namespace std;
class Person;
class Person
{protected:
int ID;
string name;
string address;
long int phone;
string dob;
//char pass[25];
std::string pass;
public:
Person();
Person(int ID,string name, string address, long int phone, string dob, string pass) :
ID(ID),name(name), phone(phone),address(address),dob(dob),pass(pass)
{};
//COPY CONSTRUCTOR MUST BE CREATED INORDER TO MAKE VECTOR WORK
Person(const Person&);
virtual void showDetails() const = 0;
//MAKING THIS CLASS AN ABSTRACT CLASS
//BUNCH OF GETTERS
int getID() const;
string getName() const;
string getAddress() const;
long int getPhone() const;
string getDob() const;
string getPass() const;
void setPass(string a);
};
Here is the derived class from it :
#include<iostream>
#include"Person.h"
#ifndef CUSTOMER_H
#define CUSTOMER_H
class Customer :public Person {
private:
float balance;
protected:
public:
Customer() :Person(), balance(0) {}
Customer(int ID,std::string name,std::string address,long int phone, string dob,std::string
pass,float balance):
Person(ID,name,address,phone,dob,pass),balance(balance){};
//Customer(int ID, const char* name, const char* address, long int phone, string dob, const
char* pass, float balance) :
// Person(ID, name, address, phone, dob, pass), balance(balance) {};
//COPY CONSTRUCTOR MUST BE PROVIDED, ELSE VECTOR WONT WORK
Customer(const Customer& other) :Person(other) {
this->balance = other.balance;
}
float getBalance() const;
void showDetails() const;
// void setValues();
void deposit(float);
void withdraw(float);
};
#endif
Im having issues that data is not copied from file into vector properly : Here is the implementation of file handling:
void Controller::displayCustomers()
{
vector<Customer> custVector;
Customer cust;
fstream fin("customer.txt", ios::binary | ios::in);
while (fin.read(reinterpret_cast<char*>(&cust), sizeof(cust)));
{
custVector.push_back(cust);
}
fin.close();
cout << "ID\tNAME\tADDRESS\tPHONE\t\tDOB\tPASSWORD\tBALANCE" << endl;
for (vector<Customer>::iterator itr = custVector.begin();
itr != custVector.end(); ++itr)
{
cout << itr->getID() << "\t" << itr->getName() << "\t" << itr->getAddress() << "\t"
<< itr->getPhone() << "\t" << itr->getDob() << "\t" << itr->getPass() <<
"\t" << itr->getBalance() << endl;
}
cout << endl;
}
The constuctors runs more than data members and gives a memory access error when vector members are accessed. What should be the best practice.?
You cannot use binary I/O to directly read or write objects containing std::string. So this code is wrong.
fin.read(reinterpret_cast<char*>(&cust), sizeof(cust))
Best practise depends entirely on what you are trying to achieve. Must you use binary I/O? Can you change the class? Are you trying to get indexed access on your file?
For better advice you need to state what you are actually trying to achieve. At the moment all anyone can say it that this code is wrong.
It's possible that you just chose binary I/O because you throught it would be easiest. If that's the case then you should probably abandon it and switch to text I/O. But I'm not going to give advice based on speculation. You need to say what you are trying to do here.
ADDENDUM
I noticed this is your code
//char pass[25];
std::string pass;
If you followed through with that, and replaced all the strings in your classes then you might find that your reading and writing code started working. This is what's known as a plain old data (POD) class. POD classes can be read and written in the way you are trying to.
Note you would also have to remove any virtual functions as well, so maybe a POD class isn't such a good idea.

C++ implementing derived class from base class by map and using methods from

i am facing issue which i want to create abstract class and 4 subclasses. Abstract class = Entry , and other subclasses are given in the code down.
class entry {
friend ostream &operator<<(ostream &os, const entry &obj);
private:
static constexpr char *def_info = "Undefind";
protected:
string desc;
int ID;
static int counter;
public:
entry() : entry(def_info) {}
entry(string input_s);
void setDesc(string);
string getDesc() const;
int getID() const;
virtual string getContents() const = 0;
virtual void displaying(ostream &os) const = 0;
virtual ~entry() = default;
};
int entry::counter = 0;
entry::entry(string input_s) :
desc{input_s} {
++counter;
ID = counter;
}
ostream &operator<<(ostream &os, const entry &obj) {
os << obj.getContents()<<endl;
obj.displaying(os);
return os;
}
void entry::setDesc(string input) {
desc = input;
}
string entry::getDesc() const {
return desc;
}
int entry::getID() const {
return ID;
}
//PhoneEntry extending the Entry with a phone number
class phone_entry :virtual public entry {
private:
static constexpr char *text = "Undefind";
static constexpr int def_no = 48000000000;
protected:
int phone_number;
public:
phone_entry(string input_s = text, int input = def_no) :
entry(input_s), phone_number(input) {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nPhone number : " << phone_number;
return output.str();
}
virtual ~phone_entry() = default;
};
//EmailEntry extending the Entry with an e-mail addres
class email_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
protected:
string email;
public:
email_entry(string des = def_info, string email_entry = def_info) :
entry(des), email{email_entry} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nEmail : " << email;
return output.str();
}
virtual ~email_entry() = default;
};
//AddressEntry extending the Entry with an address containing a city, a street and a house number
class address_entry : virtual public entry {
private:
static constexpr char *def_info = "Undefind";
static constexpr int def_no = 0;
protected:
string city;
string street;
int house_number;
public:
address_entry(string des = def_info, string c = def_info, string s = def_info, int hn = def_no) :
entry{des}, city{c}, street{s}, house_number{hn} {}
virtual string getContents() const override {
ostringstream output;
output << "ID: " << ID << "\nD: " << desc << "\nCity: " << city << "\nStreet: " << street << "\nHouse number: "
<< house_number;
return output.str();
}
virtual ~address_entry() = default;
};
class contact_book : virtual public entry {
static constexpr char *def_info = "Undefind";
private:
map<string,entry *> contacts;
string nick_name;
public:
class error_mesg : public logic_error {
public:
error_mesg(const string message = "NULL") :
logic_error(message) {}
};
contact_book(string e = "undefind") :
entry{def_info},nick_name{e} {}
void add(string a , entry &content){
contacts.insert(make_pair(a,&content));
}
virtual void displaying(ostream &os) const override {
os << "TESTING";
}
};
I want to use contact_book class and use map container to insert the key and values to any of the subclasses like ("cool", new phone_entry("NAME",000000) by using add method that it has two parameters one for the key and other it must have connection to the other classes so i thought that using entry obj will do the job ofc i used pointer in the member because i want to use Polymorphism. also i dont have any idea how i can use the getContencts and it knows from which subclass calling. For example , he asked that the main will look like this :
ContactBook contacts(“My contacts”);
contacts.add(“Johny”, new PhoneEntry(“John Smith”, 100200300));
contacts.add(“Lisa”, new EmailEntry(“Lisa Wood”, “lisa#gmail.com”));
contacts.add(“Andy”, new AddressEntry(“Andrew Fox”, “Warsaw”, “Green St.”, 7));
cout << contacts;
//result (ordered):
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
//John Smith: phone 100200300 (pos. 1)
//Lisa Wood: e-mail lisa#gmail.com (pos. 2)
try {
cout << contacts[“Andy”].getContents() << endl;
//result:
//Andrew Fox: Warsaw, Green St. 7 (pos. 3)
can you please help me out how to implement them and get what he wants and how & will work on that adding method and new as well in main func.
You are not pretty clear about what your actual problem is – so I'll assume you have trouble getting the desired output for the entire contact book...
First, some other issues, though:
It is meaningless to let contact_book inherit from entry - the book contains entries, it is not one. It seems as if you only inherited to be able to override displaying function to be able to use the already defined operator<< for entry class. But that's a bad reason for inheriting. Instead, you should provide a separate overload of operator<< for your contact book:
std::ostream& operator(std::ostream& s, contact_book const& cb); // coming to later
Then get used to reuse code where appropriate; I assume getContents should output the same string that would be written to std::cout via operator<<. OK, then let's profit from:
std::string entry::getContents()
{
std::ostringstream s;
s << *this;
return s.str();
}
You don't need to have it virtual any more (and shouldn't).
I personally would go with a default for displaying function (that's not a very good name, though, you should prefer imperative forms 'display', perhaps even better: 'printToStream' or just 'printTo'):
void entry::printTo(std::ostream& s)
{
// output members to s
}
Then your inheriting classes could re-use it:
void phone_entry::printTo(std::ostream& s)
{
entry::printTo(s); // use parent's version first to print common data
// now append phone number to s...
}
Users should rather use operator<< instead of printTo function, though. Might be a good idea to have it protected (or even private).
Finally getting back to outputting the contact book:
std::ostream& operator(std::ostream& s, contact_book const& cb)
{
// you want to output every entry? then do so:
for(auto& e : cb.contacts)
{
s << *e.second << std::endl;
// ^^^^^^^ map entries are of type std::pair<key_type const, mapped_type>
// ^ you stored pointers, operator<< accepts reference
}
}
Again, you'd be re-using code already written.
One last note: You are mixing classic initialisation (parentheses) and uniform initialisation (braces), one time even in one single line (email_contact):
entry(des), email{email_entry}
I personally think UI in general has some valid reasoning, the way it was implemented in C++ is broken, though. There are quite a few other issues with, my 'favourite' one is:
std::vector<int> v0{7}; // gives you a vector with 7 elements, all 0!!!
// with classic initialization:
std::vector<int> v1(7); // now clear, you WANT such a vector!
std::vector<int> v2({7}); // now clear, you want initializer list
You now can follow my reasoning or not (others opt for UI nonetheless to profit from the advantages of), but whatever you decide – please do it consistently over the entire file/project!

How do I change different elements of the same with same member function?

I am new to C++ and am not able to find the answer. This is the code I want to write:
#include <iostream>
using namespace std;
class Employee{
private:
string name;
string gender;
public:
void display();
void update(string);
Employee(string a, string b){
name = a;
gender = b;
};
~Employee(){};
};
void Employee::display(void){
cout << "Name: " << name << endl;
cout << "Gender: " << gender << endl;
}
void Employee::update(string a){
/*
a function that updates either the
name element or gender element
based on which element it is used by.
*/
}
int main(){
Employee employee1 ("Joe","Male");
Employee employee2 ("Jon","Male");
employee1.display();
employee2.display();
employee1.name.update("Mary"); // This is what I want to do: Same function
employee2.gender.update("Female"); // for different elements of same type
employee1.display();
employee2.display();
return 0;
}
How do I go about doing this?
I thought about function overloading but both elements are of the same type. I do not want to pass any extra values and make the code look crappy. Any ideas? Thank you.
Use setters and getters like this:
void Employee::setName(const string &a) {
this->_name = a; // validate or whatever you need to do
}
const string &Employee::name() const {
return this->_name;
}
void Employee::setGender(const string &a) {
// ....
}
Usage as one would expect
employee1.setName("Mary");
employee2.setGender("Female");
The basic_string class already implements a 'setter':
employee1.name.assign("Mary");
employee2.gender.assign("Female");
If you want to access name and gender like you have written in your question, you need to make both public, as #sop correctly pointed out.

cannot convert parameter 1 from 'PrintVisitor *const ' to 'Visirot &'

I used two design pattern Composite and Visitor. I have no problem with Composite.But when he began writing derived classes for input and output got some errors, solution which I did never found. Although in reality, and if everything is InputVisitor done so remained only PrintVisitor and main().
Here is my code:
UPD: I rewrite some parts of code. Now I have no erros, but it only open terminal and nothind doing...
P.S. Maybe I did not properly implement of patterns. Someone has a better idea?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
class BaseComponent {
public:
virtual void add(BaseComponent *)=0;
virtual void accept(class Visitor &)=0;
};
class Card :public BaseComponent {
public:
Card (string bookName, vector<string> authors, int year): _bookName(bookName), _authors(authors), _year(year) {}
string getBookName() const {
return _bookName;
}
vector<string> getAuthors() const {
return _authors;
}
int getYear() const {
return _year;
}
void setBookName(string bookName) {
_bookName = bookName;
}
void setAuthors(vector<string> authors) {
copy(authors.begin(), authors.end(), _authors.begin());
}
void setYear(int year) {
_year = year;
}
void add(BaseComponent *){}
void accept(class Visitor &);
private:
string _bookName;
vector<string> _authors;
int _year;
};
class Folder :public BaseComponent {
public:
Folder(): _folderName(""), _parentFolder("") {}
Folder(string parentFolder): _folderName(""), _parentFolder(parentFolder) {}
string getFolderName() const {
return _folderName;
}
string getParentName() const {
return _parentFolder;
}
vector<BaseComponent*> getSubFolders() const {
return _subFolders;
}
void setFolderName(string folderName) {
_folderName = folderName;
}
void setParentFolder(string parentFolder) {
_parentFolder = parentFolder;
}
void add(BaseComponent *component) {
_subFolders.push_back(component);
}
void accept(class Visitor &);
private:
string _folderName;
string _parentFolder;
vector<BaseComponent*> _subFolders;
};
class Visitor {
public:
virtual void visitCard(Card *)=0;
virtual void visitFolder(Folder *)=0;
};
void Card::accept(class Visitor &visitor) {
visitor.visitCard(this);
}
void Folder::accept(class Visitor &visitor) {
visitor.visitFolder(this);
}
class InputVisitor :public Visitor {
public:
InputVisitor(string file): _file(file){}
void setFile(string file) {
_file = file;
}
void visitCard(Card *){}
void visitFolder(Folder *folder){
ifstream input(_file);
string folderName;
getline(input, folderName);
folder->setFolderName(folderName);
string fileName;
while (!input.eof()) {
input >> fileName;
if (fileName == "----") {
break;
} else {
Folder *subFolder = new Folder(folderName);
InputVisitor *inputVisitor = new InputVisitor(fileName);
subFolder->accept(*inputVisitor);
folder->add(subFolder);
}
}
while (!input.eof()) {
string name, tempAuthor;
vector<string> authors;
int n, year;
input >> name;
input >> n;
for (int i = 0; i<n; ++i) {
input >> tempAuthor;
authors.push_back(tempAuthor);
}
input >> year;
Card *subBook = new Card(name, authors, year);
folder->add(subBook);
}
input.close();
}
private:
string _file;
};
class PrintVisitor :public Visitor {
public:
PrintVisitor(string outputFile): _outputFile(outputFile) {}
void setOutputFile(string outputFile) {
_outputFile = outputFile;
}
void visitFolder(Folder *folder) {
ofstream output(_outputFile);
output << folder->getFolderName() << endl << "\t";
vector<BaseComponent*> subFolders = folder->getSubFolders();
vector<BaseComponent*>::iterator it;
for (it=subFolders.begin(); it!=subFolders.end(); ++it) {
(*it)->accept(*this);
}
output.close();
}
void visitCard(Card *card) {
ofstream output(_outputFile);
output << "Book: " << card->getBookName() << endl
<< "Author(s): ";
vector<string> authors = card->getAuthors();
for (vector<string>::iterator it=authors.begin(); it!=authors.end(); ++it) {
output << *it << " ";
}
output << endl << "Year: " << card->getYear();
output.close();
}
private:
string _outputFile;
};
int main() {
Folder root;
root.accept(*(new InputVisitor("root.txt")));
root.accept(*(new PrintVisitor("output.txt")));
return 0;
}
In this code:
InputVisitor *input;
input->setFile("root.txt");
root->accept(input); //Here
InputVisitor is a *input. Your accept function takes a reference to a visitor. Change it to:
root->accept(*input); //Here
and all will be fine, aside from the typo I mentioned in the comment.
If you remove all the class in front of names for classes, the compiler will tell you when there is a misspelled class name. Otherwise, it will just treat it as "there'll be a class named Visirot at some point in the future, and I don't really care what's in it right now.
Here is the declaration of BaseComponent::accept:
virtual void accept(class Visirot &)=0;
Here is the call:
root->accept(input); //Here
Here is the declaration of input:
InputVisitor *input;
So, first, the declaration of BaseComponent::accept apparently has a typo; Visirot should probably be Visitor.
Second, accept takes a Visitor&, but it's being called with an InputVisitor*. InputVisitor is derived from Visitor, soInputVisitor*is convertible toVisitor*andInputVisitor&is convertible toVisitor&, but there is no conversion from a pointer-to-type into a reference-to-type. So either changeBaseComponent::accept` to take a pointer or change the call to pass a reference.
First problem.
Assuming the typo Visirot is fixed, then at line 152 you have
subFolders[i]->accept(this); //Here some probrem
which passes a pointer to T where a T is expected.
Just dereference that pointer:
subFolders[i]->accept(*this);
Second problem.
Applying the same fixes in the main program would be wrong:
int main() {
BaseComponent *root;
InputVisitor *input;
input->setFile("root.txt");
root->accept(*input); //Here
PrintVisitor *output;
output->setOutputFile("output.txt");
root->accept(output); //And here
return 0;
}
This dereferences uninitialized pointers, which yields Undefined Behavior.
Don't do that.
Rewrite it as e.g.
int main() {
Folder root;
InputVisitor input;
input.setFile("root.txt");
root.accept(input); //Here
PrintVisitor output;
output.setOutputFile("output.txt");
root.accept(output); //And here
}
(and possibly replace Folder with whatever concrete class you want there.)
Third problem.
At line 144 you're assigning to a stream:
_outputFile = ofstream(outputFile);
where _outputFile is a member of type ofstream, and outputFile is a string.
This uses a C++11 feature (rvalue assignment of streams) that g++ didn't implement as of version 4.7.1.
Presumably the idea is to close _outputFile and reopen it: just do that, and the code will be much more portable:
// Add failure checking:
_outputFile.close();
_outputFile.open( outputFile );
Also, more descriptive naming would be good…
General problem set in the given code.
Compiling the above yields a number of warnings about signed/unsigned comparisons and unused local variables. Fix all that. Build at highest practical warning level, -Wall with g++ and /W4 with Visual C++, and make it compile cleanly.
Logic errors & testing.
Even when it compiles cleanly, there can and usually will remain logic errors. To root out those, devise a set of exactly reproducible tests, complete with any necessary test data.