Capítulo 1: Aspectos Básicos de C++

Programa "básico" de C++. La función main

Práctica 1: En Anjuta, crea un proyecto nuevo, selecciona programa genérico, lenguaje de programación C++, como nombre del proyecto kk (o el que se te antoje).
Una vez creado el proyecto ( lo cual no debe dar problemas, si lo hace consultar capítulo 0), si observamos la ventana del proyecto, aparece el archivo main.cc, pulsamos sobre él, y nos aparecerá en la ventana contigua el siguiente texto:

/* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */
#include <iostream>
int main()
{
     std::cout << "Hello world" << std::endl;
     return 0;
}

Comencemos por explicar las dos primeras líneas:
 /* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */

Estos son comentarios, texto que se introduce en un programa para explicarlo. Es buena práctica ir comentando lo que se hace y por qué, de lo contrario reutilizar o depurar el código pasado un cierto tiempo puede convertirse en tarea imposible (por muy "humano" que sea el C++).

Existen dos formas de hacer comentarios en C++:
  • Una heredada de C, los comentarios comienzan con '/*' y terminan con '*/'. Este tipo de comentario es útil en: 
    • largas explicaciones:
/******************************************************************
   Calcular la media ponderada de la nota de los tres trimestres
el primer trimestre debe tener una valoración del 30 %
el segundo, el más importante, 40%
el tercero el restante 30%
******************************************************************/
    • Modificación de pequeños fragmentos de código. A veces para depurar código, pueden retocarse algunas instrucciones:
std::cout <</*"X =" << x <<*/"Y= " << y;
es igual a
std::cout<<"Y= "<<y;
  • Una segunda específica de C++ donde los comentarios comienzan con '//' y terminan con el final de línea. Las líneas del programa podían haberse sustituido por:
//Created by Anjuta version 1.2.4.a
//This file will not be overwritten

Observa que este segundo comentario no puede modificar pequeños fragmentos de código, salvo que coincidan con el final de línea.

 
#include <iostream>
Un programa es una secuencia de acciones u operaciones realizadas sobre los distintos datos y dispositivos conectados al ordenador.

Existen programas con muy pocas líneas de código y otros con miles, cuando ocurre esto, lo habitual es realizar el programa en varios archivos, para unirlos se utiliza la línea #include.

