1

I have a Person class which has a vector of Accounts. The account class is an abstract class and has a class type CurrentAccount. I have a method which will print out a Person account details called 'printAllAccounts'. But I see to be getting an error where it says 'accounts' and it says 'expression must have a class type'. Here is the person header class: Person.h

    #include "pch.h"
#include "Account.h"


using namespace std;

class Person {
public:
    Person(string);
    void addAccount(Account &);
    bool closeAccount(int *);
    void printAllAccounts();
    bool creditMoney(int *, double *);
    bool debitMoney(int *, double *);
    virtual ~Person();
private:
    const string name;
    vector<Account> accounts;
};

Here is the method for for Person.cpp:

void Person::printAllAccounts()
{
    if (accounts.size() > 0) {
        for (int i = 0; i < accounts.size(); i++)
        {
               //below line of accounts is where error is happening
            cout << **accounts**.at(i).printDetails().c_str() << endl;
        }
    }
    else {
        cout << "Person : " << name << " has no accounts" << endl;
    }

}

[Edit] Here is print details in the Account Class:

Actually there is an error on return toRet; Account.cpp file

void Account::printDetails() const
{
    ostringstream conAcc, conBal;
    conAcc << this->accountNo;
    string toRet;
    toRet += "Account No: ";
    toRet += conAcc.str();
    toRet += " Balance : ";
    conBal << this->balance;
    toRet += conBal.str();
    return toRet;
}

Here is the Account.h header file(abstract class)

#include "pch.h"

using namespace std;

class Account {
public:
    Account(int *, double *);
    virtual ~Account();
    bool debit(double *);
    bool credit(double *);
    int getAccNo();

    //making it abstract
    virtual double getBalance() const = 0;
    virtual void printDetails() const;
private:
    double balance;
    int accountNo;
};
  • 2
    What is `printDetails()`, and does it return a `std::string`? – Bathsheba Nov 15 '19 at 10:29
  • From the name, it sounds like `printDetails` prints the details rather than returns a string containing the details. (You might be confusing "output" as in "printing to the console" with "output" as in "returning a value from a function".) – molbdnilo Nov 15 '19 at 10:30
  • 1
    First, include the `Accounts.h` header in your post; it's relevant. If it is as you say it is, *"The account class is an abstract class"*, then you shouldn't have a concrete vector of those anyway, as [you're going to slice](https://stackoverflow.com/questions/274626/what-is-object-slicing?r=SearchResults&s=1|359.4793). Second, break that line into *at least* two statements to isolate the *real* error. And just fyi, `using namespace std;` = *horrible* thing to put anywhere, *especially* a header file. – WhozCraig Nov 15 '19 at 10:32
  • Can you show the declaration of `Account` class? Or at least `printDetails()` method declaration? – Yuri Kovalenko Nov 15 '19 at 10:35
  • I include Account.cpp and Account.h files –  Nov 15 '19 at 10:39
  • 2
    With your update, that's all kinds of broken. `Account::printDetails` returns `void`, so attempting to reference `c_str()` as a member function is obviously not going to work. That said, I said it earlier and I'll say it again, A vector of concrete `Account` objects **won't work**. See [What is object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing?r=SearchResults&s=1|359.4793) for why. – WhozCraig Nov 15 '19 at 10:39
  • Does your Account.cpp compile? You are trying to return an `std::string` from function returning `void` – Yuri Kovalenko Nov 15 '19 at 10:40
  • @WhozCraig, before slicing you'll get a [compile error](https://godbolt.org/z/aq6fJ-). – Evg Nov 15 '19 at 10:57

1 Answers1

2

std::vector<Account> will internally create an array of Account and thus cannot store derived classes like CurrentAccount. Even if you add a CurrentAccount object, the vector will create a copy of type Account and store that. And if Account is abstract, you won't be able to store anything at all, since an abstract class cannot be instantiated. (You might want to look up object slicing to read more about what's going on.)

To fix this, you can use std::vector<std::unique_ptr<Account>>. That way your vector holds pointers of type Account*, which can point to derived classes like CurrentAccount.

Max Vollmer
  • 8,412
  • 9
  • 28
  • 43
  • You won't be able to store `Account`, because it's an abstract class. You'll get a [compile error](https://godbolt.org/z/aq6fJ-) before slicing could happen. – Evg Nov 15 '19 at 10:45