Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Beraldo

Chamar método cujo nome está numa string

Recommended Posts

Gostaria de saber como posso chamar um método cujo nome está numa string

 

Vejam o exemplo que criei para demonstração:

#include <iostream>
#include <cstdio>     
#include <cstring>
#include <string>                       
#include <exception>


using namespace std;



class GeneralException : public exception
{

public:
	GeneralException( string func )
	{
		char funcName[50];
		
		sprintf( funcName, "%sException", func.c_str() );
		
		cout << "Devo chamar: " << funcName << endl;
	}

private:
	void test1Exception()
	{
		cout << "Test 1 Exception..." << endl;
	}
	
	
	void test2Exception()
	{
		cout << "Test 2 Exception..." << endl;
	}
};


class Beraldo
{

public:
	void test1()
	{
		throw GeneralException( __FUNCTION__ );
	}
	
	
	void test2()
	{
		throw GeneralException( __FUNCTION__ );
	}
};


int main()
{
	Beraldo *b = new Beraldo();	
	
	try
	{
		b->test1();
	}
	catch( exception& e )
	{
		cout << "exceção capturada" << endl;
	}
	
	
	return 0;
}

Esse é o reflexo exato do que preciso fazer numa aplicação de socket. Tenho uma classe Socket e uma SocketException (Beraldo e GeneralException nesse caso, respectivamente)

 

Métodos da classe Beraldo disparam exceções de GeneralException, passando por parâmetro o nome da função, ao qual é adicionada a palavra "Exception" - resultado na variável "funcName"

 

 

O contrutor de GeneralException precisa chamar o método cujo nome está em "funcName".

 

 

Em PHP issos é simples, mas não encontrei uma solução para C++. Alguém sabe como posso fazer isso?

 

 

 

 

Obrigado

Compartilhar este post


Link para o post
Compartilhar em outros sites

Provavelmente não é o melhor método, mas...

 

#include <stdio.h>
#define METH_HAND(x) x

void soma(int a,int B) {
printf("%d\n",a+B);
}

void texto(char *str) {
printf("%s\n",str);
}

FILE * abrir(const char *arq) {
return fopen(arq, "r");
}

void fechar(FILE *p) {
fclose(p);
}

