Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile time check whether a base class is "interface"

After it turned out that what I originally wanted is probably not possible w/o involving C++11 I want to slightly change the requirement and ask you if this can be achieved.

previous question

Basically I want to check in compile time if a class is inheriting from "interface". By interface I mean class with pure virtual methods only. I would like to do the following code:

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

The behavior here is if T has only pure virtual methods then it will compile and if one of its methods is not then fail.

Can anyone think of something like that?

like image 847
Vadim S. Avatar asked Mar 28 '12 07:03

Vadim S.


3 Answers

This is basically similar to Java interfaces. In C++, there is no existence of interface as such, it's just a terminology used for a class with all pure-virtual methods and only static const data members.

Additionally, pure virtual methods may or may not have a function body. Thus C++ pure virtual methods are not exactly same as Java's abstract methods.

Unfortunately what you are asking is not possible to simulate in C++.

like image 123
iammilind Avatar answered Nov 10 '22 06:11

iammilind


First off, interfaces are not really a native concept to C++. I'm sure most programmers know what they are, but the compiler doesn't, and that's where you're running into problems. C++ can do a lot of things, and I bet you can twist it into looking like a lot of different languages, but if you're going to write C++, it's best to do things the C++ way.

Another thing - there's a lot of grey area here. What if you had an "interface" like you suggested, but somebody did one of these:

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

I'm almost 100% sure you can't stop someone from doing that.

You may be able to make sure there are no member variables though, even though I'm not sure I agree with this way of doing things. Make an empty class, and then do a static_assert(sizeof(InterfaceClass) == sizeof(Empty)). I'm not sure if it's safe to assume the size would be 0 - that's a question for someone more familiar with the standards.

like image 35
parkovski Avatar answered Nov 10 '22 04:11

parkovski


What you want can not be done directly, as others have already explained.

However, you can still get the behavior you want with a bit of discipline from the interface developers. If all your interfaces derive from a common base class Interface, you can check that Interface is a base class at compile time using a technique similar to this question.

For example :

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

Of course, the developer of the base class can cheat and derive from Interface even though the base class is not an interface. Which is why I said it requires some discipline from the developer.

That said though, I can't see how this would be useful. I've never felt I needed this kind of compile time check.

like image 25
Sander De Dycker Avatar answered Nov 10 '22 05:11

Sander De Dycker