msk
msk

Reputation: 139

Polymorphism without pointers

I was trying to create an abstract class and use it to determine the paying method of a purchase, using polymorphism. I tried some different things, but I can't still get it to work as I wanted. Here is the code:

class PaymentMethod {
    public:
        PaymentMethod() {}
        virtual std::string getPaymentMethod() = 0;
};

class PayWithMoney : public PaymentMethod {
    public:
        PayWithMoney() {}
        virtual std::string getPaymentMethod() {
            std::string paymentMethod = "Payed with Money"; 
            return paymentMethod;
        }
};

class PayWithDebitCard : public PaymentMethod {
    public:
        PayWithDebitCard() {}
        virtual std::string getPaymentMethod() {
            std::string paymentMethod = "Payed with Debit Card"; 
            return paymentMethod;
        }
};

And I have another class:

class Purchase {
    private:
        something
        PaymentMethod _paymentMethod;
    public:
        Purchase(something, const PaymentMethod& paymentMethod)

But I keep getting compiler error saying cannot declare field ‘Purchase::_paymentMethod’ to be of abstract type ‘PaymentMethod’.

I'm guessing I will have to use pointers instead right?

I thought I should try to avoid new and delete unless working with long-lived objects, but since PaymentMethod is an abstract class, I can't use it as a class member... Am I wrong?

Upvotes: 1

Views: 546

Answers (2)

Kerrek SB
Kerrek SB

Reputation: 476990

You should try to avoid new and delete, that's absolutely correct.

Here's how:

#include <memory>       // for std::unique_ptr
#include <utility>      // for std::move

class Purchase
{
    Purchase(std::unique_ptr<PaymentMethod> payment_method)
    : payment_method_(std::move(payment_method))
    { }

    std::unique_ptr<PaymentMethod> payment_method_;

public:
    static Purchase MakeDebitCardPurchase()
    {
        return Purchase(std::make_unique<PayWithDebitCard>());
    }

    static Purchase MakeCashPurchase()
    {
        return Purchase(std::make_unique<PayWithCash>());
    }
};

Usage:

auto purchase = Purchase::MakeCashPurchase();

Note that std::make_unique doesn't exist yet, so you may instead have to say:

return Purchase(std::unique_ptr<PaymentMethod>(new PayWithCash));

This is the only time you have to say new, and even that will go away once std::make_unique is available in the standard library.

As an added benefit of this design, you can now easily add testing code, such as mock payment methods.

Upvotes: 5

egur
egur

Reputation: 7960

Just remove PaymentMethod _paymentMethod from the purchase class, your Purchase function receives it anyway.

Another thing, since you pass a const reference to Purchase, all the functions that Purchase calls must be const:

virtual std::string getPaymentMethod() = 0;

-->

virtual std::string getPaymentMethod() const = 0;

Upvotes: 0

Related Questions