2017-09-08 5 views
-2

これは宿題に関連しているので、これらのオブジェクトを格納するためにベクトルを使用する必要があります。 私は派生したCheckingAccountとSavingsAccountを持つ基本クラスBankAccountを持っていますC++ベクトル内のオブジェクトを検索し、その上でメンバ関数を呼び出す

私はどのアカウントにデータを入力したいのか、つまりチェックや貯蓄を求め、残高と金利/取引手数料を求めます。次に、switch文を使用して、オブジェクトはこれらの入力を使用して初期化され、スマートポインタを使用してベクトルvector<shared_ptr<BankAccount>>account_listに追加されます。

次に、メンバー関数creditまたはdebitのトランザクションを追加することで、対話するアカウントタイプを選択するようにユーザーに依頼します(小切手または節約金利の取引手数料を基本クラスから上書きします)。

私の問題はここにあります:ユーザーが取ったルートによっては、ユーザーが選択した順序でどちらかのアカウントが追加されているため、ベクター内のオブジェクトの位置がわかりません。

アカウントが(スイッチの場合)のような追加される:

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; 

どのようにして最初の2つのオブジェクトのベクトルで、型CheckingAccountを見つけるか、SavingsAccountを入力し、次に、要素の位置を知ることができ、呼び出しそれに対する適切なメンバ関数?

これは私がこれまで行ってきたことですから、私が実験していたものを理解しようとする、面倒なコードを許してください。

基本クラスでは、私は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

イテレータ自身をポインタのように振る舞う(すなわち:そのインターフェイスポインタに似ているように設計された)ので、あなたは、ベクトルのイテレータを持って、基礎となるオブジェクトのメソッドを呼び出したい場合は、あなたがそうします」そのイテレータは問題のオブジェクトへのポインタでした。

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あるか何行うことになっています見当がつかない。しかし、コードの部分が正しく書かれている可能性があり、実装方法を見ずには解析できません。とにかく、私が提案した調整はこのエラーを修正するはずです。

EDIT:いいえ。 HasIdentifier。これは非常に簡単な修正です:find_ifによって呼び出されたファンクタのシグニチャは、bool operator()(T t) const、またはbool operator()(T const& t) constまたはbool operator()(T & t) constなどの形式を取ることになっています。Tstd::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'をチェックするのもいいでしょう。今度は' std :: vector > :: iterator'の代わりに 'auto'を使うことができます。 – Jarod42

+0

助けてくれてありがとうございます。なぜ、 'namespace std'を使うのをやめようと勧めていますか? –

+0

@MarcReinecker私が提供したリンクは、独自の論文を正当化しています。 – Xirema

関連する問題