C++在向量中查找对象并调用其上的成员函数

问题描述:

这是作业相关的,所以我必须使用向量来存储这些对象。 我有一个基类的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

你能否提出一个更好的方式来使用指针? –

迭代器本身看上去是指针(即:它们的接口设计类似于一个指针),所以如果你有一个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