Nuestro programa, por básico que sea, utiliza una  librería (otros archivos): iostream; la cual nos permite salir por el terminal. Si comentamos la línea (// #include <iostream>), grabamos el archivo, y compilamos(f11), observarás que aparecen unos errores, y no es sino porque nos faltan una líneas de código que se encuentran en el archivo <iostream> (/usr/include/c++/4.0.3/iostream)

int main(){
...
}

También es habitual que si varias instrucciones realizan una acción determinada, y esta se repite con frecuencia, esas instrucciones se agrupen en lo que se denomina una función.
Existe una función especial, única y esencial en todo archivo ejecutable, la función main [main (eng.)-> principal (spa)]. Es la función por la que comienza la ejecución del programa.
Como función que es, el código que almacena se encuentra entre dos llaves {... instrucciones...}
Práctica 2: Antes de seguir explicando el programa anterior, vamos a jugar un poquito modificando el programa, de tal suerte que quede así:

/* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */

#include <iostream>
int main()
{  
    int x;
    int y;
    x=12;
    y=10;
    std::cout << "X= " << x << " Y= " << y << std::endl;
    x=x+y;
    std::cout << "------después de x=x+y--------" << std::endl<<std::endl;
    std::cout << "X= " << x << " Y= " << y << std::endl;
    return 0;
}



Una vez editado (puedes copiar y pegar), graba el archivo, compila (F11) y ejecuta (F3). No debiera haber problemas.

Las variables

Volvamos a nuestro ordenador, a los 0 y 1, nuestro procesador opera con (grandes) memorias y dispositivos  que básicamente contienen 0 y 1.
Para que mi ordenador sepa que la sucesión "0001101010101110" en una determinada posición de la memoria es un número y no una letra o un punto en una foto,... debemos indicarle que tipo de dato es y asignarle un nombre a ese espacio de memoria que nos permita su uso posterior.  

Para ello, en nuestro programa hemos escrito:
int x;
int y;

con esto, reservamos en la memoria del ordenador espacio suficiente para almacenar una secuencia de  0 y 1, las cuales serán interpretadas como dos números enteros (int de integer), uno recibirá el nombre de 'x' y otro el de 'y'.  Esto se denomina declaración de variables (es un paso obligatorio en C y C++) .
------------------------------------------------------------------------------------
x=12;
y=10;

Las siguientes instrucciones asignan a 'x' el valor de 12  (00001100) y a 'y' el valor de 10 (00001010). Estas primeras asignaciones se denominan inicialización. No son obligatorias pero si recomendables, de hecho prueba a insertar la instrucción que utilizamos para salir por pantalla delante de las inicializaciones de x e y, recibirás un mensaje de advertencia al compilar y observa el valor de los datos (en programas complejos esto podría causarnos un error difícil de detectar).
...
int y;
std::cout << "X= " << x << " Y= " << y << std::endl;
x=12;
...

Declaración e inicialización podrían haberse realizado en un solo paso: int x=12;
-----------------------------------------------------------------------------------
x=x+y;

Esta última instrucción puede resultar extraña para un matemático (sin conocimientos informáticos) pero es muy utilizada en programación. Indica al ordenador que sume los valores de las variables 'x' e 'y' (12+10) y el resultado lo almacene nuevamente en 'x'. 'x' e 'y' se pueden sumar porque han sido definidas como variables numéricas, y la suma es una operación definida entre variables numéricas.



Práctica 3: Existe otro tipo predefinido en C y C++, char, (un carácter).  El siguiente programa declara 'x' como una variable entera y a 'y' como una variable char; a 'x' le asigna el valor 64 (01000000), y posteriormente, le asigna a 'y' el valor de 'x'. Al imprimir por el terminal la salida aparece X= 64 Y=@. Si buscas los códigos ascii, verás que la @ es el código nº 64 (¡qué coincidencia!).

#include <iostream>

int main()
{    int x;
    char y;
    x=64;
    y=x;
    std::cout << "X= " << x << " Y= " << y << std::endl;
   
    return 0;
}

Normalmente, en C y C++ la asignación de tipos es advertida, o incluso da error (pruebe a sustituir int x; por double x; -double es una forma de declarar variables numéricas reales- observarás  un aviso).

En C y C++, es fundamental, considerar los tipos de variables. El siguiente programa muestra la diferencia entre dividir dos enteros (resultado un entero) y dividir dos números enteros, considerándolos como reales.


#include <iostream>

int main()
{    int x=23;
    int  y=12;
    std::cout << "int X/Y = " << x/y << std::endl;
    std::cout << "double X/Y = " << (double)x/(double)y << std::endl;   
    return 0;
}


(double)x es una operación denominada cast, que viene a significar que le decimos al compilador que la variable no es real, pero que creemos que se trate como tal.

;

toda instrucción de C++ termina con un punto y coma [;].
Aun cuando no lo parezca, este programa es igual al de la práctica 1:
/* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */

#include <iostream>
int main()
{
    std::cout
    <<
    "Hello world"
    <<
    std::endl;
    return
    0;
}


o este:

#include <iostream>
int main(){    std::cout << "Hello world" << std::endl; return 0;}


Las tabulaciones, retornos,... son una cuestión estética y para facilitar la lectura a nosotros, pero no afecta al código objeto compilado.

Es un error frecuente (en mi caso mucho más) olvidarse de colocar un ';' al final de una instrucción.
¿Pero... #include?
Ciertamente la línea de #include no tiene un ';' , esto es así porque no es código ejecutable en sí, es una directiva para que al compilar el archivo previamente se incluya el código del archivo específicado. Por ello se les denomina directivas del preprocesador, y se reconocen porque vienen precedidas por el símbolo #.
¿ y main?
Como hemos dicho las funciones son una agrupación de código entre dos llaves {...}, dentro de ellas existen instrucciones ejecutables (con sus respectivos ;), pero ellas en sí no lo son. Mejor con un poco de práctica.
Práctica 3: Modifiquemos el programa de esta forma:

/* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */

#include <iostream>
int suma (int,int);
int main()
{    int x,y;
    x=12;
    y=10;
    std::cout << "X= " << x << " Y= " << y << std::endl;
    x=suma(y,y);
    std::cout << "------después de x=x+y--------" << std::endl<<std::endl;
    std::cout << "X= " << x << " Y= " << y << std::endl;
    return 0;
}
int suma (int x, int y)
{
    return x+y;
}
NOTA: Recuerda que para compilar de nuevo es suficiente pulsar F11, y luego F3.
Pero ANTES es necesario GRABAR el archivo.
int suma (int,int);

Es la declaración de la función, o más exactamente el prototipado, le dice al compilador que se va a utilizar una función denominada suma, que acepta dos valores de tipo integer, y devuelve como resultados de la operación otro integer.
(prueba a borrar esta línea y compila el proyecto... te aparecerá un mensaje de error diciéndote que suma no es conocida en el ámbito de main)

int suma (int x, int y)
{
    return x+y;
}

Es la definición de la función, donde se encuentra el código, en este caso una única instrucción. return es una palabra clave utilizada para devolver el valor. En nuestra función devuelve la suma de las dos variables, y en el caso de main devuelve 0 (0 es el valor utilizado para comunicar al sistema que el programa a terminado con éxito, se pueden devolver otros valores).

x=suma(y,y);

Es una asignación que llama a la función suma con dos parámetros y el resultado de esta es asignado a la variable x. Aquí tras suma si ponemos ; porque no se está definiendo sino que se esta ejecutando.

ATENCIÓN: Observa que la 'x' e 'y' de main, y la 'x' e 'y' de suma son diferentes.  Llamamos a suma con dos 'y'-de main-, esto es  suma (10, 10). A la variable 'x' de la función suma, y a la 'y', se le asigna el valor 10, por lo que el resultado devuelto es 20.


C++, algo más que un paso adelante

Hemos hablado de las asignaciones, existe una muy habitual en informática:
x=x+1;
que en C y otros lenguajes puede expresarse como:
x++;

Es fácil entender así el significado de C++, ( lenguaje basado en C), pero que aspira a avanzar un paso más.

Todos los lenguajes de programación, vienen con unos tipos predefinidos (más o menos igual en todos ellos). El usuario puede crear nuevos datos que son una combinación de los datos predefinidos. Por ejemplo, podemos definir un tipo de variable punto, que almacena dos enteros 'x' e 'y', para realizar operaciones con puntos debemos crear funciones. Veamos el siguiente ejemplo:
/* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */

#include <iostream>
// la palabra struct crea un nuevo tipo de dato, en este caso denominado punto.
// que tiene dos variables enteras
struct punto{
    int x;
    int y;
};
// prototipo de las funciones utilizadas, observa los valores de retorno
punto asigna(int,int); // devuelve una estructura punto
punto suma (punto,punto);// devuelve un punto
void imprimir(punto);// no devuelve ningun valor, solo realiza instrucciones.
int main()
{    punto A;// declaración de una variable punto definida por nosotros
    punto B;
    A=asigna(3,7);// llamada a la función asigna, que devuelve un punto
    B=asigna(10,3);
    imprimir(A);// llamada a la función imprimir
    imprimir(B);
    B=suma(A,B);// llamada a la función suma, que devuelve un punto
    imprimir(B);   
    return 0;
}
punto asigna(int j, int i){
    punto Z;
    Z.x=j; // para acceder a un elemento de la estructura se utiliza el operador '.'
    Z.y=i;
    return Z;
}
void imprimir (punto Z){

    std::cout<< "X= "<< Z.x <<" Y = "<< Z.y<<std::endl;
}
punto suma (punto Z, punto M){
   punto R;
   R.x=Z.x+M.x;
   R.y=Z.y+M.y;
   return R;
}

C++, incorpora innumerables ventajas a C, entre ellas, esta la sobrecarga de los operadores, lo que permite a un usuario crear datos con operaciones similares a las predefinidas por el compilador, de tal suerte que nuestra función main quedará así:
int main()
{    punto A(3,7);// declaración de una variable punto definida por nosotros
    punto B(10,3);
    std::cout <<A;
    std::cout<<B;
    B=A+B;// o incluso B=+A;
    std::cout<<B;   
    return 0;
}


 El código completo:
/* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */

#include <iostream>

class punto{
     int x;
     int y;
    public:
     punto(int,int);
     punto operator + (punto);
     friend std::ostream& operator << (std::ostream&,punto);
};

// funcion main ligeramente modificada

int main() 
{    punto A(7,7);
    punto B(10,3);
    std::cout<<"A es igual: "<<A<<std::endl;
    std::cout<<"B es igual: "<<B<<std::endl;
    B= A + B;
    std::cout<<"Tras la suma:"<<std::endl<<std::endl;
    std::cout<<"A es igual: "<<A<<std::endl;
    std::cout<<"B es igual: "<<B<<std::endl;
    return 0;
}
punto::punto(int j, int i){
    x=j;
    y=i;
}
punto punto::operator+ (punto P){
    return punto(x+P.x,y+P.y);
}
std::ostream& operator << (std::ostream& os, punto P){

    os<< "X= "<< P.x <<";  Y = "<< P.y<<";"<<std::endl;
return os;
}


Lo habitual es que la definición del nuevo dato, la clase se realice en otro archivo (punto.h y punto.cc) y añadamos una directiva #include "punto.h" al ejecutable. Asi el archivo main.cc quedaría así:

/* Created by Anjuta version 1.2.4a */
/*    This file will not be overwritten */

#include <iostream>
#include "punto.h"

int main() //ligeramente modificado
{    punto A(7,7);
    punto B(10,3);
    std::cout<<"A es igual: "<<A<<std::endl;
    std::cout<<"B es igual: "<<B<<std::endl;
    B= A + B;
    std::cout<<"Tras la suma:"<<std::endl<<std::endl;
    std::cout<<"A es igual: "<<A<<std::endl;
    std::cout<<"B es igual: "<<B<<std::endl;
    return 0;
}


El archivo punto.h
#include <iostream>

class punto{
     int x;
     int y;
    public:
     punto(int,int);
     punto operator + (punto);
     friend std::ostream& operator << (std::ostream&,punto);
}
;

El archivo punto.cc
#include <iostream>
#include "punto.h"

punto::punto(int j, int i){
    x=j;
    y=i;
}
punto punto::operator+ (punto P){
    return punto(x+P.x,y+P.y);
}
std::ostream& operator << (std::ostream& os, punto P){

    os<< "X= "<< P.x <<";  Y = "<< P.y<<";"<<std::endl;
return os;
}


Para editar los ficheros, en el menú de Anjuta: Archivo, Nuevo (c++ header para punto.h y c++ source para punto.cc).
Pero para modificar el proyecto (cosa que hemos dejado a Anjuta) debemos primero "limpiar todo" del menu construir. Luego debemos añadir los archivos al proyecto (en el menu proyecto, añadir archivo, archivo de código fuente). Posteriormente, Construir->Auto generar. Y finalmente compilar y ejecutar

Hay cosas que no he explicado del programa básico, como los :: , pero todo se andará. Me interesa más que hayas visto el potencial de C++ para ir desarrollando estructuras más complejas, reutilizables como las librerias de GTK y GNOME que tanto nos costo instalar. Vayamos a ello.