int main() {
METH_HAND(soma)(3,4);
METH_HAND(texto)("ashdjahsd 23948723");
FILE *p = METH_HAND(abrir)("test.txt");
if (p == NULL) {
	puts("erro");
	return 1;
} else { puts("abri"); }

METH_HAND(fechar)(p);
return 0;
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Caramba! Isso é uma #@?$%~ gambiarra! Chamar método cujo nome está numa String?!?!? Se você estivesse usando C puro eu até entenderia. Mas C++ dá pra usar POO. Polimorfismo cairia muito bem nesta situação. Se estiver apenas estudando tudo bem. Agora se estiveres a implementar isso num sistema aconselho-o a pensar umas 20 vezes antes.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vergil... Onde você está vendo gambiarra nisso? Eu sinceramente não vejo gambiarra...

De um exemplo com recurso a polimorfismo, fiquei curioso.

 

 

Beraldo, acho que a melhor solução é você fazer uma lookup table.

A solução que a Isis postou é válida, mas não trata strings da forma que especificaste no primeiro post.

 

Utilizando os recursos que o C++ te fornece, podemos criar lookup tables de um modo interessante.

(Para lookup tables em C, o link que a Isis forneceu é perfeito)

Uma ideia é você implementar functors e associar um nome a cada functor.

Assim você consegue um ponteiro para uma função que retorna algo do tipo R e recebe x parametros de tipos t1, ..., tx

A única chatice é que não da pra tornar o número de parametros genéricos também...

 

Algo como:

template<typename R>
class Functor0
{
public:
    Functor0(char* name, R (*f)(void));
    ~Functor0();

    R operator() (void);
private:
    R (*f_ptr)(void);
    string name;
};

template<typename R, typename P1>
class Functor1
{
public:
    Functor1(char* name, R (*f)(P1));
    ~Functor1();
    
    R operator() (P1);
private:
    R (*f_ptr)(P1);
    string name;
};

//E assim vai para Functor2, Functor3, ... FunctorN

Então, em alguma parte do seu código você tem algo do tipo:


template<typename R>
class Functor0Table
{
public:
    
    // bla bla bla

    Functor0<R> lookup(string name);
private:
    std::vector<Functor<R> > tbl;

    // bla bla bla
};

Em runtime é impossível transformar uma string em um nome de uma função em C++, pois o compilador adiciona caracteres relativos ao número/tipo dos parametros de uma função.

Imaginemos a seguinte função:

void my_function(int a, int B);
Após compilada, vai se chamar qualquer coisa como:

_my_functionXw3r@e3r3

Para evitar esse tipo de coisa, declare a linkagem como C.

Compartilhar este post


Link para o post
Compartilhar em outros sites
A solução que a Isis postou é válida, mas não trata strings da forma que especificaste no primeiro post.

 

Não entendi que restrição é essa.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado pelas respostas, pessoal.

 

 

Vitor, achei muito interessante sua sugestão. Ainda estou começando com C++, então vou pesquisar mais sobre o que postou, para entender direittinho o código. Ainda está meio confuso para mim.

 

 

Vergil, também fiquei curioso para ver onde o Polimorfismo entra aí. Não compreendi sua sugestão. Agradeço se der um exemplo.

 

 

 

http://forum.imasters.com.br/public/style_emoticons/default/thumbsup.gif

Compartilhar este post


Link para o post
Compartilhar em outros sites

A solução que a Isis postou é válida, mas não trata strings da forma que especificaste no primeiro post.

Não entendi que restrição é essa.

 

Pelo que entendi, o Beraldo quer chamar uma função cujo nome está numa string gerada em runtime.

Nestas condições, o uso de macros não resolve o problema.

 

Será que entendi corretamente?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Obrigado pelas respostas, pessoal.

 

Vitor, achei muito interessante sua sugestão. Ainda estou começando com C++, então vou pesquisar mais sobre o que postou, para entender direittinho o código. Ainda está meio confuso para mim.

 

Vergil, também fiquei curioso para ver onde o Polimorfismo entra aí. Não compreendi sua sugestão. Agradeço se der um exemplo.

 

http://forum.imasters.com.br/public/style_emoticons/default/thumbsup.gif

 

Primeiro peço desculpas se tiver sido um pouco grosseiro. Não foi minha intenção. :P É que essa é a forma com que falo com alguns colegas.

 

Bem! Pelo que vi, parece que esse é um recurso da linguagem C++. Deixa eu explicar a minha sugestão. Claro que tudo depende de como você modela o seu projeto.

 

Imagine que você tenha um sistema de locação / gestão de veículos. Você quer por exemplo consultar um objeto VeiculoAutomotor que seja um carro. Vou dar o exemplo usando java pois conheço pouco de C++.

 

public interface VeiculoAutomotor {
   public abstract void cadastrar();
   public abstract void excluir();
   public abstract VeiculoAutomotor encontrar(VeiculoAutomotor va);
}

public class Carro implements VeiculoAutomotor {
   // Atributos da classe

   public void cadastrar() {

   }

   // Outras implementações de métodos da interface

   public String toString() {
      return "carro";
   }
}

public class Moto implements VeiculoAutomotor {
   // Atributos da classe

   public void cadastrar() {

   }

   // Outras implementações de métodos da interface

   public String toString() {
      return "moto";
   }
}

public class Caminhao implements VeiculoAutomotor {
   // Atributos da classe

   public void cadastrar() {

   }

   // Outras implementações de métodos da interface

   public String toString() {
      return "caminhao";
   }
}

public class VeiculoAutomotorFactory {

   // Usando reflection. Não testei este código. Acredito que deva haver tratamento de excessão aqui.
   public VeiculoAutomotor getInstance(Class className) {
      VeiculoAutomotor va = (VeiculoAutomotor) className.newInstance();
      return va;
   }

   // Usando if. Dá pra usar switch se quiser dar um código pra cada classe.
   public static VeiculoAutomotor getInstance(String className) {
      if(className.equalsIgnoreCase("carro")) {
         return new Carro();
      } // mais condições
      return null;
   }
}

Agora imagine que dentro da aplicação você tenha uma tela com um combobox. Quando você selecionar uma opção o método cadastrar será chamado. Neste momento você não sabe que objeto será instanciado. A decisão será tomada em tempo de execução.

Class className = combobox.getSelectedItem().getClass();
VeiculoAutomotorFactory.getInstance(className).cadastrar();

// Ou você pode usar o outro método
String className = combobox.getSelectedItem().toString();
VeiculoAutomotorFactory.getInstance(className).cadastrar();

Tudo depende de como você modelo seu projeto. Acho que as soluções apresentadas são válidas, porém aumentam muito a complexidade. Dificulta o entendimento. Por que não usar soluções que sejam de melhor entendimento e que possibilitem a reutilização do código?

 

PS: O código não foi testado. E desculpa se eu viajei na maionese.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Pelo que entendi, o Beraldo quer chamar uma função cujo nome está numa string gerada em runtime.

Nestas condições, o uso de macros não resolve o problema.

 

(gdb) l 1

1 #include <stdio.h>

2 #define METH_HAND(x) x

3 void soma(int a,int b ) {

4 printf("%d\n",a+b );

5 }

6

7 void texto(char *str) {

8 printf("%s\n",str);

9 }

10

(gdb)

11 FILE * abrir(const char *arq) {

12 return fopen(arq, "r");

13 }

14

15 void fechar(FILE *p) {

16 fclose(p);

17 }

18

19 int main() {

20 METH_HAND(soma)(3,4);

(gdb)

21 METH_HAND(texto)("ashdjahsd 23948723");

22 return 0;

23 }

(gdb)

Line number 24 out of range; p2.c has 23 lines.

(gdb) b 20

Breakpoint 1 at 0x8048547: file p2.c, line 20.

(gdb) b 21

Breakpoint 2 at 0x804855b: file p2.c, line 21.

(gdb) b 22

Breakpoint 3 at 0x8048567: file p2.c, line 22.

(gdb) r

Starting program: /home/isis/src/imasters/a.out

 

Breakpoint 1, main () at p2.c:20

20 METH_HAND(soma)(3,4);

(gdb) s

soma (a=3, b=4) at p2.c:4

4 printf("%d\n",a+b );

(gdb) s

7

5 }

