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.
Related
I'm trying to set a class member variable from STL vector in C++.
But it doesn't work the way I want it to. The variable doesn't change, The variable is the same like before.
Am I programming in the wrong way?
Here's the code.
#include <iostream>
#include <vector>
using namespace std;
class Test {
private:
std::string name;
public:
Test();
Test(std::string p_name);
std::string getName();
void setName(std::string p_name);
};
Test::Test() { name = ""; }
Test::Test(std::string p_name) : name(p_name) {}
std::string Test::getName() { return name; }
void Test::setName(std::string p_name) { name = p_name; }
int main() {
// Initializing vector with values
vector<Test> tests;
for (size_t i = 0; i < 10; i++) {
tests.push_back(Test());
}
for (Test test : tests) {
cout << test.getName() << endl;
test.setName("a");
}
for (Test test : tests) {
cout << test.getName() << endl;
}
return 0;
}
This is the result:
> ./main
>
Why It doesn't work, and how to fix it?
You're copying the elements from the vector each time you iterate through it in your loop.
Try changing your code to something like this:
for (auto& test : myTests) {
test.setName("My new name");
}
In this case, the ampersand (&) marks the variables as a reference, which means you can manipulate it directly.
The way your code is written, you're using the copy-constructor to construce a new object.
You can circumvent this, by adding something like:
public:
explicit Test(const Test&) = delete;
to your class.
This will prevent the copying of the object, which will reduce the likelihood of these types of errors.
First of all, I am new here to c++ and I'm trying to learn it. Also new to stackoverflow.
Find it quite hard to be honest.
If you have additional comments in terms of my code and how i can improve it, please let me know as I am still in the learning process.
ok I was I just creating a online booking system using object oriented programming.
Ok so the main issue is that I dont understand why system.setDisplay(1234); isn't printing anything. I have tried everything and just isn't adding up.
OnlineBookingSystem is the class is being used to call setDisplay(id) which then invoked the display class.
If you can help it would mean the world to me and the error i`m getting is:
runtime error: member call on null pointer of type 'User' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:179:54
#include <vector>
#include <string>
#include <iostream>
#include <memory>
#include <queue>
using namespace std;
enum class BookGenre
{
Horror,Adventure,Romance,Comic
};
class Book
{
private:
BookGenre genre;
string title;
size_t id;
public:
Book(string title,size_t id,BookGenre genre):title(title),id(id),genre(genre){}
string getTitle(){return title;}
size_t getId(){return id;}
BookGenre getGenre(){return genre; }
};
class Library
{
private:
vector<shared_ptr<Book>> listOfBooks;
public:
Library(){};
void addBook(string title,size_t id,BookGenre genre)
{
listOfBooks.push_back(make_shared<Book>(title,id,genre));
}
shared_ptr<Book> getBook(size_t id)
{
for(auto&x:listOfBooks)
{
if(x->getId()==id)
{
return x;
}
}
return nullptr;
}
void removeBook(size_t id)
{
for(auto it=listOfBooks.begin();it!=listOfBooks.end();it++)
{
if((*it)->getId()==id)
{
listOfBooks.erase(it);
}
}
}
};
class User
{
protected:
size_t id;
string username;
public:
User(size_t id,string username):id(id),username(username)
{
}
virtual ~User(){}
size_t getId(){return id;}
string getUsername(){return username;}
};
class Employee:public User{
private:
double salary;
public:
Employee(size_t id,string username,double salary):User(id,username),salary(salary)
{
}
void setSalary(double salary)
{
this->salary=salary;
}
double getSalary(){return salary;}
};
class Customer:public User{
private:
bool membership;
public:
Customer(size_t id,string username):User(id,username)
{
membership=false;
}
void setMemberActive()
{
membership=true;
}
bool isMemberActive()
{
return membership;
}
};
class UserManager
{
private:
vector<shared_ptr<User>>listOfUsers;
queue<shared_ptr<Customer>>queue;
public:
UserManager()
{
}
void addCustomer(size_t id,string username)
{
listOfUsers.push_back(make_shared<Customer>(id,username));
}
void removeCustomer(string username)
{
for(auto it=listOfUsers.begin();it!=listOfUsers.end();it++)
{
if(dynamic_pointer_cast<Customer>(*it))
{
if((*it)->getUsername()==username)
{
listOfUsers.erase(it);
}
}
}
}
shared_ptr<Customer> getCustomer(string username)
{
for(auto it=listOfUsers.begin();it!=listOfUsers.end();it++)
{
if(dynamic_pointer_cast<Customer>(*it))
{
if((*it)->getUsername()==username)
{
return dynamic_pointer_cast<Customer>(*it);
}
}
}
return nullptr;
}
void addToQueue(string username)
{
queue.push(getCustomer(username));
}
void removeCurrentCustomer()
{
queue.pop();
}
shared_ptr<Customer> getNextCustomer()
{
if(queue.empty())
{
return nullptr;
}
return queue.front();
}
/*
same process for user;
*/
};
class Display
{
private:
shared_ptr<Customer> m_customer;
shared_ptr<Book> m_book;
public:
Display(shared_ptr<Customer> _customer,shared_ptr<Book> _book ):m_customer(_customer),m_book(_book)
{
}
shared_ptr<Customer> getUser(){return m_customer;}
shared_ptr<Book> getBook(){return m_book;}
void displayInfo()
{
cout<<"Customer username: "<<m_customer->getUsername()<<endl;
cout<<"Member Active: "<<m_customer->isMemberActive();
cout<<"book id: "<<m_book->getId()<<endl;
cout<<"book title: "<< m_book->getTitle()<<endl;
}
};
class OnlineBookingSystem
{
private:
UserManager manager;
Library library;
shared_ptr<Display>display;
public:
OnlineBookingSystem()
{
UserManager manager;
Library library;
this->manager=manager;
this->library=library;
this->display=nullptr;
}
Library getLibrary()
{
return library;
}
UserManager getUserManager()
{
return manager;
}
void setDisplay(size_t id)
{
display=make_shared<Display>( manager.getNextCustomer(),library.getBook(id));
display->displayInfo();
}
shared_ptr<Display> getDisplay()
{
return this->display;
}
};
int main()
{
OnlineBookingSystem system;
auto lib=system.getLibrary();
lib.addBook("Adventure of Pablo",1234,BookGenre::Adventure);
auto manager=system.getUserManager();
manager.addCustomer(2020,"Michael");
auto _customer= manager.getCustomer("Michael");
_customer->setMemberActive();
manager.addToQueue("Michael");
system.setDisplay(1234);
return 0;
}
Problems I see:
Problem 1
Since the return type of OnlineBookingSystem::getLibrary() is Library, the line
auto lib=system.getLibrary();
construct lib as a copy of the object in system. Any changes made to lib are changes to the copy, not to the Library object in system.
To fix the problem, change the return type to a reference:
Library& getLibrary()
{
return library;
}
and capture the return value also as a reference in main.
auto& lib=system.getLibrary();
Problem 2
Similar to Problem 1 but this time it is in OnlineBookingSystem::getUserManager. Change its return type to be a reference:
UserManager& getUserManager()
{
return manager;
}
and capture the return value also as a reference in main.
auto& manager=system.getUserManager();
Problem 3
Adopt defensive programming at every step until something is a performanced bottleneck. If a return value of a function can be nullptr, check the return value at the point of invocation and deal with the case when the return value is indeed nullptr.
Update OnlineBookingSystem::setDisplay to:
void setDisplay(size_t id)
{
display=make_shared<Display>( manager.getNextCustomer(),library.getBook(id));
if ( display )
{
display->displayInfo();
}
else
{
// Deal with the nullptr case
std::cout << "Unable to find a book with id " << id << std::endl;
}
}
The problem
It comes down to your call to system.getUserManager() returning a copy of OnlineBookingSystem's manager field, instead of a pointer to it.
As a result, when you call manager.addToQueue("Michael"), it is adding Michael to the UserManager instance that is local to int main(), instead of the instance that's held in system.
Your function OnlineBookingSystem::setDisplay(size_t) makes a call to manager.getNextCustomer(). Because you've added Michael to a different instance of manager, this returns nullptr.
How to fix it
You simply need to modify OnlineBookingSystem::getUserManager() to return a pointer to manager instead of a copy of it:
UserManager* getUserManager()
{
return &manager;
}
Then modify the calling code to use the pointer dereference operator (->) instead of a period to access methods on manager.
I added some exception handling into some functions in my Project. Before adding the error handling the program was working normally. After adding the exceptions I now get garbage values in the constructor and mutator parameters and I'm not sure where its coming from. Some of the functions are called in no other location than the constructor, so I have no idea where they are getting the garbage data from.
I also checked for memory leaks with valgrind and some debugging with gdb, but didn't find anything. I'm at my wits end. I have attached a sample of the constructor cpp below and one of the mutators with the exception handling.
Protofield.cpp
ProtoField::ProtoField(std::string t_name, std::string t_abbreviation, FieldType t_type, Base t_base, int t_mask, std::string t_description, int t_offset, int t_length){
try{
setName(t_name);
setAbbreviation(t_abbreviation);
setType(t_type);
setBase(t_base);
setMask(t_mask);
setDescription(t_description);
setOffset(t_offset);
setLength(t_length);
m_valueString = std::map<int, std::string>();
}
catch(std::runtime_error e){
std::cerr<<"Error in ProtoField Constructor"<<std::endl;
std::cerr<<e.what()<<std::endl;
return;
}
}
/*Removed for brevity*/
void ProtoField::setMask(int t_mask){
if(mask != 0){
std::stringstream ss;
ss<<"Field " << m_abbreviation << " mask previously set: "<<m_mask;
throw std::runtime_error(ss.str());
}
else{
m_mask = t_mask;
}
return;
}
/*Removed for brevity*/
ProtoField.hpp
class ProtoField{
private:
std::string m_name;
std::string m_abbreviation;
FieldType m_type;
Base m_base;
int m_mask;
std::string m_description;
int m_offset;
int m_length;
std::map<int, std::string> m_valueString;
public:
ProtoField(
std::string t_name = "",
std::string t_abbreviation = "",
FieldType t_type = FieldType::ft_invalid,
Base t_base = Base::invalid,
int t_mask = 0,
std::string t_description = "",
int t_offset = -1,
int t_length = -1
);
std::string getName();
std::string getAbbreviation();
FieldType getType();
Base getBase();
int getMask();
std::string getDescription();
int getOffset();
int getLength();
std::map<int, std::string> getValueString();
void setName(std::string t_name);
void setAbbreviation(std::string t_abbreviation);
void setType(FieldType t_type);
void setType(std::string t_typestr);
void setBase(Base t_base);
void setBase(std::string t_basestr);
void setMask(int t_mask);
void setDescription(std::string t_description);
void setOffset(int t_offset);
void setLength(int t_length);
void addValueString(int t_key, std::string t_value);
void removeValueString(int t_key);
//other functions
std::string to_string();
};
I feel as though its also worth mentioning, only integers appear to be affected. The other values including strings and enums seem to remain consistent with their previous behaviors. So in the class shown, only the mask, offset, and length show odd behaviors.
Edit: For more detail where the constructor is called I included the two functions I know of here.
void parser::parseFields(ProtoData& t_data, ptree::ptree t_subtree){
try{
std::vector<ProtoField> fields;
for(auto val : t_subtree.get_child("")){
ProtoField field;
parseField(t_data, field, val.second);
fields.push_back(field);
}
for(auto field:fields){
t_data.addField(field);
}
}
catch(ptree::ptree_bad_path error){
std::cerr<<"Bad Path to Fields"<<std::endl;
}
catch(ptree::ptree_bad_data error){
std::cerr<<"Bad Data to fields"<<std::endl;
}
}
void parser::parseField(ProtoData& t_data, ProtoField& t_field, ptree::ptree t_subtree){
try{
t_field.setAbbreviation(t_subtree.get<std::string>("abbreviation"));
t_field.setName(t_data.getName() + "_" + t_field.getAbbreviation());
t_field.setBase(t_subtree.get<std::string>("base", "none"));
t_field.setType(t_subtree.get<std::string>("type"));
}
catch(ptree::ptree_bad_path error){
std::cerr<<"Bad Path to Field"<<std::endl;
}
catch(ptree::ptree_bad_data error){
std::cerr<<"Bad Data to field"<<std::endl;
}
}
Your constructor does not initialize m_mask. You then call setMask, which reads this yet-to-be-initialzed value (assuming that the if(mask != 0) line should be if(m_mask != 0)). This is Undefined Behavior. The value read could be anything. When it is a nonzero value, the exception will be thrown.
The solution is to either initialize m_mask before calling setMask, or assign to m_mask directly in the constructor and not call the helper function. (And since the constructor sets the mask, which can only be done once, why does that function even need to exist?)
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!
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..