Class Inheritance c++ - c++

i have a base class product and a child class multiBuyProduct
class Product
{
public:
Product(std::string name, Amount price);
}
class MultiBuyProduct :public Product
{
public:
MultiBuyProduct(std::string aName, Amount price, int minDiscountedQuantity, int discountedPercent);
now obviously some of the constructor variables are the same but in my main class i assume if i want the functionality of multiBuyProduct i need to call it? or can i call product and pass values for the multiBuyProduct constructor into a parameter that is expecting a product?
Below shows a method where this is used
void ShoppingCart::add(Product p, int quantity, bool end)
{
}
Above is the method i want to sent the parameters to but i dont know if i need to change the code for this method to accept a MultiBuyProduct or ...??
EDIT: sorry forgot to mention 'Amount' is a class that takes two integers
Amount amount(0,1);

You should change ShoppingCart::add something like below, to achieve polymorphic behavior:
void ShoppingCart::add(Product *p, int quantity, bool end)
{
p->doSomething();
// ...
Product *product = p;
product->doSomething();
// ...
}
Usage:
ShoppingCart shoppingCart;
MultiBuyProduct multiBuyProduct("Paper", Amount(0,1), 1, 1);
shoppingCart.add(&multiBuyProduct, 1, true);

You will probably want to add a virtual method in Product, say, Amount Product::calculatePrice(int quantity), and override it in MultiBuyProduct so that it performs the correct calculation based on minDiscountedQuantity. Then, call this method from add(). Furthermore, you need to pass a reference (Product&) or a pointer (Product*) to add() in order for virtual method invocation to work.

You should change a few things.
You need a type of pointer or reference for polymorphic behaviour.
You need to call the base class constructor.
You need to override your virtual methods.
You should watch out for proper memory management once you rely on pointers.
You should try to be const correct.
Consider this example below:
#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <sstream>
class Product
{
private:
double Price;
std::string Name;
public:
Product(const std::string& name, double price)
: Price(price),
Name(name)
{
std::cout << "Created " << name << " for $" << price << std::endl;
}
virtual std::string GetName() const
{
return Name;
}
virtual double GetPrice() const
{
return Price;
}
};
class MultiProduct :public Product
{
private:
int Quantity;
public:
MultiProduct(const std::string& name, double price, int quantity)
: Product(name, price),
Quantity(quantity)
{
std::cout << "Created " << quantity << "x " << name << " for $" << price << " each." << std::endl;
}
virtual double GetPrice() const
{
return Product::GetPrice() * Quantity;
}
virtual std::string GetName() const
{
std::stringstream s;
s << Product::GetName();
s << " x";
s << Quantity;
return s.str();
}
};
class ShoppingCart
{
private:
std::vector< std::shared_ptr<Product> > Cart;
public:
void Add( std::shared_ptr<Product> product )
{
Cart.push_back( product );
}
void PrintInvoice() const
{
std::cout << "Printing Invoice:" << std::endl;
for( auto it = Cart.begin() ; it != Cart.end() ; ++it )
{
std::cout << (*it)->GetName() << ": " << (*it)->GetPrice() << std::endl;;
}
}
};
int main()
{
ShoppingCart cart;
cart.Add( std::shared_ptr<Product>( new Product( "cheese", 1.23 ) ) );
cart.Add( std::shared_ptr<Product>( new MultiProduct( "bread", 2.33, 3 ) ) );
cart.Add( std::shared_ptr<Product>( new Product( "butter", 3.21 ) ) );
cart.Add( std::shared_ptr<Product>( new MultiProduct( "milk", 0.55, 5 ) ) );
cart.Add( std::shared_ptr<Product>( new Product( "honey", 5.55 ) ) );
cart.PrintInvoice();
std::cout << "Press any key to continue" << std::endl;
std::cin.get();
return 0;
}

Related

Troubles with std::set.insert c++

I have a set of a custom class and when I'm trying to insert an object of that class, the terminal gives me an error:
#ifndef EMPLOYEE_HH
#define EMPLOYEE_HH
#include <string>
#include <iostream>
#include <set>
#include <iterator>
using namespace std ;
class Employee {
public:
// Constructor
Employee(const char* name, double salary) : _name(name), _salary(salary) {}
// Accessors
const char* name() const { return _name.c_str() ; }
double salary() const { return _salary ; }
// Print functions
void businessCard(ostream& os = cout) const {
os << " +------------------+ " << endl
<< " | ACME Corporation | " << endl
<< " +------------------+ " << endl
<< " " << name() << endl ;
}
private:
string _name ;
double _salary ;
} ;
class Manager : public Employee{
public:
Manager(const char* name, double salary) : Employee(name, salary) {};
void addSubordinate(Employee& empl){
_subs.insert(empl);
}
const set<Employee*>& listOfSubordinates() const{
return _subs;
}
void businessCard() const{
Employee::businessCard();
set <Employee*>::iterator it=_subs.begin();
cout <<"Managed employees: " <<endl;
while(it!=_subs.end()){
cout <<*it++ <<endl;
}
}
private:
set <Employee*> _subs;
};
#endif
The addSubordinate() routine:
void addSubordinate(Employee& empl){
_subs.insert(empl);
}
returns this error:
no instance of overloaded function "std::set<_Key, _Compare, _Alloc>::insert [with _Key=Employee *, _Compare=std::less<Employee *>, _Alloc=std::allocator<Employee *>]" matches the argument list
I have tried to overload the operator < as other people suggested in response to similar questions, but that doesn't seem to solve the issue.
Your set accepts a pointer to an Employee, but you are trying to insert the object itself.
What you can do is
void addSubordinate(Employee& empl){
_subs.insert(&empl); // This will store the address to the object
}
or accept a pointer itself
void addSubordinate(Employee* empl){
_subs.insert(empl);
}
You need to define the < operator in the Employee class. The items in a set are always sorted and since you don't have a comparator it won't let you insert an instance of that class.
Try something like this:
bool operator<(const Employee& emp){
return salary() < emp.salary();
}

C++ - Updating value in pointer gets overridden

I've recently begun learning C++ and I'm having some trouble updating a pointer in my Movie class. I've got a feeling I have an issue somewhere in my Move/Copy constructors but have been trying to solve this issue for hours, swapping pointers to references to values and finally coming here for help.
I have a class Movie, which contains a string name, string rating and int watched member variables. Another class Movies, holds a vector of the movies. On movie, my method increment_watched is supposed to increment the int watched by one, the value does get incremented but it seems like the value is not saved. The display_all_movies method in Movies, which simply displays the movies that it stores holds the old value for watched. I know the issue is probably something really small but I haven't been able to work out why the value isn't being saved.
If someone could explain why the pointer value seems to be getting overridden I'd appreciate it greatly. Thanks in advance!
Code is below, there is some debug couts in there.
Movie.h
#ifndef _MOVIE_H_
#define _MOVIE_H_
#include <string>
#include <iostream>
class Movie {
private:
std::string *name;
std::string *rating;
int *watched;
public:
std::string get_name();
std::string get_rating();
int get_watched();
void increment_watched();
Movie(std::string name, std::string rating, int watched_val); // normal constructor
Movie(const Movie &source); // copy constructor
Movie(Movie &&source); // move constructor
~Movie();
};
#endif // _MOVIE_H_
Movie.cpp
#include "Movie.h"
std::string Movie::get_name() {
return *name;
}
std::string Movie::get_rating() {
return *rating;
}
int Movie::get_watched() {
return *watched;
}
void Movie::increment_watched() {
std::cout << *watched << std::endl;
(*watched)++; // TODO FIX!
std::cout << *watched << std::endl;
}
Movie::Movie(std::string name, std::string rating, int watched_val)
: name{nullptr}, rating{nullptr}, watched{nullptr}{
std::cout << "Creating movie " << watched_val << " with normal constructor" << std::endl;
this->name = new std::string{name};
this->rating = new std::string{rating};
this->watched = new int{watched_val};
}
Movie::Movie(const Movie &source)
: Movie(*source.name, *source.rating, *source.watched) {
std::cout << "Creating movie " << *source.watched << " with copy constructor" << std::endl;
}
Movie::Movie(Movie &&source)
: Movie(*source.name, *source.rating, *source.watched) {
std::cout << "Creating movie " << *source.watched << " with move constructor" << std::endl;
source.name = nullptr;
source.rating = nullptr;
source.watched = nullptr;
}
Movie::~Movie() {
delete name;
delete rating;
delete watched;
}
Movies.h
#ifndef _MOVIES_H_
#define _MOVIES_H_
#include <vector>
#include <string>
#include <iostream>
#include "Movie.h"
class Movies {
private:
static int count;
std::vector<Movie> *movies;
public:
void add_movie(std::string &&name, std::string &&rating, int &&watch);
void increment_movie_count(std::string &&name);
void display_all_movies();
void count_movies();
Movies();
Movies(const Movie &source); // copy constructor
Movies(Movie &&source); // move constructor
~Movies();
};
#endif // _MOVIES_H_
Movies.cpp
#include "Movies.h"
int Movies::count = 0;
void Movies::add_movie(std::string &&name, std::string &&rating, int &&watch) {
bool contains {false};
for(auto movie : *movies) {
if(movie.get_name() == name) {
contains = true;
}
}
if(!contains) {
movies->push_back(Movie{name, rating, watch});
count++;
}
}
void Movies::increment_movie_count(std::string &&name) {
for(auto movie : *movies) {
if(movie.get_name() == name) {
movie.increment_watched();
}
}
}
void Movies::display_all_movies() {
for(auto movie : *movies) {
std::cout << "Title " << movie.get_name() << " Rating " << movie.get_rating() << " Watched " << movie.get_watched() << std::endl;
}
}
void Movies::count_movies() {
std::cout << "There are " << count << " movies " << std::endl;
}
Movies::Movies() {
movies = new std::vector<Movie>{};
}
Movies::~Movies() {
delete movies;
}
And finally main.cpp
#include <iostream>
#include "Movies.h"
using std::cout;
using std::endl;
int main() {
Movies *my_movies;
my_movies = new Movies();
(*my_movies).count_movies();
my_movies->add_movie("Big", "PG-13", 2);
my_movies->increment_movie_count("Big");
my_movies->display_all_movies();
return 0;
}
Changefor(auto movie : *movies) to for(auto& movie : *movies) to update the original movie objects. Otherwise, you're only updating copies of the movie objects.

Is it possible to use same functions for every class

I have multiple classes and each of them has their own methods. All of these methods perform the same task, as you can see in my code. The only unique thing is the values of the title, code and credit members that are defined inside the classes.
Is there a way to write this code such that a single set of methods can do the required tasks (using the specific values within the class that made the request to the method) for each and every class?
I'm a university student, and due to this I don't want to use inheritance since we haven't learned it yet.
class seng305
{
string title = "Software design and architecture", code = "SENG305";
int credit = 4;
public:
seng305();
~seng305();
string get_info();
string get_title();
int get_credit();
};
class comp219
{
string title = "Electronics in computer engineering", code = "COMP219";
int credit = 4;
public:
comp219();
~comp219();
string get_info();
string get_title();
int get_credit();
};
seng305::seng305()
{
cout << '\t' << "Created" << endl;
}
seng305::~seng305()
{
cout << '\t' << "Destroyed" << endl;
}
string seng305::get_info()
{
return (code + "-" + title);
}
string seng305::get_title()
{
return title;
}
int seng305::get_credit()
{
return credit;
}
//--------------------------------------------------
comp219::comp219()
{
cout << '\t' << "Created" << endl;
}
comp219::~comp219()
{
cout << '\t' << "Destroyed" << endl;
}
string comp219::get_info()
{
return (code + "-" + title);
}
string comp219::get_title()
{
return title;
}
int comp219::get_credit()
{
return credit;
}
As you can see, the get_info(), get_title(), and get_credit() methods do the same thing.
I would like for a single get_info(), get_title(), get_credit() to be able to do the task for each class.
There is no reason to use separate classes at all in this example. A single class will suffice, eg:
class course
{
string title, code;
int credit;
public:
course(const string &title, const string &code, int credit);
~course();
string get_info() const;
string get_title() const;
int get_credit() const;
};
course::course(const string &title, const string &code, int credit)
: title(title), code(code), credit(credit)
{
cout << '\t' << "Created" << endl;
}
course::~course()
{
cout << '\t' << "Destroyed" << endl;
}
string course::get_info() const
{
return (code + "-" + title);
}
string course::get_title() const
{
return title;
}
int course::get_credit() const
{
return credit;
}
Then, you simply create instances of your class as needed, eg:
course seng305("Software design and architecture", "SENG305", 4);
course comp219("Electronics in computer engineering", "COMP219", 4);
...
I know you said that you don't want to use inheritance, but that could be the next logical step, using the above code as a base:
class courseSeng305 : public course
{
public:
courseSeng305() : course("Software design and architecture", "SENG305", 4) {}
};
class courseComp219 : public course
{
public:
courseComp219() : course("Electronics in computer engineering", "COMP219", 4) {}
};
courseSeng305 seng305;
courseComp219 comp219;
...

Upcasting with vector in c++

I'm working with my code and I faced this problem. I want to put 3 different classes data in single vector, so I created base class vector. It look like this :
std::vector <Video*> vid_list;
When I read the file I push data in this vector using one of the derived class constructors like that :
vid_list.push_back(new Official_Music_Video(video_title, video_time,
Date(y,m,d), num_of_views));
so I want to display this data on the screen, but my base class only got methods for
std::string title;
double time;
Date date_of_release;
but not for int number_of_views. I heard that if I wanna use derived class getter method I have to use upcasting so I tried to make this
void views (Video& v) {
v.get_views();
}
and then in my display method
void Official_Music_Video::display_info(std::vector <Video*>& vid_list){
Official_Music_Video ofc;
for (unsigned int i = 0; i < vid_list.size(); i++){
cout << vid_list[i]->get_title() << " " << vid_list[i]->get_time()
<< " " << vid_list[i]->write_year_to_file() << "-" <<
vid_list[i]->write_month_to_file() << "-" << vid_list[i]-
>write_day_to_file () << endl;
cout << "This video viewed " << vid_list[i].views(ofc) << " times"
<< endl;
}
}
But it's not working. Can you help me understand where I made mistake and what's wrong ?
If all three of your derived classes have a "number_of_views" method, put it in the base class as well, and problem solved. If not, then your code is nonsensical. What do you expect to happen when you put an "Unofficial_Music_Video" into the vector, and run your loop over it?
If you really need to add per-type behavior to the class, consider what you actually want to accomplish. Do you need users of Video to be able to query "number_of_views", despite the fact that field doesn't exist for all subtypes? Maybe you just want to access a human-readable description of the statistics? If that's the case, it might make the most sense to add a "virtual std::string StatsSummary()" method to Video, and make subclasses implement it as required.
You might want to move some of the implementation to the base class or so, but this is something that could help you finding the solution:
#include <vector>
#include <string>
#include <iostream>
class Date // for demo only
{
public:
Date(int y, int, int m, int d)
: y(y) , m(m), d(d) {}
int y;
int m;
int d;
};
class Video
{
public:
virtual std::string get_title() = 0;
virtual int get_time() = 0;
virtual int write_year_to_file() = 0;
virtual int write_month_to_file() = 0;
virtual int write_day_to_file () = 0;
virtual ~Video(){}
virtual void display_info()
{
std::cout << get_title()
<< " " << get_time()
<< " " << write_year_to_file()
<< "-" << write_month_to_file()
<< "-" << write_day_to_file ()
<< std::endl;
}
};
class VideoWithViewCount
: public Video
{
public:
virtual int views() = 0;
virtual void display_info()
{
Video::display_info();
std::cout << "This video viewed " << views() << " times" << std::endl;
}
};
class Official_Music_Video : public VideoWithViewCount
{
public:
Official_Music_Video(std::string _video_title, int _video_time, Date _date, int _Num_of_views)
: d(_date)
, time(_video_time)
, Num_of_views(_Num_of_views)
, video_title(_video_title)
{}
virtual int get_time() override {return time; };
virtual int write_year_to_file() override { return d.y; } // better call them get...
virtual int write_month_to_file() override {return d.m; }
virtual int write_day_to_file () override { return d.d; }
virtual int views() override {return Num_of_views; };
private:
Date d;
int time;
int Num_of_views;
std::string video_title;
};
class Other_Video : public Video
{
public:
Other_Video(std::string _video_title, int _video_time, Date _date)
: d(_date)
, time(_video_time)
, video_title(_video_title)
{}
virtual int get_time() override {return time; };
virtual int write_year_to_file() override { return d.y; }
virtual int write_month_to_file() override {return d.m; }
virtual int write_day_to_file () override { return d.d; }
private:
Date d;
int time;
std::string video_title;
};
int main(int,char**)
{
std::vector <Video*> vid_list;
// could also use unique_ptr or shared_ptr from #include <memory> in vector as follows:
// std::vector <unique_ptr<Video> > vid_list;
// std::vector <shared_ptr<Video> > vid_list;
// fill video vector
// vid_list.push_back(new Official_Music_Video(video_title, video_time, Date(y,m,d), num_of_views));
for (auto v : vid_list) // when using unique_ptr remember to use "const auto&" instead of "auto"
{
v->display_info();
}
return 0;
}

Pointers to class fields

My task is as follows :
Using pointers to class fields, create menu allowing selection of ice, that Person can buy in Ice shop. Buyer will be charged with waffel and ice costs.
Selection of ice and charging buyers account must be shown in program.
Here's my Person class :
#include <iostream>
using namespace std;
class Iceshop {
const double waffel_price = 1;
public:
}
class Person {
static int NUMBER;
char* name;
int age;
const int number;
double plus, minus;
public:
class Account {
int number;
double resources;
public:
Account(int number, double resources)
: number(number), resources(resources)
{}
}
Person(const char* n, int age)
: name(strcpy(new char[strlen(n)+1],n)),
number(++NUMBER), plus(0), minus(0), age(age)
{}
Person::~Person(){
cout << "Destroying resources" << endl;
delete [] name;
}
friend void show(Person &p);
int* take_age(){
return &age;
}
char* take_name(){
return name;
}
void init(char* n, int a) {
name = n;
age = a;
}
Person& remittance(double d) { plus += d; return *this; }
Person& paycheck(double d) { minus += d; return *this; }
Account* getAccount();
};
int Person::
Person::Account* Person::getAccount() {
return new Account(number, plus - minus);
}
void Person::Account::remittance(double d){
resources = resources + d;
}
void Person::Account::paycheck(double d){
resources = resources - d;
}
void show(Person *p){
cout << "Name: " << p->take_name() << "," << "age: " << p->take_age() << endl;
}
int main(void) {
Person *p = new Person;
p->init("Mary", 25);
show(p);
p->remittance(100);
system("PAUSE");
return 0;
}
How to change this into using pointers to fields ?
class Iceshop {
const double waffel_price;
int menu_options;
double[] menu_prices;
char* menu_names;
char* name;
public:
IceShop(char*c)
: name(strcpy(new char[strlen(n)+1],n)),
waffel_price(1), menu(0)
{}
void init(int[] n){
menu_options = n;
}
void showMenu(Iceshop &i){
int list;
list = &i
char* sorts = i->menu_names;
int count=0;
while(count < list){
cout << count+1 << ")" << sorts[count] << endl;
++count;
}
}
void createMenu(Iceshop *i){
for(int j=0; j <(i->menu_options), ++j){
cout << "Ice name: ";
cin >> i->menu_names[j];
endl;
cout << "Ice cost: "
cin >> i->menu_prices[j];
endl;
}
}
void chargeClient(Person *p, Iceshop* i, int sel){
p->remittance( (i->menu_prices[sel])+(i->waffel_price) );
}
};
You could try to build a menu driven UI.
Something like this (copy paste from a forum, for more examples search for 'C++ console' menu' or something like it on google.
int choice = 0;
while (choice != 4)
{
cout <<"Enter choice:"<< endl <<
"1) ice 1" << endl <<
"2) ice 2" << endl<<
"3) ice 3" << endl <<
"4) exit" << endl;
cin >> choice;
switch(choice)
{
case 1:
//show menu to buy or cancel
break;
case 2:
//show menu to buy or cancel
break;
}
//etc
}
Here is what I would do. Note that it's not exactly what you're looking for and, well, abstract situation modelling is always tough :)
But I hope this code would make you understand what you have to do.
Also, I am not exactly sure about using pointers to class fields, because this tends to be a situation where pointer usage is superflous.
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
// Some abstract type used to measure prices
typedef size_t money_t;
struct Item {
// Item's name and price
std::string name;
money_t price;
// Could also have something that makes
// it an item, but this is not necessary
// This could be anything, because we're actually
// modelling an abstract situation
// (...)
// Note that we don't allow unnamed items
Item(const std::string& name, const money_t& price = 0) : name(name), price(price) { }
// Note here that items are treated as 'same' only by names
// This means we're actually talking about 'logical groups' of items
bool operator==(const Item& item) const { return name == item.name; }
bool operator==(const std::string& item_name) const { return name == item_name; }
};
class Store {
private:
// Store's item storage
// Note that items actually represent infinite groups
// of items (in our case store is an abstract store
// which items simply can't end)
std::vector<Item> items;
public:
// Initialize a store that doesn't sell anything
Store() { }
// Initialize a store that could sell specified types of items
Store(const std::vector<Item>& items) : items(items) { }
// Show what we actually sell in this store
void EnumerateItems() const {
for (size_t i = 0; i < items.size(); ++i)
std::cout << items[i].name << " : " << items[i].price << "\n";
}
Item Sell(const std::string& name) const {
// Find appropriate item in the item list
std::vector<Item>::const_iterator what = std::find(items.begin(), items.end(), name);
// If nothing found, throw an exception
if (what == items.end()) {
throw std::domain_error("Store doesn't sell this type of item");
}
// Return item as a sold one
return (*what);
}
};
class Person {
private:
// Person's name (identity)
std::string name;
// Item's that are currently possesed
// by this person
std::vector<Item> owned_items;
// Amount of cash that this person has
money_t cash;
public:
// Note that we don't allow unnamed persons
Person(const std::string& name, const money_t& cash = 0) : name(name), cash(cash) { }
void Buy(const Item& what) {
owned_items.push_back(what);
cash -= what.price;
}
};
void GoShopping(Person& person, const Store& store) {
// Let's simulate buying one item
// You could easily make a loop and determine what to buy in
// every loop iteration
store.EnumerateItems();
person.Buy(store.Sell("Shoes"));
}
int main() {
// Initialize our store that sells only shoes
std::vector<Item> items;
items.push_back(Item("Shoes", 25));
Store grocery(items);
// Initialize our person
Person jim_carrey("Jim Carrey", 500);
// The yummy part
GoShopping(jim_carrey, grocery);
return 0;
}