How to print some specific atributes of derived class using overload << - c++

I have a base Class named Animals and 2 derived class Dog and Cat
class Animal{
protected:
std::string name;
std::string color;
public:
std::string getName() {
return name;
}
std::string getColor() {
return color;
}
...
class Cat : public Animal {
private :
int lives;
public :
int getLives() {
return lives;
}
...
class Dog : public Animal {
private :
std::string gender;
public:
std::string getGender(){
return gender;
}
...
and i have e vec of shared_ptr
std::vector<std::shared_ptr<Animal>> animals
I've added some cats and dogs in the vector and i am trying to print all the characteristics of each animal from vector ,using operator >>(this is a homework,we have to use this ) and i did this
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<std::shared_ptr<T>>& v)
{
for (int i = 0; i < v.size(); ++i) {
os << v[i]->getName();
os << "-";
os << v[i]->getColor();
if (i != v.size() - 1)
os << ", ";
os<<"\n";
}
return os;
}
but in this way i can print only the name and color or the animals(these atributes are in the base class)
My question is :
How can i print all the attributes ,for cats lives and for dogs gender???

Try this:
class Animal {
protected:
std::string name;
std::string color;
public:
virtual void print(std::ostream& os){
os << "Name:" << name <<" Color:"<< color;
}
void setName(string n) { name = n; }
void setColor(string c) { color = c; }
std::string getName() {
return name;
}
std::string getColor() {
return color;
}
};
class Cat : public Animal {
private:
int lives;
public:
void setLives(int n) { lives = n; }
void print(std::ostream& os) {
Animal::print(os);
os <<" Lives:"<<lives;
}
int getLives() {
return lives;
}
};
class Dog : public Animal {
private:
std::string gender;
public:
void setGender(string g) { gender = g; }
void print(std::ostream& os) {
Animal::print(os);
os << " Gender:" << gender;
}
std::string getGender() {
return gender;
}
};
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<std::shared_ptr<T>>& v)
{
for (int i = 0; i < v.size(); ++i) {
v[i]->print(os);
os << "\n";
}
return os;
}
int main()
{
shared_ptr<Dog> d1 = make_shared<Dog>();
d1->setName("Dog1"); d1->setColor("White"); d1->setGender("Male");
shared_ptr<Cat> c1 = make_shared<Cat>();
c1->setName("Cat1"); c1->setColor("Brown"); c1->setLives(1);
vector<shared_ptr<Animal>> vec;
vec.push_back(d1);
vec.push_back(c1);
cout << vec;
return 0;
}

Related

How to operate on only one type of derived class when working with multiple derived classes?

I have 1 base class, Item, and 3 derived classes: CD, Book, & List.
I figured out how to print out and add Item objects, regardless of whether it's a Book or CD, in a vector within a List object. But I can't figure out how to print only Books or only CDs. I can't make any mentions of a CD or Book class in the List class, and I can't move the bool isBook or isCD members to the base class.
class Item
{
protected:
string name;
int id;
public:
//pure virtual methods (ex: virtual bool isID(int);
};
class CD: public Item
{
private:
bool isCD;
public:
//defining virtual methods from base class for class specific operations
virtual string format() { return "Artist: " + name }
};
class Book: public Item
{
private:
bool isBook;
public:
//defining virtual methods from base class for class specific operations
virtual string format() { return "Author: " + name }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
void Add(Item &adding) {} // already figured out
void printAll() // print all objects in vector regardless of type Book or CD
{
for(auto &i: holdings)
cout << i->format() << '\n';
}
void printBooks(){}
void PrintCDs(){}
}
You don't need the isCD and isBook boolean members in each class. You can use dynamic_cast instead, eg:
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (Book *b = dynamic_cast<Book*>(i))
cout << b->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (CD *c = dynamic_cast<CD*>(i))
cout << c->format() << '\n';
}
}
};
If you don't want to use this approach, then you can use some additional virtual methods instead, eg:
class Item
{
...
public:
...
virtual bool isBook() const { return false; }
virtual bool isCD() const { return false; }
};
class CD: public Item
{
...
public:
...
bool isCD() const override { return true; }
};
class Book: public Item
{
...
public:
...
bool isBook() const override { return true; }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (i->isBook())
cout << i->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (i->isCD())
cout << i->format() << '\n';
}
}
};
Alternatively:
enum ItemType { itCD, itBook };
class Item
{
...
public:
...
virtual ItemType getType() const = 0;
};
class CD: public Item
{
...
public:
...
ItemType getType() const override { return itCD; }
};
class Book: public Item
{
...
public:
...
ItemType getType() const override { return itBook; }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (i->getType() == itBook)
cout << i->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (i->getType() == itCD)
cout << i->format() << '\n';
}
}
};

