Reputation: 2595
In the below code, I am trying to override the price()
function for both Taxed and Untaxed, however, they both call the parent virtual function instead of the overriden one that was given to them. What did I mess up?
Header file:
#ifndef PRODUCT_H
#define PRODUCT_H
#include <string>
#include <iostream>
class Product {
protected:
int _quantity;
double _cost;
std::string _name;
public:
Product(std::string name, double cost);
virtual ~Product();
void set_quantity(int quantity);
virtual double price() const;
friend std::ostream & operator<< (std::ostream &ost, const Product &product);
};
std::ostream & operator<< (std::ostream &ost, const Product &product);
class Taxed : public Product{
private:
static double _tax;
public:
using Product::Product;
virtual ~Taxed();
static void set_tax_rate(double sales_tax);
double price() const override;
};
class Taxfree : public Product{
public:
using Product::Product;
virtual ~Taxfree();
double price() const override;
};
#endif //PRODUCT_H
.cpp file:
#include <string>
#include <iomanip>
#include <iostream>
#include "product.h"
Product::Product(std::string name, double cost){
_name = name;
_cost = cost;
_quantity = NULL;
};
Product::~Product(){};
void Product::set_quantity(int quantity){
if (quantity < 0){
std::cerr << "Cannot have negative quantity";
}
_quantity = quantity;
};
double Product::price() const {
return 2;
};
std::ostream & operator<< (std::ostream &ost, const Product &product){
if (product._quantity > 0)
ost << product._name << " (" << product._quantity << " @ " << std::fixed << std::setprecision(2) << std::setfill('0') << product.price() << ")";
else
ost << product._name << " (" << std::fixed << std::setprecision(2) << std::setfill('0') << product.price() << ")";
return ost;
};
double Taxed::_tax = 0.0825;
Taxed::~Taxed(){};
void Taxed::set_tax_rate(double sales_tax) {
Taxed::_tax = sales_tax;
};
double Taxed::price() const{
return _quantity * _cost * (1+_tax);
}
Taxfree::~Taxfree(){};
double Taxfree::price() const{
return _quantity * _cost;
}
Upvotes: 3
Views: 115
Reputation: 118681
You are experiencing object slicing. By storing a std::vector<Product>
, you are actually creating instances of the base Product class and losing your instances of Taxed and Taxfree. In products.push_back(Taxfree("Apple", 2))
, the Taxfree is passed to the compiler-generated copy constructor Product(const Product&)
, because a Taxfree
object can bind to a const Product&
.
Had you removed the base implementation of price()
and made it a pure virtual function with virtual double price() const = 0;
, you would have noticed this problem when your program failed to compile (because Product would become an abstract class and constructing it would no longer be possible).
Instead, you will need to use something like std::vector<std::shared_ptr<Product>>
:
std::vector<std::shared_ptr<Product>> products;
products.push_back(std::make_shared<Taxfree>("Apple", 2));
products.push_back(std::make_shared<Taxed>("Iron",1.75));
products.push_back(std::make_shared<Taxfree>("Soda",2.5));
products.push_back(std::make_shared<Taxfree>("Lemon",2.5));
(I'd suggest unique_ptr
instead, but it looks like you want the products
and cart
to contain the same object. Or, you could use unique_ptr
and just create copies of the products, which is probably better if you plan to mutate them.)
Upvotes: 9