2017-09-08 39 views
-2

這是作業相關的,所以我必須使用向量來存儲這些對象。 我有一個基類的BankAccount與衍生的CheckingAccount和SavingsAccountC++在向量中查找對象並調用其上的成員函數

請問佔他們要爲輸入數據,即支票或儲蓄然後索要平衡和利率/交易費的用戶。然後,使用switch語句,使用這些輸入初始化對象,並使用智能指針將其添加到向量vector<shared_ptr<BankAccount>>account_list

接着,請問用戶通過加入成員函數creditdebit的交易(從基類中重寫,以考慮在檢查或儲蓄利率交易費用)來接一個帳戶類型進行交互。

我的問題在於:根據用戶的路線,任一帳戶都會按照用戶選擇的順序添加,所以我不知道對象在矢量中的位置。

帳戶被加入,(在一個開關的情況):

cout << "\nEnter a unique name for this savings account: \t"; 
cin >> name_input; 
cout << "\nEnter your initial balance: \t" << endl; 
cin >> balanceInput; 
cout << "\nEnter your interest rate: \t" << endl; 
cin >> interestRate_input; 
account_list.push_back(new SavingsAccount(balanceInput,name_input,interestRate_input)); //create savings account object 
cout << "\nAccount created successfully" << endl; 

如何可以先找到,在兩個物體的矢量的類型的CheckingAccount或鍵入SavingsAccount,然後知道元件的位置,呼叫它的適當的成員函數?

這是我到目前爲止,所以請原諒任何凌亂的代碼,我正在試驗,並試圖找出結果。例如:

cout << "\nEnter the amount to debit: \t" << endl; 
cin >> amount; 

//this might work but I don't know if this is where the relevant account resides 
account_list[0]->debit(amount); 

//here I don't know how to use the element once it is found to call a function on it 
vector<shared_ptr<BankAccount>>::iterator 
itElem = find_if(account_list.begin(), account_list.end(), HasIdentifier(account_choice)); 
account_list.itElem -> debit(amount); 
//the line above this doesn't work 

在基類中,我創建了一個string accountName,因此每個帳戶都有唯一的ID。

以下是爲find_if創建的HasIdentifier類,用於通過帳戶名稱進行搜索。

class HasIdentifier:public unary_function<BankAccount, bool> 
{ 
public: 
    HasIdentifier(string id) : m_id(id) { } 
    bool operator()(const BankAccount& c)const 
    { 
     return (c.getName() == m_id); 
    } 
private: 
    string m_id; 
}; 

這是以下的整個程序。我仍然得到這些錯誤:

error: no matching function for call to object of type 'HasIdentifier' 
    if (__pred(*__first)) 
     ^~~~~~ 
.../WA4_2/main.cpp:230:19: note: in instantiation of function template specialization 'std::__1::find_if<std::__1::__wrap_iter<std::__1::shared_ptr<BankAccount> *>, HasIdentifier>' requested here 
          itElem = std::find_if(account_list.begin(), account_list.end(), HasIdentifier(account_choice)); 
             ^
.../WA4_2/main.cpp:169:8: note: candidate function not viable: no known conversion from 'std::__1::shared_ptr<BankAccount>' to 'const BankAccount' for 1st argument 
      bool operator()(const BankAccount& c)const 

我真的不知道該怎麼做。如果HasIdentifier不起作用,則意味着要在矢量中搜索任何對象的標識符。

#include <iostream> 
#include <vector> 
#include <algorithm> 


// class for bank account 
class BankAccount {   //balance as double protected member so child classes can access 
protected: 
    double balance = 0; 
    std::string account_name = "???"; 
public: 
    BankAccount() {}; 

    ~BankAccount() {}; 

    BankAccount(double userBalance, std::string name) { 
     if (userBalance >= 0) {       // constructor to receive initial balance and use it to initialize the balance 
      balance = userBalance; 
     } else { 
      balance = 0;        //verify balance is greater than or equal to 0, else display error and set balance to 0 
      std::cout << "\nError, balance set to 0\n"; 
     } 
     account_name=name; 
    } 

    const std::string &getAccount_name() const { 
     return account_name; 
    } 

    void setAccount_name(const std::string &account_name) { 
     BankAccount::account_name = account_name; 
    }; 

    virtual void 
    credit(double amount) {       // Member function credit should add an amount to the current balance. 
     balance += amount; 
    } 