(gdb) s

 

Breakpoint 2, main () at p2.c:21

21 METH_HAND(texto)("ashdjahsd 23948723");

(gdb) s

texto (str=0x8048646 "ashdjahsd 23948723") at p2.c:8

8 printf("%s\n",str);

(gdb) s

ashdjahsd 23948723

9 }

(gdb) s

 

Breakpoint 3, main () at p2.c:22

22 return 0;

(gdb) s

23 }

 

As funções são chamadas, sim.

 

 

Vergil, acho que o que ele quer fazer é chamar um método (dentre vários) dentro de uma classe (cujo nome é especificado 'externamente' -- exemplo: por entrada do usuário), e não saber qual objeto será usado p/ chamar o método.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vergil, acho que o que ele quer fazer é chamar um método (dentre vários) dentro de uma classe (cujo nome é especificado 'externamente' -- exemplo: por entrada do usuário), e não saber qual objeto será usado p/ chamar o método.

 

Exatamente.

 

 

Usar Factory pode resolver, mas eu teria de possuir uma classee para cada exceção. Eu quero só uma classe com vários métodos. Logo, a solução da Ísis é mais viável

 

Ainda estou sofrendo para entender o exemplo do Vitor e como aplicá-lo ao meu caso. :P

 

Vou usar macro ou Lookup Table simples. Quando eu compreeder melhor Templates e sobrecarga, volto a pensar nesse exemplo

 

 

