【问题标题】:Compile time check whether a base class is "interface"编译时检查基类是否是“接口”
【发布时间】:2012-03-28 07:16:06
【问题描述】:

原来我最初想要的可能在不涉及 C++11 的情况下是不可能的,我想稍微改变一下要求,问你是否可以实现。

previous question

基本上,如果一个类从“接口”继承,我想检查编译时间。接口是指仅具有纯虚拟方法的类。 我想做以下代码:

template <typename T>
class Impl : public T {
public:
STATIC_ASSERT_INTERFACE(T);
};

这里的行为是,如果 T 只有纯虚方法,那么它将编译,如果其中一个方法没有,则失败。

谁能想到这样的事情?

【问题讨论】:

  • 真的所有方法都是纯虚拟的吗?甚至是析构函数?
  • 大概你想检查T 是否也有基类,如果有,它们是否也是“接口”。但答案确实是“不”。

标签: c++ compilation


【解决方案1】:

这基本上类似于 Java 接口。在 C++ 中,没有 interface 这样的存在,它只是用于 class 的术语,具有所有纯虚拟方法和只有 static const 数据成员。

此外,纯虚方法可能有也可能没有函数体。因此 C++ 的纯虚方法与 Java 的抽象方法并不完全相同。

很遗憾,您所问的是不可能用 C++ 模拟。

【讨论】:

  • 基本上我希望所有方法都是虚拟的,以确保我覆盖它们(我不是在谈论 c'tor 等......)。
  • @VadimS.:您的意思是要确保覆盖所有方法,还是要确保当您编写一个应该覆盖基类方法的方法时,它确实有吗?
  • 我想避免(在编译时)我想覆盖基类中的方法但该方法未定义为“虚拟”的情况。
【解决方案2】:

首先,接口并不是 C++ 的原生概念。我敢肯定大多数程序员都知道它们是什么,但编译器不知道,这就是你遇到问题的地方。 C++ 可以做很多事情,我敢打赌,你可以把它扭曲成许多不同的语言,但如果你要编写 C++,最好以 C++ 的方式做事。

另一件事 - 这里有很多灰色区域。如果你有一个你建议的“界面”,但有人做了其中之一:

// Technically not a member function, but still changes the behavior of that class.
bool operator==(const Interface &left, const Interface &right);

我几乎 100% 确定您无法阻止某人这样做。

尽管我不确定我是否同意这种做事方式,但您也许可以确保没有成员变量。做一个空班,然后做一个static_assert(sizeof(InterfaceClass) == sizeof(Empty))。我不确定假设大小为 0 是否安全 - 对于更熟悉标准的人来说,这是一个问题。

【讨论】:

  • 它永远不会是 0。因为如果你声明了多个 Empty 类型的变量,每个变量在内存中都必须有一个唯一的地址。
  • static_assert(sizeof(InterfaceClass) == sizeof(Empty)) - 不能确定。空类(没有成员变量和虚函数)的大小为 1 个字节,InterfaceClass 的大小通常不是 1 个字节,很可能会有虚函数使大小为 4 个字节(a 的大小)指针)
【解决方案3】:

你想要的不能直接做,其他人已经解释过了。

但是,您仍然可以通过界面开发人员的一些纪律来获得您想要的行为。如果您的所有接口都派生自一个公共基类Interface,您可以使用类似于this question 的技术在编译时检查Interface 是一个基类。

例如:

class Interface {
    public :
        virtual ~Interface() { }
};

template <typename T>
struct IsDerivedFromInterface {
    static T t();
    static char check(const Interface&);
    static char (&check(...))[2];
    enum { valid = (sizeof(check(t())) == 1) };
};

class MyInterface : public Interface {
    public :
        virtual void foo() = 0;
};

class MyBase {
    public :
        virtual void bar() { }
};

class Foo : public MyInterface {
    public :
        virtual void foo() { }
};
BOOST_STATIC_ASSERT(IsDerivedFromInterface<Foo>::valid);    // just fine

class Bar : public MyBase {
    public :
        virtual void bar() { }
};
BOOST_STATIC_ASSERT(IsDerivedFromInterface<Bar>::valid);    // oops

当然,基类的开发者可以欺骗并从Interface 派生,即使基类不是接口。这就是为什么我说这需要开发人员遵守纪律。

尽管如此,我看不出这会有什么用。我从来没有觉得我需要这种编译时检查。

【讨论】:

    猜你喜欢
    • 2020-08-09
    • 1970-01-01
    • 2012-11-15
    • 2014-08-20
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 2015-08-24
    • 1970-01-01
    相关资源
    最近更新 更多