C++在向量中查找对象并调用其上的成员函数
这是作业相关的,所以我必须使用向量来存储这些对象。 我有一个基类的BankAccount与衍生的CheckingAccount和SavingsAccountC++在向量中查找对象并调用其上的成员函数
请问占他们要为输入数据,即支票或储蓄然后索要平衡和利率/交易费的用户。然后,使用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;
如何可以先找到,在两个物体的矢量的类型的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;
}
迭代器本身看上去是指针(即:它们的接口设计类似于一个指针),所以如果你有一个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) const
或bool operator()(T const& t) const
或bool operator()(T & t) const
或其他某种风格,其中T
是您用std::vector
实例化的类型。
所以,你std::vector
是std::vector<std::shared_ptr<BankAccount>>
类型,这意味着T
是std::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;
};
@RobertPrévost不是重复的。这个问题是由用户如何(不负责任地)使用指针引起的,而不是迭代器的工作方式。 – Xirema
你能否提出一个更好的方式来使用指针? –