valeu, pessoal

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

Vergil, acho que o que ele quer fazer é chamar um método (dentre vários) dentro de uma classe (cujo nome é especificado 'externamente' -- exemplo: por entrada do usuário), e não saber qual objeto será usado p/ chamar o método.

 

Exatamente.

 

 

Usar Factory pode resolver, mas eu teria de possuir uma classee para cada exceção. Eu quero só uma classe com vários métodos. Logo, a solução da Ísis é mais viável

 

Ainda estou sofrendo para entender o exemplo do Vitor e como aplicá-lo ao meu caso. :P

 

Vou usar macro ou Lookup Table simples. Quando eu compreeder melhor Templates e sobrecarga, volto a pensar nesse exemplo

 

 

valeu, pessoal

 

A solução que passei é válida pra grandes processos. Padrões de projeto devem ser usados apenas quando houver necessidade. Se a situação for simples, exigir solução simples, tudo bem. Se estiver pensando grande, repense no que vai usar.

 

Tome como exemplo a API do Java que tem uma relação enorme de classes pra lidar com excessões. Você deve ter uma classe pra tratar de cada assunto, e não uma pra atender a várias demandas. Pense bem. Na minha humilde opinião, vocês estão pensando de forma estruturada.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Tome como exemplo a API do Java que tem uma relação enorme de classes pra lidar com excessões. Você deve ter uma classe pra tratar de cada assunto, e não uma pra atender a várias demandas. Pense bem. Na minha humilde opinião, vocês estão pensando de forma estruturada.

 

Ainda bem que pensamos de forma estruturada!

Programação estruturada é usada dentro de OO e de procedural (imperativa).

Mesmo OO precisa de procedural, já que os objetos não sabem magicamente como eles precisam fazer as coisas e o programador especifica os passos detalhadamente no nível no objeto, recorrendo à 'abstração' fornecida por outras classes p/ evitar código que não é responsabilidade do nível que está sendo construído.

A programação estruturada é (além de ser um subconjunto da procedural), segundo uma variante, a não utilização de goto, setjmp, setlongjmp e qualquer outra instrução que desvie o fluxo de forma caótica e um único ponto de saída nas funções. O paper de Dijkstra "A case against the goto statement" é famoso.O Java fez isso muito bem: a palavra goto é reservada,mas você não pode usar. Em comparação, o C adota a idéia de uma programação estruturada com vários pontos de saída, mas é o programador que deve aplicar o conceito.

 

A princípio, polimorfismo não tem nada a ver com a resolução do problema do Beraldo. Em quê a possibilidade de chamar métodos com mesma assinatura de objetos diferentes converte uma string fornecida pelo usuário ou lida de um arquivo numa chamada de função dentro do código em execução na máquina? Acho que o nome mais próximo da situação do Beraldo deve ser 'metaprogramação'.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A princípio, polimorfismo não tem nada a ver com a resolução do problema do Beraldo. Em quê a possibilidade de chamar métodos com mesma assinatura de objetos diferentes converte uma string fornecida pelo usuário ou lida de um arquivo numa chamada de função dentro do código em execução na máquina? Acho que o nome mais próximo da situação do Beraldo deve ser 'metaprogramação'.

 

Pra bom entendedor o exemplo que eu dei basta.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A princípio, polimorfismo não tem nada a ver com a resolução do problema do Beraldo. Em quê a possibilidade de chamar métodos com mesma assinatura de objetos diferentes converte uma string fornecida pelo usuário ou lida de um arquivo numa chamada de função dentro do código em execução na máquina? Acho que o nome mais próximo da situação do Beraldo deve ser 'metaprogramação'.

Pra bom entendedor o exemplo que eu dei basta.

 

Reflection não é OO. É um tipo de metaprogramação.

Metaprogramação até onde eu sei não é OO.

Macro também é um recurso de metaprogramação, embora C não seja uma linguagem com suporte a isso, mas C++ sim (e Java não).

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.