I have made a programme that has two types of classes that implements owner as well as dogs , I am having a problem with the iterator part in the << operator in the Owner.h file, I know that we can't use an iterator for an STL container having its type as a custom class , but then what is the alternative to do so ?
I am attaching the files for you reference with the main file
I know this is a lot to ask from you guys , but just recommend me a way and i'll figure it out
Thanks
Main File
#include <iostream>
#include "Owner.h"
#include "Dog.h"
using namespace std;
void Purchase(Owner& owner, Dog& dog) {
owner.AddDog(dog);
dog.SetOwner(owner);
}
int main() {
Owner owner1("Michael Hagley", "14 Brentwood Terrace");
Owner owner2("Oliver Walter", "299 Mill Road");
Dog dog1("Cheeto", 5, 2000.00);
Dog dog2("Mavrick", 8, 1800.00);
Dog dog3("Biglet", 4, 2100.00);
Dog dog4("Snoopy", 11, 600.00);
Dog dog5("Leggo", 2, 500.00);
Dog dog6("Bugsy", 4, 1100.00);
Purchase(owner1, dog1);
Purchase(owner1, dog5);
Purchase(owner2, dog2);
Purchase(owner2, dog3);
Purchase(owner2, dog6);
cout<<owner1.GetName()<<" Has the following dogs"<<std::endl;
cout<<std::endl;
cout<<owner2.GetName()<<"has the following dogs"<<std::endl;
// cout << owner1;
//
// cout << owner2;
Owner* owner = dog1.GetOwner();
if (owner) cout << dog1.GetName() << " belongs to " << owner->GetName() << endl;
owner = dog4.GetOwner();
if (owner){
cout << dog4.GetName() << " belongs to " << owner->GetName() << endl;
}
else{
cout<<dog4.GetName()<<" Has no owner"<<endl;
}
return 0;
}
Owner File
//
// Created by Kannav Sethi on 21/04/22.
//
#ifndef FINALS_OWNER_H
#define FINALS_OWNER_H
#include <iostream>
#include <vector>
//Wwe'll be using the concept of association and aggregation here
class Dog;
class Owner{
// provided the variables for the Owner here
// the only viable STL container here is vectors of type dogs
//but there is a problem with it , I wont be able to iterate over the dogs vector due to it being of a custom type
//Lets try that out here
std::string name;
std::string address;
std::vector<Dog> dogs;
int size=0;
public:
// constructor
Owner(){
name="";
address="";
};
//constructor
Owner(std::string name,std::string address){
this->name=name;
this->address=address;
};
// tried out making a copy assignment but it was futile
// Owner& operator=(Owner& oTemp){
// this->name=oTemp.name;
// this->address=oTemp.address;
// for(auto i = oTemp.dogs.begin();i!=oTemp.dogs.end();i++){
// this->dogs.push_back(i);
// }
// return *this;
// }
//add dog
void AddDog(Dog& dog){
dogs.push_back(dog);
size++;
}
//get name function
std::string GetName(){
return this->name;
}
friend std::ostream& operator<<(std::ostream& os,Owner& owner);
};
std::ostream& operator<<(std::ostream& os,Owner& owner){
std::vector<Dog>::iterator it;
os<<owner.name<<"of "<<owner.address<<" has the following dogs"<<std::endl;
double sum=0;
for(auto it=owner.dogs.begin();it!=owner.dogs.end();it){
it.operator++();
sum+=it.cost;
}
std::cout<<"the total costs of all the dogs are $"<<sum<<std::endl;
#endif //FINALS_OWNER_H
Dog file
//
// Created by Kannav Sethi on 21/04/22.
//
#ifndef FINALS_DOG_H
#define FINALS_DOG_H
#include <iostream>
#include "Owner.h"
class Owner;
class Dog{
// the variables
std::string name;
int age;
double cost;
Owner* owner;
public:
// constructors
Dog(std::string name,int age,double cost){
this->name=name;
this->age=age;
this->cost=cost;
}
// set owner
void SetOwner(Owner& _owner){
this->owner=(&_owner);
}
// get owner
Owner* GetOwner(){
return this->owner;
}
// getName
std::string GetName(){
return this->name;
}
// this streaming operator works but not the one I used in Owner
friend std::ostream& operator<<(std::ostream& os, Dog dog);
};
std::ostream& operator<<(std::ostream& os, Dog dog){
os<<dog.name<<" is "<<dog.age<<" years old and costs "<<dog.cost<<std::endl;
}
#endif //FINALS_DOG_H
You need
std::ostream& operator<<(std::ostream& os, Owner& owner) {
os << owner.name << "of " << owner.address << " has the following dogs" << std::endl;
double sum = 0;
for (auto it = owner.dogs.begin(); it != owner.dogs.end(); it++) {
sum += it->cost;
std::cout << it->name << std::endl;
}
std::cout << "the total costs of all the dogs are $" << sum << std::endl;
return os;
}
You didnt seem to realize that you have to use '->' with an iterator
You also need to make this a friend of Dog (cost is private)
// this streaming operator works but not the one I used in Owner
friend std::ostream& operator<<(std::ostream& os, Dog dog);
friend std::ostream& operator<<(std::ostream& os, Owner& o);
Related
I have an object of type piggyBank and I need to write data of this object into a file and then read it. I am aware of how to write/read to a text file but how can I overload the << operator so I can write data about the object into a file?
My code for the class here:
piggyBank.h
#include <string>
#ifndef PIGGYBANK_H
#define PIGGYBANK_H
class PiggyBank
{
private:
std::string owner;
int balance;
bool broken;
int id;
static int nrOfObjects;
public:
PiggyBank(void);
PiggyBank(std::string name);
std::string getOwnerName() const;
void setOwnerName(std::string name);
bool isBroken() ;
int getBalance(int & amount) ;
};
#endif /* PIGGYBANK_H */
piggyBank.cpp
#include "PiggyBank.h"
#include "readWrite.h"
#include <string>
#include <iostream>
using namespace std;
int PiggyBank::nrOfObjects = 0; // outside constructor
PiggyBank::getNrOfObjects(){
return nrOfObjects;
}
PiggyBank::PiggyBank(void){
{this->owner="";this->balance=0;this->broken=false;}
id = ++nrOfObjects;
}
PiggyBank::PiggyBank(std::string name, int startBalance){
{this->owner=name;this->balance=startBalance;this->broken=false;}
id = ++nrOfObjects;
}
string PiggyBank::getOwnerName() const{
return this->owner;
}
void PiggyBank::setOwnerName(string name){
this->owner = name;
}
bool PiggyBank::isBroken() {
return this->broken;
}
int PiggyBank::getBalance(int & amount) {
if(!broken){
amount = balance;
return 0;
}else{
return -1;
}
}
You want the << operator to be a friend to the class and to return ostream&.
Here is a simple example to get an idea about how it works.
friend ostream& operator << (ostream& os, const PiggyBank& obj)
{
// For example something like this
os << "Information that you want to output to the file:\n";
os << "Owner: " << obj.owner << "\n";
return os;
}
And then you can use it like this:
PiggyBack obj;
ofstream fout("file.txt");
// also check to see if the file opened correctly
if(fout.fail())
{
cout << "File failed to open\n";
return 0;
}
fout << obj;
// now you have written the owner information onto the file as well as the message before it
// inside the operator<< overload
// close the resource at the end
fout.close();
The cool part is that you can use it to print to the console too by changing fout to be cout.
For example:
cout << obj; // will print to the console
Very simple. Overload the inserter operator. Write this into your class:
friend std::ostream& operator << (std::ostream& os, const PiggyBank& pb) {
return os << pb.owner << . . . // Whatever you want
Then you can use the inserter operator as for any other data type:
int main() {
PiggyBank pb;
if (std::ofstream os("FileName"); os) {
os << pb << "\n";
}
return 0;
}
When putting freeSeats to 0, my code still says that a person has avalibale seats in his/hers car.
I have created two classes. One for Car and one for Person. The Car class has a function to see if there are free seats in the car. A person-object can have a car. When checking if the person has avalibale seats, my code responds "Yes" even though I give input "0". Why?
#pragma once
#include <iostream>
//Here is class Car declaration
class Car {
private:
unsigned int freeSeats;
public:
bool hasFreeSeats() const;
void reserveFreeSeat();
Car( unsigned int freeSeats);
};
//Here is function definition
#include "Car.h"
bool Car::hasFreeSeats() const {
if (freeSeats > 0)
return true;
return false;
}
void Car::reserveFreeSeat() {
--freeSeats;
}
Car::Car(unsigned int freeSeas) :
freeSeats{ freeSeats }
{
}
//Here is class Person declaration
class Person {
private:
std::string name;
std::string email;
Car *car; //pointer to a car
public:
Person(std::string name, std::string email, Car *car = nullptr);
std::string getName() const;
std::string getEmail() const;
void setEmail();
bool hasAvalibaleSeats() const;
friend std::ostream& operator << (std::ostream& os, const Person& p);
};
//Here is function definition
Person::Person(std::string name, std::string email, Car *car) :
name{ name }, email{ email }, car{ car }
{
}
std::string Person::getName() const {
return name;
}
std::string Person::getEmail() const {
return email;
}
void Person::setEmail() {
std::string newEmail;
std::cout << "What is the e-mail adress?";
std::cin >> newEmail;
email = newEmail;
std::cout << "E-mail has been set." << std::endl;
}
bool Person::hasAvalibaleSeats() const {
if (car != nullptr) { //check if there is a car
return car->hasFreeSeats();
}
return false;
}
std::ostream& operator << (std::ostream& os, const Person& p) {
std::string seats = "No";
if (p.hasAvalibaleSeats())
seats = "Yes";
return os << "Name: " << p.name << "\nE-mail: " << p.email << "\nHas free seats: " << seats << std::endl;
}
//From main im calling
#include "Car.h"
#include "Person.h"
int main() {
Car ferrari{ 2 };
Car bugatti{ 3 };
Car jeep{0};
Person one{ "Aleksander","aleks#aleks.com", &ferrari };
Person two{ "Sara","sara#sara.com", &bugatti };
Person three{ "Daniel", "daniel#daniel.com", &jeep };
Person four{ "Chris", "chris#chris.com" };
std::cout << one << std::endl;
std::cout << two << std::endl;
std::cout << three << std::endl;
std::cout << four << std::endl;
system("pause");
return 0;
}
I get
Name: Aleksander
E-mail: aleks#aleks.com
Has free seats: Yes
Name: Sara
E-mail: sara#sara.com
Has free seats: Yes
Name: Daniel
E-mail: daniel#daniel.com
Has free seats: Yes
Name: Chris
E-mail: chris#chris.com
Has free seats: No
But I want Daniel has free seats to be "No"
There's a typo here:
Car::Car(unsigned int freeSeas) :
freeSeats{ freeSeats }
{}
You wrote freeSeas instead of freeSeats. Due to that, the freeSeas parameter is unused and freeSeats{ freeSeats } does nothing as freeSeats is refering to the member variable, not the parameter.
Debugging is way easier when you enable compiler warnings. Compiler is your friend, and will help you immensely if you are willing to hear it.
For example, gcc gave me the following warnings when compiling your code:
prog.cc: In constructor 'Car::Car(unsigned int)':
prog.cc:37:23: warning: unused parameter 'freeSeas' [-Wunused-parameter]
Car::Car(unsigned int freeSeas) :
~~~~~~~~~~~~~^~~~~~~~
prog.cc: In constructor 'Car::Car(unsigned int)':
prog.cc:38:16: warning: '*<unknown>.Car::freeSeats' is used uninitialized in this function [-Wuninitialized]
freeSeats{ freeSeats }
^~~~~~~~~
I don't have to understand everything, but it tells me 2 things:
There is unused argument (why? it is used to initialize...)
Variable is initialized with uninitialized value (why?)
It made me look closer at this constructor and then you can see the typo.
Pardon the example but in this case:
#include <iostream>
#include <string>
using namespace std;
class A {
private:
string theName;
int theAge;
public:
A() : theName(""), theAge(0) { }
A(string name, int age) : theName(name), theAge(age) { }
};
class B {
private:
A theArray[1];
public:
void set(const A value) {theArray[0] = value; }
A get() const { return theArray[0]; }
};
int main()
{
A man("Bob", 25);
B manPlace;
manPlace.set(man);
cout << manPlace.get();
return 0;
}
Is it possible for me to retrieve the contents of the "man" object in main when I call manPlace.get()? My intention is to print both the name (Bob) and the age (25) when I call manPlace.get(). I want to store an object within an array within another class and I can retrieve the contents of said array within the main.
You need to define a ostream::operator<< on your A class to accomplish that - otherwise the format how age and name should be generated as text-output is undefined (and they are private members of your A class).
Take a look at the reference for ostream::operator<<. For your A class, such a operator could be defined like this:
std::ostream& operator<< (std::ostream &out, A &a) {
out << "Name: " << a.theName << std::endl;
out << "Age: " << a.theAge << std::endl;
return out;
}
Which would output something like:
Name: XX
Age: YY
So your complete code would be:
#include <iostream>
#include <string>
using namespace std;
class A {
private:
string theName;
int theAge;
public:
A() : theName(""), theAge(0) { }
A(string name, int age) : theName(name), theAge(age) { }
friend std::ostream& operator<< (std::ostream &out, A &a) {
out << "Name: " << a.theName << std::endl;
out << "Age: " << a.theAge << std::endl;
return out;
}
};
class B {
private:
A theArray[1];
public:
void set(const A value) { theArray[0] = value; }
A get() const { return theArray[0]; }
};
int main()
{
A man("Bob", 25);
B manPlace;
manPlace.set(man);
cout << manPlace.get();
return 0;
}
which will output:
Name: Bob
Age: 25
I have a base class called Item:
#ifndef ITEM_H
#define ITEM_H
#include <ostream>
class Item {
public:
virtual ~Item() {}
virtual void print(std::ostream& out) const {}
friend std::ostream& operator << (std::ostream& out, Item& item){
item.print(out);
return out;
}
};
#endif
and I have a derived class Tower:
#ifndef TOWER_H
#define TOWER_H
#include <iostream>
#include <iostream>
#include <exception>
#include "item.h"
#include "Card.h"
class Tower : public Item {
unsigned height;
void print(std::ostream& o) const;
public:
Tower(const Card& card);
int demolish(Card& card) const;
unsigned getHeight() const;
};
#endif
Source code for Tower:
#include "tower.h"
Tower::Tower(const Card& card){
height = card.getDis();
}
void Tower::print(std::ostream& o) const {
o << height;
}
int Tower::demolish(Card& card) const{
try {
if(height != card.getDis()){
throw std::exception ();
} else {
return height;
}
} catch (std::exception e){
cout<< "Card's value not enough to demolish the tower." << endl;
}
}
unsigned Tower::getHeight() const {
return height;
}
Now I'm trying to test the code to see if the operator overloading works properly:
void test() {
Card card (Card::SOUTH, 3);
Tower tower(card);
std::cout << "Printing tower: " << tower << std::endl; //PRINTS OUT 3 AS EXPECTED
Card one (Card::NORTH, 2);
Card two (Card::WEST, 3);
std::cout << "Expecting to receive an error: " <<endl;
tower.demolish(one);
std::cout << "Expecting to have the tower demolished: ";
std::cout << tower.demolish(two) <<std::endl;
std::cout << "Height of the tower: " << tower.getHeight() <<std::endl;
std::vector<Item> items; //creating an Item vector
items.push_back(Tower(one));
Item items2[1]; //creating an array of Items
items[0]= tower;
std::cout << "Printing out an Item: ";
std::cout << items.back()<<std::endl; //EXPECTING TO GET 2 BUT IT PRINTS NOTHING, WHY IS THAT?
std::cout << "OR: " << items2[0]<<std::endl; //SAME ISSUE HERE, EXPECTING TO GET 3
}
As can be understood from the code, a Card holds an integer value distance and an enum value direction. It would've been a mess if i included that code too. I have commented my questions in the last piece of code test(). Thanks for your help in advance.
std::vector<Item> items; //creating an Item vector
items.push_back(Tower(one));
What happens here is called "slicing". Since you're not storing pointers, but actual objects, the Tower part of the class is just cut off and only the Item part is pushed into the vector. To use virtual functions and polymorphism, you need a reference or pointer to the base class.
std::vector<Item*> items; //creating an Item vector
items.push_back(new Tower(one));
// ...
// at the end of main:
for(int i=0; i < items.size(); ++i)
delete items[i];
Or with smart pointers from Boost or a C++11 library
std::vector<shared_ptr<Item>> items;
items.push_back(make_shared<Tower>(one));
// nothing further needs to be done
For printing, you now obviously need to dereference the pointer:
std::cout << "Printing out an Item: ";
std::cout << *items.back()<<std::endl;
std::cout << "OR: " << *items2[0]<<std::endl;
}
I'm having an issue with overloading the << operator. Everything prints and enters fine, but when I try and return the ostream, I get this error:
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
I've also already overloaded another << operator in this project that has returned an ostream just fine. This operator isn't used in the following code. Here's the code:
#include "header1.h"
#include <iostream>
using namespace std;
class Car
{
public:
friend class Extras;
friend int main();
friend ostream& operator<< (ostream& os, const Car& in);
Car();
Car(string in_name, int in_year, string in_color, float in_cost);
private:
string name, color;
int year, extr_num;
float cost;
Extras *extr;
};
int main()
{
Car c1;
cout << c1;
return 0;
}
//Default Constructor
Car::Car()
{
name = "TEMP";
color = "BLUE";
year = 0;
cost = 0;
extr = new Extras[3];
extr_num = 0;
}
//Constructor
Car::Car(string in_name, int in_year, string in_color, float in_cost)
{
name = in_name;
color = in_color;
year = in_year;
cost = in_cost;
extr = new Extras[3];
extr_num = 0;
}
//Overloaded << operator for Car class
//This function is the one that fails.
ostream& operator<< (ostream& os, const Car& in)
{
os.precision(2);
os << in.name << ", " << in.year << ", "
<< in.color << ", $"<< in.cost << ", ";
os << "extras include: ";
os << endl;
return os; //Line of code in question
}
This bit of code in the other header works perfectly fine:
ostream& operator<< (ostream& os, Extras const &in)
{
os << in.ex_list;
return os;
}
Everything prints to the screen fine before the return. And these two functions look the same to me, can someone more experience with C++ tell me otherwise?
There's nothing in the shown code that will cause the problem you describe. The "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)" error is an indication that the heap was corrupted at an earlier point, it's being detected at your return statement but isn't otherwise related to the code in your operator<<
You've hosed your heap. It may or may not have anything to do with the code currently running. Don't see anything immediately apparent in what you've decided to show us that would cause it though I'd start with any use of raw pointers.