【问题标题】:Make sure a class does not inherit from two interfaces确保一个类不继承自两个接口
【发布时间】:2020-07-11 08:12:36
【问题描述】:

我有这个问题。有一个我们开发和使用的框架。我们有一些该框架的用户需要实现的接口。我想确保其中两个接口永远不能在同一个类上实现。这是一个例子

class A{
  void a() = 0;
};
class B{
  void b() = 0;
};

class C: public A, public B { // This should give error
};
class D: public A{ // OK
};

到目前为止,我认为也许我可以使用 static_assertstd::is_convertible,但我无法亲自动手。

编辑: 我不知道谁来编写派生类,所以如果可能的话,我想把它放在基接口中。基本上假设我无法访问派生类,因为它们不在我们的代码库中。

谢谢。

【问题讨论】:

  • “我想确保这两个接口永远不能在同一个类上实现。”如果用户能够做到这一点,那么它在功能上是有效的、有效的和清晰的,那么就没有理由用破坏的界面约定来取笑用户。看起来你想写一个文字冒险!
  • 这不是我的设计,我无法更改。我在代码中看到原作者进行了动态转换并给出了最糟糕的运行时错误。我想看看我能不能让它至少变成一个编译时错误
  • 动态转换成什么?您不想告诉我他尝试强制转换为所有损坏的接口类,计算数量并在多次发现时抛出错误?不! :-) 谁为改善界面的糟糕程度买单?
  • 你看到我正在经历的头痛类型????我很想以一种好的方式解决这个问题,但这不是我目前可以做出的决定,因为代码已经连接到很多地方。而且我还没有告诉你们一半。
  • 对我来说,感觉您没有(仅)有技术问题。可能值得去找你的老板,要求更好的团队教育,创建更好的代码指南,参与有益的代码审查,不要遵循学术规则(多重继承是 eval 成语)并投资于软件资本!我相信“改进”坏主意无济于事。

标签: c++ c++14


【解决方案1】:

这样写自己的特质:

template<typename Derived, typename... BaseCandidates>
struct has_no_base;

template<typename Derived>
struct has_no_base<Derived>
    : std::true_type { };

template<typename Derived, typename BaseFirst, typename... BasesRest>
struct has_no_base<Derived, BaseFirst, BasesRest...>
    : std::conditional_t<
        std::is_base_of<BaseFirst, Derived>,
        std::true_type,
        has_no_base<Derived, BasesRest...>
      > { };

template<typename Derived, typename... PossibleBases>
struct has_only_one_base;

template<typename Derived>
struct has_only_one_base<Derived>
    : std::false_type { };

template<typename Derived, typename Base>
struct has_only_one_base<Derived, Base>
    : std::conditional_t<
        std::is_base_of_v<Base, Derived>,
        std::true_type,
        std::false_type
      > { };

template<typename Derived, typename BaseFirst, typename... BasesRest>
struct has_only_one_base<Derived, BaseFirst, BasesRest...>
    : std::conditional_t<
        std::is_base_of_v<BaseFirst, Derived>,
        has_no_base<Derived, BasesRest...>,
        has_only_one_base<Derived, BasesRest...>
      > { };

然后像这样使用它:

class MyClass : public A, public B
{
    static_assert(has_only_one_base<MyClass, A, B>::value, "Error");
};

此外,只要你是这个框架的开发者,你可以提供一些检查特征:

template<typename Type>
using is_valid_class = has_only_one_base<Type, IFirst, ISecond, ... ILast>;

并使用它:

class MyClass : public A, public B
{
    static_assert(is_valid_class<MyClass>::value, "Error");
};

【讨论】:

  • OP 询问他如何保证没有人从两个接口继承。如果用户如何“滥用”界面,为什么这个用户应该自己做检查。在你的情况下,我可以在 assert 子句中写下所有内容。我看不出这个有什么帮助!
  • 感谢您的回答。但是,由于这是一个框架,假设我无权访问派生类。我只知道框架中的接口。我可以将这些断言放在接口中的某个位置吗?
  • @Ashkan:没错!这个“解决方案”是没有的,因为它需要用户自己说:我做错了。无济于事:-)
  • @Klaus 我认为没有这样的方法可以保证不存在多接口继承。唯一的方法是假设口头约定要么只继承一个接口,要么在用户的类继承 2 个或更多接口时提出is_valid_class 断言以引发编译时错误
  • 也许吧?但是,如果您的答案没有回答 OP 的问题,为什么它仍然存在。在我看来,您的代码无济于事,因为最终用户必须编写自己的支票来检查自己是否做错了事。对不起,你能帮我理解你的答案有什么用吗?想知道人们支持这个答案...... :-)
猜你喜欢
  • 2021-09-12
  • 1970-01-01
  • 2019-08-04
  • 1970-01-01
  • 2013-12-11
  • 1970-01-01
  • 2020-12-09
  • 2014-03-09
  • 1970-01-01
相关资源
最近更新 更多