Libra
Libra

Reputation: 2595

Overriden virtual method not being called

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

Answers (1)

jtbandes
jtbandes

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

Related Questions