Sobrecarga de função às avessas
De ccppbrasil.org
Alguém já se perguntou se é possível usar sobrecarga de função quando a diferença não está nos parâmetros recebidos, mas no tipo de retorno? Melhor dizendo, imagine que eu tenha o seguinte código:
GUID guid; wstring guidS; CreateNewGUID(guidS); // chama void CreateNewGUID(wstring&) CreateNewGUID(guid); // chama void CreateNewGUID(GUID&) (o compilador sabe disso)
É um uso sensato de sobrecarga. Mas vamos supor que eu queira uma sintaxe mais intuitiva, com o retorno sendo atribuído à variável:
GUID guid; wstring guidS; guidS = CreateNewGUID(); // chama wstring CreateNewGUID() guid = CreateNewGUID(); // chama GUID CreateNewGUID() (o compilador sabe disso?)
Voltando às teorias de C++, veremos que o código acima NÃO funciona. Ou, pelo menos, não deveria. Só pelo fato das duas funções serem definidas o compilador já reclama:
error C2556: 'GUID CreateNewGUID(void)' : overloaded function differs only by return type from 'std::wstring CreateNewGUID(void)'
Correto. O tipo de retorno não é uma propriedade da função que exclua a ambigüidade. Apenas a assinatura pode fazer isso (que são os tipos dos parâmetros recebidos pela função).
Pois bem. Não podemos fazer isso utilizando funções ordinárias. Então o jeito é criar nosso próprio "tipo de função" que dê conta do recado:
struct CreateNewGUID
{
// o que vai aqui?
};
Pronto. Agora podemos "chamar" a nossa função criando uma nova instância e atribuindo o "retorno" a wstring ou à nossa GUID struct:
guidS = CreateNewGUID(); // instancia um CreateNewGUID guid = CreateNewGUID(); // instancia um CreateNewGUID. A diferença está no "retorno"
Uma vez que criamos um novo tipo, e considerando que este tipo é, portanto, diferente dos tipos wstring e GUID já existentes, devemos simplesmente converter nosso novo tipo para cada um dos tipos de retorno desejados:
struct CreateNewGUID
{
operator wstring () { ... } // a conversão é a "chamada da função".
operator GUID () { ... } // E como existem duas conversões... sobrecarga!
};
E isso conclui a solução meio esquizofrênica de nossa sobrecarga às avessas:
// instancia um CreateNewGUID e chama CreateNewGUID::operator wstring() guidS = CreateNewGUID(); // instancia um CreateNewGUID e chama CreateNewGUID::operator GUID() guid = CreateNewGUID();
Eis o fonte completo:
#include <windows.h>
#include <objbase.h>
#include <iostream>
#include <string>
using namespace std;
struct CreateNewGUID
{
operator wstring ()
{
GUID guid = operator GUID();
OLECHAR buf[40] = { };
::StringFromGUID2(guid, buf, sizeof(buf));
return wstring(buf);
}
operator GUID ()
{
GUID guid = { };
::CoCreateGuid(&guid);
return guid;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
wstring guidS;
GUID guid;
// instancia um CreateNewGUID e chama CreateNewGUID::operator wstring()
guidS = CreateNewGUID();
// instancia um CreateNewGUID e chama CreateNewGUID::operator GUID()
guid = CreateNewGUID();
wcout << L"Pra nao dizer que esse exemplo nao imprime nada:\n"
<< guidS << L'\n';
return 0;
}
Voltando à pergunta original: penso que, com criatividade e C++, nada é impossível =)
Artigo original: Caloni.com.br
/*Outro Exemplo*/ Um código mais simples para exemplificar, pode ser feito da seguinte maneira:
#include <iostream>
#include <string>
using namespace std;
struct CreateNewGUID
{
operator char * ()
{
char * s = "Teste de String";
return s;
}
operator int()
{
int x = 12345;
return x;
}
};
int main()
{
int guidS;
char * guid;
// instancia um CreateNewGUID e chama CreateNewGUID::operator char * ()
guidS = CreateNewGUID();
// instancia um CreateNewGUID e chama CreateNewGUID::operator int ()
guid = CreateNewGUID();
cout << "Pra nao dizer que esse exemplo nao imprime nada:\n" << guidS << endl;
cout << "Pra nao dizer que esse exemplo nao imprime nada:\n" << guid << endl;
return 0;
}
--Anabuki 13:15, 27 Novembro 2006 (PST)