how to return or a list of items of care is based on several classes

In my function 'func' i want to create an object Menu who returns a breakfast with lemon and coffee. 'func' return a list of menu
When I try to display the menu for a breakfast that contains only lemon or only coffee it is displayed correctly. For example:
c.push_back(make_unique<Breakfast>("eggs", 10));
but when i try to display a menu that also contains lemon and coffee it shows me error in main
this is the program:
#include <iostream>
#include <vector>
using namespace std;
class Menu {
private:
int price;
public:
Menu(int p = 0) : price{ p } {}
virtual string description() = 0;
virtual int getPrice() {
return price;
}
virtual ~Menu() {}
};
class WithLemon : public Menu {
private:
Menu* meniu;
public:
WithLemon(Menu* n) :
meniu{ n } {}
string description() override {
return meniu->description() + " with lemon ";
}
int getPrice() override {
return meniu->getPrice() + 4;
}
};
class WithCoffee : public Menu {
private:
Menu* meniu;
public:
WithCoffee(Menu* n) :
meniu{ n } {
}
string description() override {
return meniu->description() + " with coffee ";
}
int getPrice() override {
return meniu->getPrice() + 5;
}
};
class Breakfast : public Menu {
private:
string name;
public:
Breakfast(string n, int p) :
name{ n }, Menu{ p } {
}
string description() override {
return name;
}
};
std::vector<std::unique_ptr<Menu>> func(void)
{
std::vector <std::unique_ptr<Menu> > c;
Breakfast a{ "breakfast eggs", 10 };
WithCoffee breakfast_with_coffee{ &a };
Menu* breakfast_with_coffee_and_lemon = new WithLemon{ &breakfast_with_coffee };
//cout << breakfast_with_coffee_and_lemon->description() << " " << breakfast_with_coffee_and_lemon->getPrice();// print ----> breakfast eggs with coffee with lemon 19
c.push_back(make_unique<WithLemon>(&breakfast_with_coffee));
return c;
}
int main() {
std::vector < std::unique_ptr<Menu> > lista = func();
for (int i = 0; i < lista.size(); i++) {
cout << lista[i]->description() << " " << lista[i]->getPrice() << endl; //error read memory access
}
return 0;
}
You can't take a pointer to automatic memory, store it in a smart pointer and leave the function. After you leave the function the automatic memory is freed and the smart pointer contains a dangling pointer. The simplest way to avoid this problem and other problems with memory leaks is to use smart pointers for all variables:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Menu {
private:
int price;
public:
Menu(int p = 0) : price{ p } {}
virtual std::string description() = 0;
virtual int getPrice() {
return price;
}
virtual ~Menu() = default;
};
class WithLemon : public Menu {
private:
std::unique_ptr<Menu> meniu;
public:
WithLemon(Menu* n) : meniu{ n } {}
std::string description() override {
return meniu->description() + " with lemon ";
}
int getPrice() override {
return meniu->getPrice() + 4;
}
};
class WithCoffee : public Menu {
private:
std::unique_ptr<Menu> meniu;
public:
WithCoffee(Menu* n) :
meniu{ n } {
}
std::string description() override {
return meniu->description() + " with coffee ";
}
int getPrice() override {
return meniu->getPrice() + 5;
}
};
class Breakfast : public Menu {
private:
std::string name;
public:
Breakfast(std::string n, int p) : Menu{ p }, name{ n } {}
std::string description() override {
return name;
}
};
std::vector<std::unique_ptr<Menu>> func(void) {
std::vector <std::unique_ptr<Menu> > c;
auto a = std::make_unique<Breakfast>("breakfast eggs", 10);
auto breakfast_with_coffee = std::make_unique<WithCoffee>(a.release());
//Menu* breakfast_with_coffee_and_lemon = new WithLemon{ breakfast_with_coffee };
//std::cout << breakfast_with_coffee_and_lemon->description() << " " << breakfast_with_coffee_and_lemon->getPrice();// print ----> breakfast eggs with coffee with lemon 19
c.push_back(std::make_unique<WithLemon>(breakfast_with_coffee.release()));
return c;
}
int main() {
std::vector < std::unique_ptr<Menu> > lista = func();
for (const auto &i : lista) {
std::cout << i->description() << " " << i->getPrice() << std::endl; //error read memory access
}
return 0;
}
Avoid raw new and delete. Avoid pointers to automatic memory.

