while sentencia programacion lenguaje instruccion estructura else ejemplos decision c++ object

c++ - programacion - Usando una variable que fue definida en una sentencia if antes



sentencia if en c++ (8)

int main() { if(i = 0) { myclass1 a = "Example1"; } else { myclass2 a = "Example2"; } cout << a << endl; }

Sé que una forma de hacerlo es definiéndola fuera del bloque, pero ¿qué sucede si no he decidido qué tipo es antes de verificar la condición de i ?


C ++ es un lenguaje de tipo estático , y requiere que el tipo de variables que se utilizan en el código se conozcan en el momento de la compilación.

No hay forma de escribir un programa en C ++ donde una declaración como std::cout << a; se compila y el tipo de a no se conoce hasta el tiempo de ejecución.

Para eso necesitas un lenguaje de tipo dinámico , como por ejemplo Python o JavaScript.


Esto definitivamente requiere polimorfismo, y opcionalmente, si quieres tenerlo un poco más elegante, el patrón de fábrica . El patrón de fábrica no es mágico, solo oculta el if dentro de un envoltorio agradable.

¿Por qué no otro enfoque, como por ejemplo, std::variant que es básicamente una union disfrazada? Bueno, es bueno si puedes almacenar diferentes tipos de cosas, o incluso cualquier tipo ( std::any ) con el mismo nombre, pero no es muy útil ya que también quieres hacer algo significativo con el objeto. Si desea hacer cosas completamente diferentes, no relacionadas, entonces también puede tener diferentes objetos con el alcance de los bloques if (y con un código completamente diferente). Sin embargo, si desea hacer lo mismo o cosas similares en diferentes objetos, entonces (generalmente) deben ser del mismo tipo o uno relacionado.

Por lo general, los diferentes tipos no tienen los mismos miembros de datos o las mismas funciones de miembros de acceso público. Por lo tanto, hacer lo mismo en un nivel de código fuente con diferentes tipos normalmente no funciona (excepto por coincidencia).

Pero si dos clases tienen subconjuntos idénticos en sus interfaces, y desea poder hacerlo de manera intercambiable, heredar de una clase base es lo más natural e idiomático que se puede hacer. Para eso se inventó el polimorfismo. Usa lo idiomático.

(Puede obtener el mismo efecto neto de las funciones de llamada con el mismo nombre en diferentes tipos no relacionados a través de un ayudante de plantilla, y presume que los nombres que utiliza existen, eso simplemente funcionará , pero no es un estilo tan bueno, causa una gran hinchazón al instanciar la función dos veces).


Podrías probar el polymorphism . Asumiendo que myclass1 y myclass2 "implementan" una clase llamada myclass , puedes hacer algo como esto:

int main() { myclass*a; if (i=0) { a = new myclass1("Example1"); } else { a = new myclass2("Example2"); } cout<<*a<<endl; }

Si desea usar el tipo myclass1 o myclass2 más adelante, puede usar dynamic_cast , pero dependiendo de sus necesidades y el comportamiento que implemente en sus clases heredadas y su clase base, puede que no sea necesario.

Nota: aquí uso un puntero en bruto, ya que es un objeto de corta duración y está claro que el programa ha finalizado. Le animo a leer sobre punteros inteligentes y usarlos de manera apropiada para evitar pérdidas de memoria . Tenga cuidado con las pérdidas de memoria en algunas plataformas que persisten hasta que, después de reiniciar, es posible que se necesite liberar (eliminar) manualmente la memoria asignada. Más sobre todo eso here .


Si es este problema específico, creo que sería mucho más fácil.

int main(){ if(i == 0) //You wrote i=0 !! silly mistake std::cout << myclass1("Example1"); else std::cout << myclass2("Example2"); }

o puedes elegir

template<class T> void foo(T out) { std::cout << out; } int main() { if( i==0 ) foo(myclass1("ex1")); else foo(myclass2("ex2")); }

más

this es el camino a seguir Y no recomendaría el uso de cout aquí, ya que puede que no tenga sobrecargas para aceptar su clase definida por el usuario.


Si puede usar c ++ 17 , puede usar std::variant o std::any en caso de que sus tipos no tengan una clase base común. Estas clases son contenedores seguros para cualquier tipo o tipo específico. Un ejemplo con std::variant puede ser el siguiente:

#include <iostream> #include <string> #include <variant> int main() { bool input = false; std::cin >> input; std::variant<int, long, double, std::string> myVariant; if(input) myVariant = "Example1"; else myVariant = 3.14; std::visit([](auto&& arg) { std::cout << arg << std::endl; }, myVariant); }

En lugar de c ++ 17 , también puede utilizar boost::variant o boost::any .


Trataré de darte una respuesta práctica que asuma que estás acostumbrado a hacer este tipo de cosas en JavaScript o algo así y solo intentar escribir código en C ++.

Primero, debes entender que en C ++, cout << a . En realidad puede llamar a un método completamente diferente dependiendo del tipo de a . Por esa razón, no tiene ningún sentido escribir cout << a cuando no sabes nada sobre ese tipo. De hecho, no puede hacer nada en absoluto a menos que sepa lo suficiente sobre el tipo de C ++ para decidir qué método u operador desea invocar.

Si ambas clases tienen una base común aceptable, entonces podrías hacer algo como esto:

int main() { base_class *pa; my_class1 a1; my_class2 a2; if(i = 0) { a1 = "Example1"; pa = &a1; } else { a2 = "Example2"; pa = &a2; } cout << *pa << endl; }

Tenga en cuenta que cuando escribe cout << *pa , no está necesariamente llamando al mismo método que cout << a usaría. En el primer caso, está llamando a un método que sabe cómo generar todas las subclases de base_class , mientras que en el segundo caso puede estar llamando a un método que se escribió específicamente para myclass1 o myclass2 .

Cuando no hay una clase base aceptable, simplemente no escribimos código como ese en C ++:

int main() { if(i = 0) { myclass1 a = "Example1"; cout << a << endl; } else { myclass2 a = "Example2"; cout << a << endl; } }

Recuerde que los dos métodos que se llaman en estos casos pueden ser métodos completamente diferentes . Es exactamente como llamar a cout.printClass1(a) contra cout.printClass2(a) . C ++ le permite usar el mismo nombre para métodos completamente diferentes cuando puede averiguar a cuál desea llamar basándose en los tipos de argumentos.

JavaScript no tiene ninguna magia que pueda elegir automáticamente entre printClass1 e printClass2 cuando escribes cout.callWhatever (a), y tampoco C ++. En ambos idiomas, si tiene que llamar a métodos completamente diferentes para myclass1 frente a myclass2 , entonces escribe llamadas diferentes.


Yo mismo tenía ese código, cuando de hecho intentaba diferentes variaciones del mismo código. Entonces me di cuenta de que la mejor opción sería usar un preprocesador #if y resolvió mi problema:

#define VARIATION 2 ... #if VARIATION == 1 myclass1 a = "Example1"; #else myclass2 a = "Example2"; #endif

Sé que probablemente no resuelva el tuyo, pero al menos es una solución.


int main() { auto call = [](auto a) { std::cout << a << std::endl; }; if(i = 0) call(myclass1 { "Example1" }); else call(myclass2 { "Example2" }); }