2012-03-28 45 views
6

事实证明,我最初想要的可能不可能不涉及C++ 11而不可能我想稍微更改要求并询问您是否可以实现。编译时检查基类是否为“接口”

previous question

基本上我想在编译时检查,如果一类是从“接口”继承。通过接口,我只是指纯粹的虚拟方法。 我愿做下面的代码:

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

的行为在这里是如果T纯虚函数,然后它会编译,如果它的方法是不那么失败。

任何人都可以想到类似的东西?

+1

真的所有的方法纯虚拟?即使是析构函数? – Andrzej 2012-03-28 07:40:39

+0

假设你想检查'T'是否具有基类,如果是,那么它们是否也是“接口”。但答案确实是“不”。 – MSalters 2012-03-28 07:55:03

回答

2

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

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

不幸的是,你要求的是不可能在C++中模拟。

+0

基本上我想要所有的方法都是虚拟的,以确保我覆盖它们(我不是在谈论c'tor等......)。 – 2012-03-28 08:18:23

+0

@VadimS .:你的意思是你想确保你重写所有的方法,或者你想确保当你编写一个应该重写基类方法的方法时,它的确如此? – 2012-03-28 08:44:46

+0

我想避免(在编译时)的情况下,我想重写基类中的方法,但该方法没有被定义为'虚拟'。 – 2012-03-28 09:07:45

1

首先,接口并不是真正的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是否安全 - 这对于更熟悉标准的人来说是一个问题。

+1

它不会是0.因为如果你声明了多个'Empty'类型的变量,它们每个都必须在内存中有一个唯一的地址。 – enobayram 2012-03-28 08:14:43

+1

'static_assert(sizeof(InterfaceClass)== sizeof(Empty))' - 不能确定。大小和空类(没有成员变量和没有虚函数)将是1个字节,并且'InterfaceClass'的大小通常不会是1个字节,最有可能的是会有虚函数,这会使大小为4个字节(大小为指针) – Sanish 2012-03-28 08:26:52

1

你想要的东西不能直接完成,正如其他人已经解释的那样。

但是,您仍然可以从界面开发人员那里获得一些您想要的行为。如果所有接口都来自公共基类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派生即使基类不是一个接口。这就是为什么我说它需要开发者的一些纪律。

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