How to create a decorator function without using virtual

I have to use the Decorator pattern, based on an UML diagram. Depending on the type of string I input, I have to return a price and a description. The issue I'm encountering is that the UML description strictly specifies that the price function is not virtual, and furthermore, it should only be implemented in the Smoothy interface, as shown below in the code:
#include<iostream>
using namespace std;
class Smoothy{
int price;
public:
int getPrice(){
return price;
}
virtual ~Smoothy() = default;
virtual string description() = 0;
};
class BasicSmoothy: public Smoothy{
private:
string nume;
public:
BasicSmoothy(string n): nume(n){}
string description(){
return nume;
}
};
class SmoothyDecorator:public Smoothy{
private:
Smoothy *b;
public:
SmoothyDecorator(Smoothy* bb){
b = bb;
}
~SmoothyDecorator(){
delete b;
}
string description(){
return b->description();
}
};
class SmoothyWithCream:public SmoothyDecorator{
public:
SmoothyWithCream(Smoothy *b):SmoothyDecorator(b){
}
string description(){
return SmoothyDecorator::description() + " with Cream!";
}
};
class SmoothyWithCinnamon:public SmoothyDecorator{
public:
SmoothyWithCinnamon(Smoothy *b):SmoothyDecorator(b){
}
string description(){
return SmoothyDecorator::description() + " with Cinnamon!";
}
};
int main(){
Smoothy* b = new SmoothyWithCinnamon(new BasicSmoothy("Kiwi"));
cout<<b->description();
}
I'm pretty sure my code reflects the Decorator pattern(plese let me know if it doesn't), but I'm not sure how to return the price, based on the string. In addition to that, the UML diagram specifies that the BasicSmoothy has two types, with two specific prices(Kiwi 10$, Strawberry 12$) and the Derived classes each add 2$ and 3$ to the final listed price.
Is there a way to return the price through the function getPrice() without it being virtual and without implementing it in the other classes?
You can make the price protected and overwrite it in the decorator:
#include<iostream>
using namespace std;
class Smoothy{
protected:
int price;
public:
int getPrice(){
return price;
}
virtual ~Smoothy() = default;
virtual string description() = 0;
};
class BasicSmoothy: public Smoothy{
private:
string nume;
public:
BasicSmoothy(string n): nume(n) {
if (nume == "Kiwi") {
price = 10;
} else if (nume == "Strawberry") {
price = 12;
} else {
throw;
}
}
string description(){
return nume;
}
};
class SmoothyDecorator:public Smoothy{
private:
Smoothy *b;
public:
SmoothyDecorator(Smoothy* bb){
b = bb;
}
~SmoothyDecorator(){
delete b;
}
string description(){
return b->description();
}
};
class SmoothyWithCream:public SmoothyDecorator{
public:
SmoothyWithCream(Smoothy *b):SmoothyDecorator(b){
price = b->getPrice() + 2;
}
string description(){
return SmoothyDecorator::description() + " with Cream!";
}
};
class SmoothyWithCinnamon:public SmoothyDecorator{
public:
SmoothyWithCinnamon(Smoothy *b):SmoothyDecorator(b) {
price = b->getPrice() + 3;
}
string description(){
return SmoothyDecorator::description() + " with Cinnamon!";
}
};
int main(){
Smoothy* b = new SmoothyWithCinnamon(new BasicSmoothy("Kiwi"));
cout<<b->description() << std::endl;
cout << b->getPrice();
}
For anyone curios, I managed to find the solution.
class Smoothy
{
public:
Smoothy()
{
}
Smoothy(int n):
price(n)
{
};
virtual ~Smoothy() = default;
int getPrice()
{
return price;
}
virtual string description() = 0;
private:
int price;
};
class BasicSmoothy :
public Smoothy
{
public:
BasicSmoothy(string n) :
Smoothy(n=="Kiwi"?10:12),
nume(n)
{
}
string description()
{
return nume;
}
private:
string nume;
};
class SmoothyDecorator :
public Smoothy
{
public:
SmoothyDecorator(Smoothy* bb, int pret) :
Smoothy(pret + bb->getPrice()), b(bb)
{
}
~SmoothyDecorator()
{
delete b;
}
string description()
{
return b->description();
}
private:
Smoothy* b;
};
class SmoothyWithCream :
public SmoothyDecorator
{
public:
SmoothyWithCream(Smoothy* b) :
SmoothyDecorator(b, 2)
{
}
virtual string description()
{
return SmoothyDecorator::description() + " with Cream!" + to_string(getPrice());
}
};
class SmoothyWithCinnamon :
public SmoothyDecorator
{
public:
SmoothyWithCinnamon(Smoothy* b) :
SmoothyDecorator(b, 3)
{
}
virtual string description()
{
return SmoothyDecorator::description() + " with Cinnamon!" + to_string(getPrice());
}
};
int main()
{
Smoothy* b1 = new SmoothyWithCinnamon(new SmoothyWithCream(new BasicSmoothy("Kiwi")));
Smoothy* b2 = new SmoothyWithCinnamon(new SmoothyWithCream(new BasicSmoothy("Strawberry")));
cout <<b1->description() << std::endl;
cout <<b2->description() << std::endl;
delete b1;
delete b2;
}