    virtual void 
    debit(double amount) {        // Member function debit should withdraw money from the Bank-Account and ensure that the debit amount does not exceed 
     if (amount > 
      balance) {        // the Bank-Account’s balance. If it does, the balance should be left unchanged and the function should print the message 
      std::cout << "The balance is less than the debit amount.\n";  // 「The balance is less than the debit amount.」 
     } else { 
      balance -= amount; 
     } 
    } 

    virtual double getBalance() {      // Member function getBalance should return the current balance. 
     return balance; 
    }; 
    std::string getName()const { 
     return this->account_name; 
    } 

    bool operator ==(const BankAccount& compare) const{ 
     return this->account_name == compare.account_name; 
    } 
}; 


class SavingsAccount : public BankAccount {    // inherit bank account class to create savings account 
    double interestRate = 0; 

public:             // constructor to get initial balance and interest rate 
    SavingsAccount(double userBalance, const std::string &name, double user_rate) : BankAccount(userBalance, name), 
                        interestRate(user_rate) { 
     interestRate = user_rate; 
    } 

    double 
    calculateInterest() {    // calculateInterest that returns a double indicating the amount of interest earned by an account 
     double earnings = 0;   // this amount is calc by multiplying the interest rate by the bank account balance 
     double a = 0; 
     a = getBalance(); 
     earnings = a * interestRate; 
     return earnings; 
    } 
    void credit(double amount) { 
     balance += amount + 
       calculateInterest();       // Member function credit should add an amount to the current balance. 
    } 
}; 

class CheckingAccount : public BankAccount { 
    double transactionFee; 
public: 
    CheckingAccount(double userBalance, const std::string &name, double transfee_input) : BankAccount(userBalance, name), 
                        transactionFee(
                          transfee_input) { 
     transactionFee=transfee_input; 
    } 

    void credit(double amount) { 
     balance += amount + transactionFee; // Member function credit should add an amount to the current balance. 
    } 

    void debit(double amount) {           // Member function debit should withdraw money from the Bank-Account and ensure that the debit amount does not exceed 
     if (amount > 
      getBalance()) {         // the Bank-Account’s balance. If it does, the balance should be left unchanged and the function should print the message 
      std::cout << "The balance is less than the debit amount.\n";  // 「The balance is less than the debit amount.」 
     } else { 
      balance -= amount + transactionFee; 
     } 
    } 
}; 



class HasIdentifier:public std::unary_function<BankAccount, bool> 
{ 
public: 
    HasIdentifier(std::string id) : m_id(id) { } 
    bool operator()(const BankAccount& c)const 
    { 
     return (c.getName() == m_id); 
    } 
private: 
    std::string m_id; 
}; 

int main() { 
    double balanceInput{0};      //variables for getting balance/interest inputs/outputs 
    double balanceOutput{0}; 
    double interestRate_input{0}; 
    double fee_input{0}; 
    std::string name_input = "???"; 

    std::vector<std::shared_ptr<BankAccount>>account_list;  //storage for accounts 


     std::cout << "\nWhat type of account would you like to input? " 
        << "\nSavings (1)" 
        << "\nChecking (2)" 
        << "\nEnter your choice:\t" 
        << std::endl; 
     int choice{0}; 
     std::cin >> choice; 
     switch(choice) { 
      case 1: {              //savings input 
       std::cout << "\nEnter a unique name for this savings account: \t"; 
       std::cin >> name_input; 
       std::cout << "\nEnter your initial balance: \t" << std::endl; 
       std::cin >> balanceInput; 
       std::cout << "\nEnter your interest rate: \t" << std::endl; 
       std::cin >> interestRate_input; 
       account_list.emplace_back(new SavingsAccount(balanceInput, name_input, 
                  interestRate_input)); //create savings account object 
       std::cout << "\nAccount created successfully" << std::endl; 
       break; 
      } 
      case 2: { 
       std::cout << "\nEnter a unique name for this checking account: \t"; 
       std::cin >> name_input; 
       std::cout << "\nEnter your initial balance: \t" << std::endl;    //checking account input 
       std::cin >> balanceInput; 
       std::cout << "\nEnter the transaction fee: \t" << std::endl; 
       std::cin >> fee_input; 
       account_list.emplace_back(new CheckingAccount(balanceInput, name_input,fee_input)); //create checking account object 
       std::cout << "\nAccount created successfully" << std::endl; 
       break; 
      } 
      default: { 
       std::cout << "\nInvalid entry" << std::endl; 
       break; 
      } 
     } 


    std::cout << "\nTo enter a transaction for your account," 
       << "\nplease enter the account name: \t"; 
    std::string account_choice="???"; 
    std::cin >> account_choice; 
    std::vector<std::shared_ptr<BankAccount>>::iterator 
      itElem = std::find_if(account_list.begin(), account_list.end(), HasIdentifier(account_choice)); 

    std::cout << "\nWould you like to process a (d)ebit or (c)redit to the account?" << std::endl; 
     int a = 0; 
     tolower(a); 
     std::cin >> a; 
     double amount{0}; 
      switch (a){ 
       case 'd': //debit the account 
        std::cout << "\nEnter the amount to debit: \t" << std::endl; 
        std::cin >> amount; 
        (**itElem).debit(amount); 
        break; 
       case 'c': //credit the account 
        std::cout << "\nEnter the amount to credit: \t" << std::endl; 
        std::cin >> amount; 
        (**itElem).credit(amount); 
        break; 
      default: 
       std::cout << "\nInvalid entry" << std::endl; 
      } 

    return 0; 
} 
+0

