2012-03-28 11 views
6

Después de que resultó que lo que originalmente quería probablemente no sea posible sin C++ 11, deseo cambiar ligeramente el requisito y preguntarle si esto se puede lograr .Tiempo de compilación compruebe si una clase base es "interfaz"

previous question

Básicamente quiero comprobar en tiempo de compilación si una clase hereda de "interfaz". Por interfaz quiero decir clase con métodos virtuales puros solamente. me gustaría hacer el siguiente código:

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

El comportamiento aquí es si T tiene sólo métodos virtuales puros continuación, se compilará y si uno de sus métodos no es entonces un error.

¿Alguien puede pensar en algo así?

+1

¿Realmente todos los métodos son puros virtuales? Incluso el destructor? – Andrzej

+0

Es probable que desee comprobar si 'T' también tiene clases base, y si es así, si también son" interfaces ". Pero la respuesta es de hecho "No". – MSalters

Respuesta

2

Esto es básicamente similar a interfaces de Java. En C++, no hay existencia de interface como tal, es solo una terminología utilizada para un class con todos los métodos puros virtuales y solo static const miembros de datos.

Además, los métodos virtuales puros pueden tener o no un cuerpo de función. Por lo tanto, los métodos virtuales puros de C++ no son exactamente lo mismo que los métodos abstractos de Java.

Lamentablemente lo que está preguntando es no es posible para simular en C++.

+0

Básicamente quiero que todos los métodos sean virtuales para asegurar que los anule (no estoy hablando de c'tor, etc.). –

+0

@VadimS .: ¿quieres decir que quieres asegurarte de anular todos los métodos, o quieres asegurarte de que cuando escribes un método que se supone que anula un método de clase base, lo hace? –

+0

Quiero evitar (en tiempo de compilación) un caso en el que deseo anular un método en la clase base, pero el método no se define como 'virtual'. –

1

En primer lugar, las interfaces no son realmente un concepto nativo de C++. Estoy seguro de que la mayoría de los programadores saben lo que son, pero el compilador no, y ahí es donde te encuentras con problemas. C++ puede hacer muchas cosas, y apuesto a que se puede convertir en una gran cantidad de idiomas diferentes, pero si vas a escribir C++, es mejor hacer las cosas al estilo C++.

Otra cosa: hay una gran cantidad de áreas grises aquí. ¿Y si tuviera una "interfaz", como usted sugiere, pero alguien lo hizo uno de estos:

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

estoy casi 100% seguro de que no se puede detener a alguien de hacer eso.

Sin embargo, es posible que pueda asegurarse de que no haya variables miembro, aunque no estoy seguro de estar de acuerdo con esta manera de hacer las cosas. Haga una clase vacía, y luego haga un static_assert(sizeof(InterfaceClass) == sizeof(Empty)). No estoy seguro de si es seguro asumir que el tamaño sería 0; esa es una pregunta para alguien más familiarizado con los estándares.

+1

Nunca será 0. Porque si declara varias variables de tipo 'Vacío', cada una de ellas debe tener una dirección única en la memoria. – enobayram

+1

'static_assert (sizeof (InterfaceClass) == sizeof (Empty))' - no puedo estar seguro. El tamaño de y la clase vacía (sin variables miembro y sin funciones virtuales) será de 1 byte y el tamaño de una 'InterfaceClass 'generalmente no será de 1 byte, probablemente la función virtual tendrá el tamaño de 4 bytes (tamaño de puntero) – Sanish

1

Lo que desea no se puede hacer directamente, como otros ya han explicado.

Sin embargo, aún puede obtener el comportamiento que desea con un poco de disciplina por parte de los desarrolladores de la interfaz. Si todas sus interfaces derivan de una clase base común Interface, puede verificar que Interface es una clase base en tiempo de compilación utilizando una técnica similar a this question.

Por ejemplo:

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 

Por supuesto, el desarrollador de la clase base puede engañar y derivar de Interface a pesar de que la clase base no es una interfaz. Por eso dije que requiere cierta disciplina del desarrollador.

Sin embargo, dicho esto, no veo cómo esto podría ser útil. Nunca sentí que necesitaba este tipo de control de tiempo de compilación.

Cuestiones relacionadas