Make a collection of an abstract class type, Abstract Class vector of shared_ptr

Error
e/c++/v1/algorithm:642:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:321:9: error:
field type 'Space' is an abstract class
_T2 second;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/map:624:16: note:
Question
How can I define a std::vector of type Space which is an abstract class and then fill this vector with instances of the derived classes Empty, Snake, Ladder.
Context
I know abstract classes in C++ can not be instantiated. Instead I've read in several posts on this and other sites that you can create a collection of an abstract type if it the type is defined as a star * pointer or any of the <memory> managed pointer data types like std::unqiue_ptr<T>. I've tried to used shared_ptr<Space> in my case, but still unable to define the collection properly. I am compiled my code using g++ -std=c++17 main.cpp && ./a.out.
Code
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <memory>
#include <typeinfo>
#include <queue>
#include <string>
#include <vector>
class Player
{
private:
int m_current_space = 1;
public:
Player() {}
void role_dice() {
m_current_space += floor( (rand()%10 + 1) / 3 );
}
int const get_current_space() {
return m_current_space;
}
void set_current_space(int current_space) {
m_current_space = current_space;
}
};
class Space
{
protected:
int m_id;
std::vector<Space> m_paths;
public:
Space() {} // requied to use [] operator in map
Space(int id) : m_id(id) {}
void add_path(Space& s) {
m_paths.push_back(s);
}
int get_id() {
return m_id;
}
virtual std::string class_type() = 0;
};
class Empty : public Space
{
public:
Empty(int id) : Space(id) {}
std::string class_type() {
return "Empty";
}
};
class Ladder : public Space
{
public:
Ladder(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(1);
}
std::string class_type() {
return "Ladder";
}
};
class Snake : public Space
{
public:
Snake(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(4);
}
std::string class_type() {
return "Snake";
}
};
class Board
{
private:
std::map<int, Space> m_board;
public:
void add_space(Space& s) {
m_board[s.get_id()] = s;
}
void draw_board() {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
std::cout << "○\n";
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
std::cout << "○ ";
}
++i;
}
}
void update_player_on_board(int position) {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
if (space_key == position) {
std::cout << "●\n";
}
else {
std::cout << "○\n";
}
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
if (space_key == position) {
std::cout << "● ";
}
else {
std::cout << "○ ";
}
}
++i;
}
}
const std::map<int, Space> get_board() {
return m_board;
}
friend std::ostream &operator<<(std::ostream& os, const Board& b) {
return os;
}
};
class GameStateManager
{
private:
std::string m_state = "game over";
bool m_playing = false;
public:
std::string const get_state() {
return m_state;
}
void set_state(std::string state) {
m_state = state;
}
};
int main()
{
std::cout << "Welcome to Bowser's 9 board game\n";
std::cout << "Start? y(yes) n(no)\n";
GameStateManager game_manager;
game_manager.set_state("playing");
auto space1 = std::make_shared<Space>(1);
auto space2 = std::make_shared<Space>(2);
auto space3 = std::make_shared<Space>(3);
auto space4 = std::make_shared<Space>(4);
auto space5 = std::make_shared<Space>(5);
auto space6 = std::make_shared<Space>(6);
auto space7 = std::make_shared<Space>(7);
auto space8 = std::make_shared<Space>(8);
auto space9 = std::make_shared<Space>(9);
std::vector<std::shared_ptr<Space>> v {
space1, space2, space3,
space4, space5, space6,
space7, space8, space9
};
Board bowsers_bigbad_laddersnake;
for(int i = 0; i < 10; ++i) {
bowsers_bigbad_laddersnake.add_space(*(v[i]));
}
bowsers_bigbad_laddersnake.draw_board();
Player mario;
int turn = 0;
while(game_manager.get_state() == "playing") {
std::cin.get();
std::cout << "-- Turn " << ++turn << " --" << '\n';
mario.role_dice();
bowsers_bigbad_laddersnake.update_player_on_board(mario.get_current_space());
if (mario.get_current_space() >= 9) {
game_manager.set_state("game over");
}
}
std::cout << "Thanks a so much for to playing!\nPress any key to continue . . .\n";
std::cin.get();
return 0;
}
You seem to have removed a lot of code to get into details here.
Have a Space pointer (smart or raw). Instantiate the specific space that you want, point to it with your pointer of type Space. Example std::shared_ptr<Space> pointerToSpace = std::make_shared<Snake> ("I'm a snake"); Now, without loss of generality, you can print the contents (of concrete type) with just the pointer to the space pointerToSpace->class_type(). Yes, you can have a collection of shared_ptrs in a container.

