No, you can not.
Yes, it can be done in languages that support reflection.
But C ++ does not support reflection. Supports RTTI, which is a subset of reflection, but it is not enough to do this.
Yes you can from a functional point of view.
You can implement this functionality for the user. The appropriate tool is the dictionary, std :: map in C ++. Trauma gives an example of use in your answer . You will not have variables added to the program at the level of the language code, but at the data level, but this is not important.
Yes you can.
With a program that modifies itself.
The following program allows the user to add new variables, assign them values and print their sum.
When the user enters a new variable name, the program copies its own C ++ code that is in a template file and adds the necessary lines for the new variables. Then compile the program and run the new program replacing the old one.
The program needs 4 auxiliary files.
It is made with GNU g ++ on linux, but it can be adapted to any system.
I have used names of variables and functions that start with _
so that they do not conflict with those used by the user. But there are also prohibited variable names like int
or main
. This is detected because the program does not compile.
If someone happens to use this crazy idea for real software, you should bear in mind that it is vulnerable to C ++ injection attacks.
The program programa.cpp:
#include <unistd.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
// Variables definidas por el usuario
// Lista de nombres de variables
std::vector<std::string> _nombresVar;
int* _obtenerPuntero( std::string _nombre) {
auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
int _pos = _it - _nombresVar.begin();
switch ( _pos ) {
}
}
void _componerListaNombresDeVariable() {
}
std::string _pideNombre()
{
std::cout << "Introduzca nombre de variable:";
std::string _nombre;
std::cin >> _nombre;
return _nombre;
}
void _crearCodigoCpp( std::string _nombreNuevaVar ) {
std::ofstream _fich;
system( "rm -f prog generado.cpp");
system( "cat plantilla1.cpp >> generado.cpp");
// Escribir codigo que declara las variables.
_fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
_fich << "int " << *_it << " = " << *_obtenerPuntero(*_it) << ";\n";
_fich << "int " << _nombreNuevaVar << " = 0;\n";
_fich.close();
system( "cat plantilla2.cpp >> generado.cpp");
// Escribir codigo para obtener un puntero a una variable. Usado por _obtenerPuntero()
_fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
for ( int _i = 0; _i<_nombresVar.size(); ++ _i )
_fich << "case " << _i << ": return &" << _nombresVar[_i] << ";\n";
_fich << "case " << _nombresVar.size() << ": return &" << _nombreNuevaVar << ";\n";
_fich.close();
system( "cat plantilla3.cpp >> generado.cpp");
// Escribir codigo que añade nombres de variables a la lista.
_fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
_fich << "_nombresVar.push_back(\"" << *_it << "\");\n";
_fich << "_nombresVar.push_back(\"" << _nombreNuevaVar << "\");\n";
_fich.close();
system( "cat plantilla4.cpp >> generado.cpp");
}
void _anyadirVar() {
std::string _nombre = _pideNombre();
auto it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
if ( it!=_nombresVar.end() ) {
std::cout << "¡Incorrecto! Ese nombre ya está usado.\n";
throw 1;
}
_crearCodigoCpp(_nombre);
int _res = system( "g++ -std=c++11 -o generado generado.cpp > /dev/null 2>/dev/null");
if ( _res!=0 ) {
std::cout << "No se puede usar ese nombre de variable.\n";
throw 1;
}
_nombresVar.push_back(_nombre);
execl( "./generado", NULL);
}
void _asignarValor() {
std::string _nombre = _pideNombre();
auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
if ( _it==_nombresVar.end() ) {
std::cout << "¡Incorrecto! Esa variable no existe.\n";
throw 1;
}
int _valor;
std::cout << "Introduzca valor entero:";
std::cin >> _valor;
if ( std::cin.fail() )
throw 2;
int* _p = _obtenerPuntero( _nombre );
*_p = _valor;
}
void _calcularSuma() {
int _suma = 0;
for ( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it )
_suma += *_obtenerPuntero(*_it);
std::cout << "Las variables suman " << _suma << "\n";
}
int main() {
_componerListaNombresDeVariable();
for(;;) {
try {
std::cout << "Elija opción y pulse INTRO:\n";
std::cout << "1.- Añadir variable\n";
std::cout << "2.- Asignar valor a variable\n";
std::cout << "3.- Calcular suma\n";
std::cout << "4.- Salir\n";
std::cout << "Opcion:" << std::flush;
int _opcion;
std::cin >> _opcion;
if ( std::cin.fail())
throw 2;
switch ( _opcion ) {
case 1: _anyadirVar(); break;
case 2: _asignarValor(); break;
case 3: _calcularSuma(); break;
case 4: return 0;
default :
std::cout << "Opcion incorrecta\n";
}
}
catch( int _err ) {
if ( _err==2 ) {
std::cout << "Eso no es un numero\n";
std::cin.clear();
std::cin.ignore(256,'\n');
}
}
}
return 0;
}
File template1.cpp:
#include <unistd.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
// Variables definidas por el usuario
File template2.cpp:
// Lista de nombres de variables
std::vector<std::string> _nombresVar;
int* _obtenerPuntero( std::string _nombre) {
auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
int _pos = _it - _nombresVar.begin();
switch ( _pos ) {
File template3.cpp:
}
}
void _componerListaNombresDeVariable() {
File template4.cpp:
}
std::string _pideNombre()
{
std::cout << "Introduzca nombre de variable:";
std::string _nombre;
std::cin >> _nombre;
return _nombre;
}
void _crearCodigoCpp( std::string _nombreNuevaVar ) {
std::ofstream _fich;
system( "rm -f prog generado.cpp");
system( "cat plantilla1.cpp >> generado.cpp");
// Escribir codigo que declara las variables.
_fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
_fich << "int " << *_it << " = " << *_obtenerPuntero(*_it) << ";\n";
_fich << "int " << _nombreNuevaVar << " = 0;\n";
_fich.close();
system( "cat plantilla2.cpp >> generado.cpp");
// Escribir codigo para obtener un puntero a una variable. Usado por _obtenerPuntero()
_fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
for ( int _i = 0; _i<_nombresVar.size(); ++ _i )
_fich << "case " << _i << ": return &" << _nombresVar[_i] << ";\n";
_fich << "case " << _nombresVar.size() << ": return &" << _nombreNuevaVar << ";\n";
_fich.close();
system( "cat plantilla3.cpp >> generado.cpp");
// Escribir codigo que añade nombres de variables a la lista.
_fich.open ("generado.cpp", std::ofstream::out | std::ofstream::app);
for( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it)
_fich << "_nombresVar.push_back(\"" << *_it << "\");\n";
_fich << "_nombresVar.push_back(\"" << _nombreNuevaVar << "\");\n";
_fich.close();
system( "cat plantilla4.cpp >> generado.cpp");
}
void _anyadirVar() {
std::string _nombre = _pideNombre();
auto it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
if ( it!=_nombresVar.end() ) {
std::cout << "¡Incorrecto! Ese nombre ya está usado.\n";
throw 1;
}
_crearCodigoCpp(_nombre);
int _res = system( "g++ -std=c++11 -o generado generado.cpp > /dev/null 2>/dev/null");
if ( _res!=0 ) {
std::cout << "No se puede usar ese nombre de variable.\n";
throw 1;
}
_nombresVar.push_back(_nombre);
execl( "./generado", NULL);
}
void _asignarValor() {
std::string _nombre = _pideNombre();
auto _it = std::find(_nombresVar.begin(), _nombresVar.end(), _nombre);
if ( _it==_nombresVar.end() ) {
std::cout << "¡Incorrecto! Esa variable no existe.\n";
throw 1;
}
int _valor;
std::cout << "Introduzca valor entero:";
std::cin >> _valor;
if ( std::cin.fail() )
throw 2;
int* _p = _obtenerPuntero( _nombre );
*_p = _valor;
}
void _calcularSuma() {
int _suma = 0;
for ( auto _it=_nombresVar.begin(); _it!=_nombresVar.end(); ++_it )
_suma += *_obtenerPuntero(*_it);
std::cout << "Las variables suman " << _suma << "\n";
}
int main() {
_componerListaNombresDeVariable();
for(;;) {
try {
std::cout << "Elija opción y pulse INTRO:\n";
std::cout << "1.- Añadir variable\n";
std::cout << "2.- Asignar valor a variable\n";
std::cout << "3.- Calcular suma\n";
std::cout << "4.- Salir\n";
std::cout << "Opcion:" << std::flush;
int _opcion;
std::cin >> _opcion;
if ( std::cin.fail())
throw 2;
switch ( _opcion ) {
case 1: _anyadirVar(); break;
case 2: _asignarValor(); break;
case 3: _calcularSuma(); break;
case 4: return 0;
default :
std::cout << "Opcion incorrecta\n";
}
}
catch( int _err ) {
if ( _err==2 ) {
std::cout << "Eso no es un numero\n";
std::cin.clear();
std::cin.ignore(256,'\n');
}
}
}
return 0;
}