@RobertPrévost不是重複的。這個問題是由用戶如何(不負責任地)使用指針引起的,而不是迭代器的工作方式。 – Xirema

+0

你能否提出一個更好的方式來使用指針? –

回答

0

迭代器本身看上去是指針(即:它們的接口設計類似於一個指針),所以如果你有一個vector的迭代器,並想調用底層對象的方法,你做不到。「儘管「迭代器是指向所討論對象的指針。

struct my_struct { 
    int val; 
    double other; 
    void func() {} 
}; 

int main() { 
    std::vector<my_struct> my_structs = /*...*/; 

    std::vector<my_struct>::iterator it = std::find_if(my_structs.begin(), my_structs.end(), [](my_struct const& m) {return m.val == 5;}); 

    it->func(); 
} 

問題在於你的情況是你使用的是std::vector<std::shared_ptr<BankAccount>>。現在,僅僅基於提供的代碼,它看起來像是某種多態性正在發生,所以我認爲指針的使用是絕對必要的(儘管you should always prefer unique_ptr over shared_ptr when given a choice),但是因爲向量本身就是保存指針,所以需要乘以間接訪問底層對象。

std::vector<std::shared_ptr<BankAccount>>::iterator 
itElem = std::find_if(account_list.begin(), account_list.end(), HasIdentifier(account_choice)); 
(**itElim).debit(amount); 
//OR... 
itElim->get()->debit(amount); 

我不知道什麼是 HasIdentifier或者它應該做的事情:基於這樣的語法,我很謹慎,它的潛在錯誤的另一個來源。但是有可能這部分代碼已經被正確寫入,並且沒有看到它是如何實現的,我無法分析它。無論如何,我提出的調整應該可以解決這個錯誤。

編輯:好的。 HasIdentifier。這是一個非常簡單的修復:find_if所調用的仿函數的簽名應該採用bool operator()(T t) constbool operator()(T const& t) constbool operator()(T & t) const或其他某種風格,其中T是您用std::vector實例化的類型。

你的情況

所以,你std::vectorstd::vector<std::shared_ptr<BankAccount>>類型,這意味着Tstd::shared_ptr<BankAccount>的。但是在函子中,您已將簽名定義爲bool operator()(BankAccount const& account) const,而std::shared_ptr<T>不會隱式轉換爲T&T const&

只需更新仿函數使用std::shared_ptr<BankAccount> const&代替:

class HasIdentifier //No need to inherit from unary_function; it's been removed from C++17 anyways 
{ 
public: 
    HasIdentifier(string id) : 
    m_id(std::move(id)) //You're passing by value anyways, so move-constructing m_id 
    //will improve performance, especially if it's a large string. 
    {} 

    bool operator()(std::shared_ptr<BankAccount> const& c)const 
    { 
     return (c->getName() == m_id); 
    } 
private: 
    string m_id; 
}; 

最後一件事:Stop using using namespace std

+0

檢查'itElem!= my_structs.end()'和'* itElem'也會很好。現在,我們可以使用'auto'而不是'std :: vector > :: iterator'。 – Jarod42

+0

感謝您的幫助。爲什麼您建議停止使用'using namespace std'? –

+0

@MarcReinecker我提供的鏈接證明了自己的論點。 – Xirema

相關問題