1

I have this Book class objects (base class: Product)

Book books[5] = {
    Book("Kucuk Prens","FR","Roman","Book",10,15,103061,12,"Kultur yayinlari",10),
    Book("Kucuk Prens1","FR","Roman","Book",10,15,103061,12,"Kultur yayinlari",10),
    Book("Kucuk Prens2","FR","Roman","Book",10,15,103061,12,"Kultur yayinlari",10),
    Book("Kucuk Prens3","FR","Roman","Book",10,15,103061,12,"Kultur yayinlari",10),
    Book("Kucuk Prens4","FR","Roman","Book",10,15,103061,12,"Kultur yayinlari",10)};

And I have a Cart class.

class Cart
{

private:

    int totalPrice;
    Product productList[5]; // kullanıcın seçtiği


public:


};

For instance, I want to add books[1] to productList[]. How can I?

Anton Menshov
  • 2,266
  • 14
  • 34
  • 55
  • C-way: use a pointer Product* productList and allocate it dynamically either with new or malloc(). If you want to resize, use realloc(). C++-way: use STL's vector. – A.B. Dec 16 '22 at 16:47
  • 1
    Welcome to C++! Do learn about `std::vector` at the *absolute* earliest opportunity. – tadman Dec 16 '22 at 16:47
  • 1
    wont work like this: https://stackoverflow.com/questions/274626/what-is-object-slicing. `productList` can only contain `Product`s – 463035818_is_not_an_ai Dec 16 '22 at 16:47
  • 2
    @A.B. thats a rather misleading suggestion. `malloc` is wrong. Not clear why you suggest dynamic allocation via `new` or `malloc` anyhow. – 463035818_is_not_an_ai Dec 16 '22 at 16:48
  • Use a `std::vector>` and derive `Book` from `Product`. – πάντα ῥεῖ Dec 16 '22 at 16:55
  • You will want to use [std::vector](https://en.cppreference.com/w/cpp/container/vector) for this rather than a fixed length primitive array. Then look at the push_back or emplace_back methods of std::vector. However, unless you are only dealing with Books, you want a collection of polymorphic objects ( instances of different derived classes), so it gets more involved. You will actually need a vector not of objects, but of (smart) pointers to objects. You might want to start with only handling Books to get practice in one new thing at a time. – Avi Berger Dec 16 '22 at 16:58
  • @463035818_is_not_a_number Book subclass of prodcut – Mablungware Dec 16 '22 at 17:05
  • @Mablungware it's not possible to modify raw c-style arrays of fixed or unknown length. Use `std::vector` as mentioned, or ask for a plain c style solution, if you're restricted to use c-style arrays. – πάντα ῥεῖ Dec 16 '22 at 17:07

1 Answers1

1

First off, you are writing C++, this means you are lucky enough to not have to utilize C arrays/malloc'd pointers, prefer STL containers instead, since they manage the memory for you!

That said, if you want to put derived classes in a base class container, you are going to have to store pointers to that base class, once again, best to use modern C++ and use smart pointers instead, since they are self-managing and will save you the headache of free'ing them:


#include <memory> //smart pointers
#include <vector> //vector, STL container for a dynamically resizable array
#include <string> //string, pretty self explanatory
#include <algorithm> //algorithm, for powerful utility algorithms

class Cart
{

private:

    int totalPrice;
// A vector of smart pointers to our base class
    std::vector<std::unique_ptr<Product>> productList;


public:

    Cart() = default;

    void addProduct(std::unique_ptr<Product>&& product)
    {
// we put our product in the cart using [Move Semantics][1], transferring ownership 
// of the pointer to the cart.
        productList.push_back(std::move(product));
    }

    void removeProduct(std::string_view product_name)
    {
//we use a combination of std::find_if, from the algorithm header, together with a 
//lambda, to remove a product by its name (similar functions can be written using
//different attributes as keys
        auto const& to_remove = std::find_if(productList.begin(), productList.end(), 
        [
            &product_name
        ](auto const& product)
        {
            return product->getName() == product_name;
        }
        );

//if we have found our product, we remove it...
        if (to_remove != productList.end())
        {
            productList.erase(to_remove);
        }
    }


    // return a const reference to the productList, this way we can iterate 
    // over the lists from outside the class without modifying it.
    std::vector<std::unique_ptr<Product>> const& getProductList() const
    {
        return productList;
    }

    // add other methods, like getTotalPrice() etc...
};

At first, the solution might seem a bit overwhelming since it's so different from C, but once you familiarize yourself with the STL and these more advanced constructs (such as lambdas) you will be writing safer code, faster.

from here, an example of usage of this class can be:

#include <iostream>

int main()  
{
    Cart cart;

    cart.addProduct(std::make_unique<Product>(10, "Apple"));
    cart.addProduct(std::make_unique<Product>(20, "Banana"));
    cart.addProduct(std::make_unique<Product>(30, "Orange"));

    cart.removeProduct("Banana");
//modern range based for loop on the returned const reference
    for(auto const& product : cart.getProductList())
    {
        std::cout << product->getName() << " " << product->getPrice() << std::endl;
    }
    return 0;
}
Neervana
  • 318
  • 1
  • 10
  • 1
    The `unique_ptr` should be taken with a grain of salt here. It's not clear from the OP's question if `Product` instances need to exist only in distinct shopping carts, or all carts can share from those instances. – πάντα ῥεῖ Dec 16 '22 at 17:14
  • 1
    Certainly if the there are multiple ```Cart```s that pick ```Product```s from an inventory, it could benefit from using ```std::shared_ptr``` instead, from OP's question the use-case is unclear so I defaulted to the ```*_ptr``` with less overhead. – Neervana Dec 16 '22 at 17:25
  • Better let the OP clarify 1st, before investing time in writing answers. If they clarify, there are loads of duplicates available here for the real underlying problems. – πάντα ῥεῖ Dec 16 '22 at 17:44