quinta-feira, 9 de julho de 2015

Programação: [C++] Templates, Friend Class & Operator Overloading

A linguagem C/C++ é indiscutivelmente a mais versátil de todas, dotada de recursos de baixo e alto nível e dinâmica para quaisquer tipos de programação. Além de ser a linguagem mãe de S.O.s como o Linux e o Windows, é possível trabalhar com orientação a objetos, listas, funções inline, assembly e mesmo reprogramar a própria linguagem (um dos tópicos que veremos a seguir...).

Trabalhando com classes em C++, podemos utilizar alguns recursos dinâmicos muito úteis como templates e operator overloading (sobrecarga de operadores).

Templates permitem-nos criar funções e classes genéricas. Pode ser usado, por exemplo, para definir containers que armazenam coleções de diferentes tipos de objetos. Veja o exemplo a seguir:
int max(int a, int b) { return a > b ? a : b; }
float max(float a, float b) { return a > b ? a : b; }
string max(string a, string b) { return a > b ? a : b; }
template <class X>X max (X a, X b) { return a > b ? a : b; }

main: 
    max(3, 7); 
    max("a", "b");
Este código permite utilizar uma única função para comparar diferentes tipos de variáveis ou objetos. Mas também podemos utilizar uma outra técnica, até mais sutil, para este tipo de problema...

A Sobrecarga de Operadores é uma técnica de programação utilizada para redefinir o significado dos operadores naturais da linguagem. Vamos supor que temos o objeto Item, e, declarados dois objetos, queremos comparar um com o outro em relação ao preço. Neste caso temos basicamente dois problemas: como saber que atributo comparar? Como fazer a comparação deste atributo naturalmente? Na sobrecarga de operadores, todos os operadores podem ser sobrescritos. Para este problema, faremos a sobrecarga do operador "<". Veja o código a seguir:
class Item {
public:
    Item(int i, float p) : id(i), preco(p) {};
    bool operator< (Item item) const{ return preco < item.preco; }
    int id;
    string nome;
    float preco;
};
int main() {
    Item i1(10,1);
    Item i2(20,2);
    (i1 < i2) ? cout << i1.id : cout << i2.id;
}
O programa então irá comparar o preço dos itens pelo preço e informará o respectivo id. Vamos apresentar agora algo ainda mais elaborado...Neste caso, se eu quisesse passar diretamente apenas o objeto Item para o operador cout, ele não saberia qual informação exibir. Para isto, podemos utilizar outra técnica de sobrescrita, que se trata na verdade da reescrita do operador "<<" interno da biblioteca ostream. Normalmente, a restrição de acesso a membros privados e protegidos da linguagem não nos permite fazer esta alteração, a menos que declaremos a classe ou membro como Friend. Veja o exemplo a seguir:
class Item {
public:
    Item(int i, string n, float p) : id(i), nome(n) , preco(p) {};
    bool operator< (Item item) const{ return preco < item.preco; }
    friend ostream& operator<<(ostream& out, Item& item)
        { out << item.nome; return out; }
    int id;
    string nome;
    float preco;
};
int main() {
    Item i1(10,"A",1);
    Item i2(20,"B",2);
    (i1 < i2) ? cout << i1 : cout << i2;
}
Com isto, ao invés de retornarmos o id  (definido manualmente), o programa automaticamente retornará o nome do item para sua saída padrão.

Nenhum comentário:

Postar um comentário