Adding two different Objects by overloading operator+ C++

I've been trying to figure out how to add a private member from Object A, to a private member from Object B.
Both Cat and Dog Class's inheriate from the base class Animal. I have a thrid class 'MyClass', that I want to inheriate the private members of the Cat and Dog class. So in MyClass, I have a friend function to overload the + operator. THe friend function is defined as follows:
MyClass operator+(const Dog &dObj, const Cat &cObj);
I want to access dObj.age and cObj.age within the above function, invoke by this statement in main:
mObj = dObj + cObj;
Here is the entire source for a complete reference into the class objects:
#include <iostream>
#include <vld.h>
using namespace std;
class Animal
{
public :
Animal() {};
virtual void eat() = 0 {};
virtual void walk() = 0 {};
};
class Dog : public Animal
{
public :
Dog(const char * name, const char * gender, int age);
Dog() : name(NULL), gender(NULL), age(0) {};
virtual ~Dog();
void eat();
void bark();
void walk();
private :
char * name;
char * gender;
int age;
};
class Cat : public Animal
{
public :
Cat(const char * name, const char * gender, int age);
Cat() : name(NULL), gender(NULL), age(0) {};
virtual ~Cat();
void eat();
void meow();
void walk();
private :
char * name;
char * gender;
int age;
};
class MyClass : private Cat, private Dog
{
public :
MyClass() : action(NULL) {};
void setInstance(Animal &newInstance);
void doSomething();
friend MyClass operator+(const Dog &dObj, const Cat &cObj);
private :
Animal * action;
};
Cat::Cat(const char * name, const char * gender, int age) :
name(new char[strlen(name)+1]), gender(new char[strlen(gender)+1]), age(age)
{
if (name)
{
size_t length = strlen(name) +1;
strcpy_s(this->name, length, name);
}
else name = NULL;
if (gender)
{
size_t length = strlen(gender) +1;
strcpy_s(this->gender, length, gender);
}
else gender = NULL;
if (age)
{
this->age = age;
}
}
Cat::~Cat()
{
delete name;
delete gender;
age = 0;
}
void Cat::walk()
{
cout << name << " is walking now.. " << endl;
}
void Cat::eat()
{
cout << name << " is eating now.. " << endl;
}
void Cat::meow()
{
cout << name << " says meow.. " << endl;
}
Dog::Dog(const char * name, const char * gender, int age) :
name(new char[strlen(name)+1]), gender(new char[strlen(gender)+1]), age(age)
{
if (name)
{
size_t length = strlen(name) +1;
strcpy_s(this->name, length, name);
}
else name = NULL;
if (gender)
{
size_t length = strlen(gender) +1;
strcpy_s(this->gender, length, gender);
}
else gender = NULL;
if (age)
{
this->age = age;
}
}
Dog::~Dog()
{
delete name;
delete gender;
age = 0;
}
void Dog::eat()
{
cout << name << " is eating now.. " << endl;
}
void Dog::bark()
{
cout << name << " says woof.. " << endl;
}
void Dog::walk()
{
cout << name << " is walking now.." << endl;
}
void MyClass::setInstance(Animal &newInstance)
{
action = &newInstance;
}
void MyClass::doSomething()
{
action->walk();
action->eat();
}
MyClass operator+(const Dog &dObj, const Cat &cObj)
{
MyClass A;
//dObj.age;
//cObj.age;
return A;
}
int main()
{
MyClass mObj;
Dog dObj("B", "Male", 4);
Cat cObj("C", "Female", 5);
mObj.setInstance(dObj); // set the instance specific to the object.
mObj.doSomething(); // something happens based on which object is passed in
dObj.bark();
mObj.setInstance(cObj);
mObj.doSomething();
cObj.meow();
mObj = dObj + cObj;
return 0;
}
If you want to access a private member of Dog, then your operator has to be a friend of Dog, not just a friend of some derived class of Dog.
If you add friend MyClass operator+(const Dog &dObj, const Cat &cObj); to the definition of class Cat and class Dog, then the function will have access to dObj.age and cObj.age.
Alternatively, you could add friend MyClass; to the definitions of class Cat and class Dog, but then all of MyClass's functions have access to all of Cat and Dog's internals.
Alternatively alternatively, you could make age protected rather than private.