提问人:Antonio 提问时间:8/24/2023 最后编辑:Antonio 更新时间:8/24/2023 访问量:84
具有便捷方法的 C++ 接口
C++ Interface with convenience methods
问:
假设我有以下接口:
struct Person {
std::string name;
unsigned short age;
};
class ContainerInterface {
public:
virtual ~ContainerInterface () = default;
virtual void addPerson (Person const&) = 0;
virtual std::optional<Person> getPerson (std::string const& name) const = 0;
virtual bool hasPerson (std::string const& name) const = 0;
};
此接口可以通过以下方式实现:
class Container: public ContainerInterface {
public:
virtual void addPerson (Person const& person) override {
_people.push_back(person);
}
virtual std::optional<Person> getPerson (std::string const& name) const override {
for (const auto& person: _people) {
if (person.name == name) return person;
}
return std::nullopt;
}
virtual bool hasPerson (std::string const& name) const override {
return getPerson(name).has_value();
}
private:
std::vector<Person> _people;
};
虽然这看起来很简单,但有一个问题:像这样的方法实际上只是 的别名。所有实现都应该共享这一点,而不应该留给实现本身来强制执行。事实上,没有什么能阻止实现做这样的事情:hasPerson
getPerson(name).has_value()
ContainerInterface
class BrokenContainer: public Container {
public:
virtual bool hasPerson (std::string const& name) const override {
return false;
}
};
当然,我可以通过作为以下部分的一部分来实现此问题:hasPerson
ContainerInterface
class ContainerInterface {
public:
virtual ~ContainerInterface () = default;
virtual void addPerson (Person const&) = 0;
virtual std::optional<Person> getPerson (std::string const& name) const = 0;
virtual bool hasPerson (std::string const& name) const final;
};
// Should always do this, regardless of implementation
bool ContainerInterface::hasPerson (std::string const& name) const {
return getPerson(name).has_value();
}
但是我的界面不再是一个纯粹的界面了。在某些生产设置中,我可以将宏粘附在我的接口上,将其标记为纯接口,并检查它是否未实现任何方法。如果我使用这种方法,我将无法将我的类标记为纯接口。ContainerInterface
另一种解决方法是实现为免费函数:hasPerson
bool hasPerson (ContainterInterface const& container, std::string const& name) {
return container.getPerson(name).has_value();
}
但这感觉并不令人满意,因为听起来它应该是一种 .hasPerson
ContainerInterface
有没有更优雅的方法来保持纯接口,同时强制所有实现都具有相同的含义?ContainerInterface
hasPerson
答:
1赞
Ted Lyngmo
8/24/2023
#1
解决方法是不让其他类直接继承。ContainerInterface
class ContainerInterface { // pure
public:
virtual ~ContainerInterface() = default;
virtual void addPerson (Person const&) = 0;
virtual std::optional<Person> getPerson (std::string const& name) const = 0;
virtual bool hasPerson (std::string const& name) const = 0;
private:
ContainerInterface() = default; // private
friend class ContainerBase; // except for ContainerBase
};
class ContainerBase : public ContainerInterface {
public:
bool hasPerson (std::string const& name) const override final {
// ^^^^^
return getPerson(name).has_value();
}
};
class Container : public ContainerBase {
// ^^^^^^^^^^^^^
//...
};
这与为接口提供无法重写的默认实现基本相同:
class ContainerInterface {
public:
virtual ~ContainerInterface() = default;
virtual void addPerson (Person const&) = 0;
virtual std::optional<Person> getPerson (std::string const& name) const = 0;
virtual bool hasPerson (std::string const& name) const final {
return getPerson(name).has_value();
}
};
评论