Search code examples
c++pointerspolymorphism

Problem accessing object attributes from a pointer class attribute


I have the following class:

class Customer {

private:
    string name;
    savingAccount *savingsAccount = nullptr;
public:
   void setSavingsAccount(savingAccount savingsAccount);
   savingAccount* getSavingsAccount();

And methods:

savingAccount* Customer::getSavingsAccount()
{
    return this->savingsAccount;
}

void Customer::setSavingsAccount(savingAccount savingsAccount)
{
    this->savingsAccount = &savingsAccount;
}

savingsAccount class is derived from account struct:

struct account {
private:
    double balance;
    double interestRate;
    double interest;
    const string accountType = "Base Account";

public:
    account();
    double getBalance();
    double getIntRate();
    double calculateInterest(int n);
    void setBalance(double balance);
    void setIntRate(double rate);
    string getType();

};

class savingAccount : public account {
public:
    double savingDepositArr[5];
    const string accountType = "Saving Account";

Now the problem: I am creating SavingsAccount and Customer objects.

savingAccount newSavingAccount;
Customer customer;
customer.setSavingsAccount(newSavingAccount);

When I try to access anything through getSavingsAccount I can't.

customer.getSavingsAccount.getBalance()
customer.getSavingsAccount().getBalance()

or

customer.getSavingsAccount.accountType

I am 100% sure I am not using the pointer the right way. I have been looking for a solution for a long time, however still nothing. If I remove the pointers and just have the object as an attribute, it works but this is not the solution I am looking for. I just want to know what I am doing wrong.


Solution

  • Customer::getSavingsAccount() returns a pointer to a savingAccount object. To access members of that object, you need to dereference the pointer using the * operator, and then access the members using the . operator. Or, you can use the shorter -> operator:

    (*customer.getSavingsAccount()).getBalance()
    customer.getSavingsAccount()->getBalance()
    

    That being said, be aware that Customer::setSavingsAccount() takes in a savingAccount object by value, so a copy of the input object is passed in. setSavingsAccount() saves a pointer to that copy. When setSavingsAccount() exits, the copy gets destroyed, leaving the pointer dangling pointing at invalid memory. Thus, anything you try to do afterwards that involves dereferencing that pointer will cause undefined behavior.

    For what you are attempting to do, make setSavingsAccount() take the savingAccount object by reference instead, eg:

    class Customer {
    private:
        ...
        savingAccount *savingsAccount = nullptr;
    public:
       void setSavingsAccount(savingAccount &savingsAccount);
       ...
    };
    
    void Customer::setSavingsAccount(savingAccount &savingsAccount)
    {
        this->savingsAccount = &savingsAccount;
    }
    

    Just make sure the input savingAccount object outlives the Customer object, or else you will still end up with a dangling pointer.

    An alternative solution would be to use std::unique_ptr or std::shared_ptr instead, eg:

    #include <memory>
    
    class Customer {
    private:
        ...
        std::unique_ptr<savingAccount> savingsAccount;
    public:
       void setSavingsAccount(std::unique_ptr<savingAccount> savingsAccount);
       savingAccount* getSavingsAccount();
    };
    
    savingAccount* Customer::getSavingsAccount()
    {
        return this->savingsAccount.get();
    }
    
    void Customer::setSavingsAccount(std::unique_ptr<savingAccount> savingsAccount)
    {
        this->savingsAccount = std::move(savingsAccount);
    }
    
    auto newSavingAccount = std::make_unique<savingAccount>();
    Customer customer;
    customer.setSavingsAccount(std::move(newSavingAccount));
    ...
    customer.getSavingsAccount()->getBalance();
    customer.getSavingsAccount()->accountType;
    

    Or:

    #include <memory>
    
    class Customer {
    private:
        ...
        std::shared_ptr<savingAccount> savingsAccount;
    public:
       void setSavingsAccount(std::shared_ptr<savingAccount> savingsAccount);
       std::shared_ptr<savingAccount> getSavingsAccount();
    };
    
    std:shared_ptr<savingAccount> Customer::getSavingsAccount()
    {
        return this->savingsAccount;
    }
    
    void Customer::setSavingsAccount(std::shared_ptr<savingAccount> savingsAccount)
    {
        this->savingsAccount = savingsAccount;
    }
    
    auto newSavingAccount = std::make_shared<savingAccount>();
    Customer customer;
    customer.setSavingsAccount(newSavingAccount);
    ...
    customer.getSavingsAccount()->getBalance();
    customer.getSavingsAccount()->accountType;