jueves, 15 de julio de 2010

Como implementar interfaces en C++

C++ por si solo no trata las interfaces como un concepto diferenciado. Sin embargo se puede trabajar con interfaces tipo Java o C# aprovechándose de la heréncia múltiple creando clases abstractas.

En el siguiente ejemplo las clases ClassA y ClassB implementan la interfaz Interface, para ello tan solo tienen que redefinir el método method.

class Interface{
public:
virtual int method(int param) = 0;
virtual ~Interface(){};
};

class ClassA : public Interface{
public:
int method(int param){return param+1;}
};

class ClassB : public Interface{
public:
int method(int param){return param+2;}
};

Todos los usos que se le dan normalmente a las interfaces siguen siendo válidos con esta aproximación, con una salvedad, si queremos pasar la interfaz como parámetro a una función normalmente se haría como sigue.

std::string function(Interface i){
std::string str;

int number = i.method(1);
if(number==2){str = "ClassA";}
else if(number==3){str = "ClassB";}

return str;
}

Sin embargo, si hacemos esos el compilador protestará con un error similar a: "cannot declare parameter 'i' to be of abstract type 'interface'".

¿Por qué?
Esto ocurre porque por defecto en C++ los parámetros se pasan por valor, el objeto 'i' es imposible de crear ya que es de un tipo abstracto, el compilador no puede instanciarlo.

¿Qué solución hay?
Pasarlo como referencia, con una definición como la siguiente.

std::string function(Interface &i)

Si queremos asegurarnos que el parámetro no se modifica, habría que pasarlo como referencia constante.

std::string function(const Interface &i)

Esto plantea un nuevo problema, generando un error de compilación similar a: "passing 'const Interface' as 'this' argument of 'virtual int Interface::method(int)' discards qualifiers".

No se puede llamar a una función no constante desde un objeto constante. Para solucionarlo los métodos de la interfaz deberían ser constantes, quedando como sigue.

class Interface{
public:
virtual int method(int param) const = 0;
virtual ~Interface(){};
};

class ClassA : public Interface{
public:
int method(int param) const{return param+1;};
};

class ClassB : public Interface{
public:
int method(int param) const{return param+2;};
};

2 comentarios:

Unknown dijo...

Hab metele un enlace a wingedbox.com en el sidebar que se lo tienes hasta a edu! jeje

A ver si así nos dan pagerank y aparecemos por algún término de la página que no sea el nombre XD

Anónimo dijo...

Muy bien explicado gracias.