我有一个学校的任务,创建一个管理猫收容所的应用程序,我必须提供根据某些标准过滤猫的选项。
我有一个基类 Filter,以及两个派生类,用于按年龄和品种过滤猫。
class Filter
{
public:
virtual bool operator()(const Cat & cat) const = 0;
virtual ~Filter() {}
};
class FilterOfBreed : public Filter
{
private:
std::string breed;
public:
FilterOfBreed(const std::string & b) : breed(b) {}
bool operator()(const Cat & cat) const override { return this->breed.length() == 0 || this->breed == cat.getBreed(); }
};
class FilterAgeLessThan : public Filter
{
private:
int age;
public:
FilterAgeLessThan(int a) : age(a) {}
bool operator()(const Cat & cat) const override { return cat.getAge() <= this->age; }
};
在我的控制器中,我有过滤器功能,它使用copy_if进行过滤。
vector<Cat> Controller::filter(const Filter * filter)
{
vector<Cat> result;
copy_if(this->repo.getCats().begin(), this->repo.getCats().end(), back_inserter(result), filter);
return result;
}
我希望能够使用不同类型的过滤从控制器调用过滤器函数。 例如:
Filter * filter = new FilterOfBreed("Birman");
vector<Cat> filtered = ctrl.filter(filter);
过滤后应包含伯曼品种的猫。
或者对于以下代码:
Filter * filter = new FilterAgeLessThan(3);
vector<Cat> filtered = ctrl.filter(filter);
过滤应包含年龄小于或等于 3 的猫。
为了进行过滤,我需要一个函数来接收两个参数并检查它们之间是否存在某种关系。但是函数"copy_if"必须接收一元谓词作为最后一个参数。我在这里的一篇文章中读到,我可以使用指向 copy_if 中类的指针(该类具有附加参数作为成员),并重载该类的 operator()。这就是我创建类过滤器的原因。
但是当我编译代码时,它给了我一个错误:"术语没有计算为一个接受 1 个参数的函数"。错误来自函数"copy_if"。
>std::copy_if
接受对可调用对象的引用,而不是指向它的指针。 您基本上有两种选择:
-
在不更改函数签名的情况下,进行引用并将其传递给
copy_if
:vector<Cat> Controller::filter(const Filter * filter) { vector<Cat> result; copy_if(repo.getCats().begin(), repo.getCats().end(), back_inserter(result), *filter); // THIS ASTERISK IS THE KEY ^^^ return result; }
-
更改函数以获取引用,就像
copy_if
一样:vector<Cat> Controller::filter(const Filter & filter) // CHANGED TO AMPERSAND HERE ^^^ { vector<Cat> result; copy_if(repo.getCats().begin(), repo.getCats().end(), back_inserter(result), filter); return result; }
与现已删除的评论相反,按值传递不是一种选择。 多态性仅适用于指针和引用,不适用于副本。
此外,对函数对象使用基类也不流行。 现代C++样式通常会为此使用 lambda:
vector<Cat> filtered =
ctrl.filter([](const Cat& cat){ return cat.getBreed() == "Birman"; });
要做到这一点,你可以
使您的筛选函数成为可以接受 lambda 类型的模板:
template<typename Predicate> vector<Cat> Controller::filter(const Predicate & filter) { vector<Cat> result; copy_if(repo.getCats().begin(), repo.getCats().end(), back_inserter(result), filter); return result; }
使用执行类型擦除的
std::function
,这与多态性几乎相同,但不需要继承:vector<Cat> Controller::filter(std::function<bool(const Cat&)> filter) { vector<Cat> result; copy_if(repo.getCats().begin(), repo.getCats().end(), back_inserter(result), filter); return result; }
这两者仍将接受Filter
派生的调用。