Время компиляции, проверьте, является ли базовый класс "интерфейсом" - PullRequest
6 голосов
/ 28 марта 2012

После того, как выяснилось, что то, что я изначально хотел, вероятно, невозможно без использования C ++ 11, я хочу немного изменить требование и спросить вас, можно ли это достичь.

предыдущаявопрос

В основном я хочу проверить во время компиляции, наследует ли класс от "интерфейса".Под интерфейсом я имею в виду класс только с чисто виртуальными методами.Я хотел бы сделать следующий код:

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

Поведение здесь, если T имеет только чисто виртуальные методы, то он будет компилироваться, и если один из его методов не будет, то сбой.

Кто-нибудь может придумать что-нибудь подобное?

Ответы [ 3 ]

2 голосов
/ 28 марта 2012

Это в основном похоже на Java-интерфейсы .В C ++ не существует interface как такового, это просто терминология, используемая для class со всеми чисто виртуальными методами и только static const членами данных.

Кроме того, чисто виртуальные методы могут иметь или не иметь тело функции.Таким образом, чисто виртуальные методы C ++ не совсем такие же, как абстрактные методы Java.

К сожалению, вы спрашиваете, невозможно моделировать в C ++.

1 голос
/ 28 марта 2012

То, что вы хотите, не может быть сделано напрямую, как уже объяснили другие.

Тем не менее, вы все равно можете получить желаемое поведение с небольшой дисциплиной от разработчиков интерфейса. Если все ваши интерфейсы получены из общего базового класса Interface, вы можете проверить, что 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, даже если базовый класс не является интерфейсом. Вот почему я сказал, что это требует некоторой дисциплины от разработчика.

Тем не менее, я не вижу, как это было бы полезно. Я никогда не чувствовал, что мне нужна такая проверка времени компиляции.

1 голос
/ 28 марта 2012

Во-первых, интерфейсы на самом деле не являются родной концепцией для 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 - это вопрос для кого-то более знакомого со стандартами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...