C++ Tutorial
Empezando con C ++
Buscar..
Observaciones
El programa 'Hello World' es un ejemplo común que se puede usar simplemente para verificar la presencia del compilador y la biblioteca. Utiliza la biblioteca estándar de C ++, con std::cout
de <iostream>
, y solo tiene que compilar un archivo, lo que minimiza la posibilidad de un error de usuario durante la compilación.
El proceso para compilar un programa C ++ difiere inherentemente entre compiladores y sistemas operativos. El tema Compilación y creación contiene los detalles sobre cómo compilar el código C ++ en diferentes plataformas para una variedad de compiladores.
Versiones
Versión | Estándar | Fecha de lanzamiento |
---|---|---|
C ++ 98 | ISO / IEC 14882: 1998 | 1998-09-01 |
C ++ 03 | ISO / IEC 14882: 2003 | 2003-10-16 |
C ++ 11 | ISO / IEC 14882: 2011 | 2011-09-01 |
C ++ 14 | ISO / IEC 14882: 2014 | 2014-12-15 |
C ++ 17 | TBD | 2017-01-01 |
C ++ 20 | TBD | 2020-01-01 |
Hola Mundo
Este programa imprime Hello World!
al flujo de salida estándar:
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
}
Análisis
Examinemos cada parte de este código en detalle:
#include <iostream>
es una directiva de preprocesador que incluye el contenido del archivo de cabecera estándar de C ++iostream
.iostream
es un archivo de encabezado de biblioteca estándar que contiene definiciones de los flujos de entrada y salida estándar. Estas definiciones se incluyen en elstd
nombresstd
, que se explica a continuación.Los flujos de entrada / salida (E / S) estándar proporcionan formas para que los programas obtengan entrada y salgan a un sistema externo, generalmente el terminal.
int main() { ... }
define una nueva función llamadamain
. Por convención, la funciónmain
se llama a la ejecución del programa. Sólo debe haber una funciónmain
en un programa de C ++, y siempre debe devolver un número del tipoint
.Aquí, el
int
es lo que se llama el tipo de retorno de la función. El valor devuelto por la funciónmain
es un código de salida.Por convención, un sistema que ejecuta el programa interpreta como exitoso un código de salida del programa
0
oEXIT_SUCCESS
. Cualquier otro código de retorno está asociado con un error.Si no hay ninguna declaración de
return
, la funciónmain
(y, por lo tanto, el propio programa) devuelve0
de forma predeterminada. En este ejemplo, no necesitamos escribir explícitamente lareturn 0;
.Todas las demás funciones, excepto aquellas que devuelven el tipo
void
, deben devolver explícitamente un valor de acuerdo con su tipo de retorno, o de lo contrario no deben devolverlo en absoluto.
std::cout << "Hello World!" << std::endl;
grabados "¡Hola mundo!" al flujo de salida estándar:std
es un espacio de nombres , y::
es el operador de resolución de alcance que permite buscar objetos por nombre dentro de un espacio de nombres.Hay muchos espacios de nombres. Aquí, usamos
::
para mostrar que queremos usarcout
desde elstd
nombresstd
. Para obtener más información, consulte Operador de resolución de alcance - Documentación de Microsoft .std::cout
es el objeto de flujo de salida estándar , definido eniostream
, y se imprime en la salida estándar (stdout
).<<
es, en este contexto , el operador de inserción de flujo , llamado así porque inserta un objeto en el objeto de flujo .La biblioteca estándar define el operador
<<
para realizar la inserción de datos para ciertos tipos de datos en flujos de salida.stream << content
inserta elcontent
en el flujo y devuelve lo mismo, pero el flujo actualizado. Esto permite encadenar inserciones de secuencias:std::cout << "Foo" << " Bar";
Imprime "FooBar" en la consola."Hello World!"
es una cadena de caracteres literal , o un "texto literal". El operador de inserción de flujo para los literales de cadena de caracteres se define en el archivoiostream
.std::endl
es un objeto especial de manipulador de flujo de E / S , también definido en el archivoiostream
. Insertar un manipulador en un flujo cambia el estado del flujo.El manipulador de flujo
std::endl
hace dos cosas: primero inserta el carácter de fin de línea y luego vacía el búfer del flujo para forzar que el texto aparezca en la consola. Esto asegura que los datos insertados en la transmisión realmente aparezcan en su consola. (Los datos de transmisión generalmente se almacenan en un búfer y luego se "descargan" en lotes, a menos que se fuerce un vaciado de inmediato).Un método alternativo que evita la descarga es:
std::cout << "Hello World!\n";
donde
\n
es la secuencia de escape de caracteres para el carácter de nueva línea.El punto y coma (
;
) notifica al compilador que una declaración ha finalizado. Todas las declaraciones de C ++ y las definiciones de clase requieren un punto y coma finalizado.
Comentarios
Un comentario es una forma de colocar texto arbitrario dentro del código fuente sin que el compilador de C ++ lo interprete con un significado funcional. Los comentarios se utilizan para dar una idea del diseño o método de un programa.
Hay dos tipos de comentarios en C ++:
Comentarios de una sola línea
La secuencia de doble barra diagonal hacia adelante //
marcará todo el texto hasta que aparezca una nueva línea como comentario:
int main()
{
// This is a single-line comment.
int a; // this also is a single-line comment
int i; // this is another single-line comment
}
C-Style / Block Comentarios
La secuencia /*
se usa para declarar el inicio del bloque de comentarios y la secuencia */
se usa para declarar el final del comentario. Todo el texto entre las secuencias de inicio y finalización se interpreta como un comentario, incluso si el texto es de otro modo una sintaxis de C ++ válida. Estos a veces se denominan comentarios de "estilo C", ya que esta sintaxis de comentario se hereda del lenguaje predecesor de C ++, C:
int main()
{
/*
* This is a block comment.
*/
int a;
}
En cualquier comentario de bloque, puedes escribir lo que quieras. Cuando el compilador encuentra el símbolo */
, termina el comentario de bloque:
int main()
{
/* A block comment with the symbol /*
Note that the compiler is not affected by the second /*
however, once the end-block-comment symbol is reached,
the comment ends.
*/
int a;
}
El ejemplo anterior es un código válido de C ++ (y C). Sin embargo, tener /*
adicional dentro de un comentario de bloque puede dar como resultado una advertencia en algunos compiladores.
Los comentarios en bloque también pueden comenzar y terminar dentro de una sola línea. Por ejemplo:
void SomeFunction(/* argument 1 */ int a, /* argument 2 */ int b);
Importancia de los comentarios
Al igual que con todos los lenguajes de programación, los comentarios proporcionan varios beneficios:
- Documentación explícita de código para facilitar la lectura / mantenimiento
- Explicación del propósito y funcionalidad del código.
- Detalles sobre la historia o razonamiento detrás del código.
- Colocación de derechos de autor / licencias, notas de proyectos, agradecimientos especiales, créditos de contribuyentes, etc. directamente en el código fuente.
Sin embargo, los comentarios también tienen sus desventajas:
- Deben mantenerse para reflejar cualquier cambio en el código.
- Los comentarios excesivos tienden a hacer que el código sea menos legible
La necesidad de comentarios se puede reducir escribiendo un código claro y autodocumentado. Un ejemplo simple es el uso de nombres explicativos para variables, funciones y tipos. Factorizar tareas relacionadas lógicamente en funciones discretas va de la mano con esto.
Marcadores de comentario utilizados para deshabilitar el código
Durante el desarrollo, los comentarios también se pueden usar para deshabilitar rápidamente partes del código sin borrarlo. A menudo, esto es útil para propósitos de prueba o depuración, pero no es un buen estilo para nada que no sean ediciones temporales. Esto a menudo se conoce como "comentar".
Del mismo modo, mantener las versiones antiguas de un fragmento de código en un comentario con fines de referencia es desagradable, ya que desordena los archivos al tiempo que ofrece poco valor en comparación con la exploración del historial del código a través de un sistema de versiones.
Función
Una función es una unidad de código que representa una secuencia de sentencias.
Las funciones pueden aceptar argumentos o valores y devolver un solo valor (o no). Para usar una función, una llamada de función se usa en valores de argumento y el uso de la llamada de función se reemplaza con su valor de retorno.
Cada función tiene una firma de tipo : los tipos de sus argumentos y el tipo de su tipo de retorno.
Las funciones están inspiradas en los conceptos del procedimiento y la función matemática.
- Nota: las funciones de C ++ son esencialmente procedimientos y no siguen la definición exacta o las reglas de las funciones matemáticas.
Las funciones a menudo están destinadas a realizar una tarea específica. y puede ser llamado desde otras partes de un programa. Una función debe ser declarada y definida antes de ser llamada en otro lugar en un programa.
- Nota: las definiciones de funciones populares pueden estar ocultas en otros archivos incluidos (a menudo por conveniencia y reutilización en muchos archivos). Este es un uso común de los archivos de encabezado.
Declaración de funciones
Una declaración de función declara la existencia de una función con su nombre y tipo de firma para el compilador. La sintaxis es la siguiente:
int add2(int i); // The function is of the type (int) -> (int)
En el ejemplo anterior, la función int add2(int i)
declara lo siguiente al compilador:
- El tipo de retorno es
int
. - El nombre de la función es
add2
. - El número de argumentos a la función es 1:
- El primer argumento es del tipo
int
. - El primer argumento se mencionará en el contenido de la función con el nombre
i
.
- El primer argumento es del tipo
El nombre del argumento es opcional; La declaración para la función también podría ser la siguiente:
int add2(int); // Omitting the function arguments' name is also permitted.
Según la regla de una definición , una función con un cierto tipo de firma solo se puede declarar o definir una vez en una base de código C ++ completa visible para el compilador de C ++. En otras palabras, las funciones con una firma de tipo específica no se pueden redefinir, solo deben definirse una vez. Por lo tanto, lo siguiente no es válido en C ++:
int add2(int i); // The compiler will note that add2 is a function (int) -> int
int add2(int j); // As add2 already has a definition of (int) -> int, the compiler
// will regard this as an error.
Si una función no devuelve nada, su tipo de retorno se escribe como void
. Si no toma parámetros, la lista de parámetros debe estar vacía.
void do_something(); // The function takes no parameters, and does not return anything.
// Note that it can still affect variables it has access to.
Llamada de función
Una función puede ser llamada después de que haya sido declarada. Por ejemplo, el siguiente programa llama a add2
con el valor de 2
dentro de la función de main
:
#include <iostream>
int add2(int i); // Declaration of add2
// Note: add2 is still missing a DEFINITION.
// Even though it doesn't appear directly in code,
// add2's definition may be LINKED in from another object file.
int main()
{
std::cout << add2(2) << "\n"; // add2(2) will be evaluated at this point,
// and the result is printed.
return 0;
}
Aquí, add2(2)
es la sintaxis de una llamada de función.
Definición de la función
Una definición de función * es similar a una declaración, excepto que también contiene el código que se ejecuta cuando se llama a la función dentro de su cuerpo.
Un ejemplo de una definición de función para add2
podría ser:
int add2(int i) // Data that is passed into (int i) will be referred to by the name i
{ // while in the function's curly brackets or "scope."
int j = i + 2; // Definition of a variable j as the value of i+2.
return j; // Returning or, in essence, substitution of j for a function call to
// add2.
}
Sobrecarga de funciones
Puedes crear múltiples funciones con el mismo nombre pero diferentes parámetros.
int add2(int i) // Code contained in this definition will be evaluated
{ // when add2() is called with one parameter.
int j = i + 2;
return j;
}
int add2(int i, int j) // However, when add2() is called with two parameters, the
{ // code from the initial declaration will be overloaded,
int k = i + j + 2 ; // and the code in this declaration will be evaluated
return k; // instead.
}
Ambas funciones se llaman con el mismo nombre add2
, pero la función real que se llama depende directamente de la cantidad y el tipo de los parámetros en la llamada. En la mayoría de los casos, el compilador de C ++ puede calcular qué función llamar. En algunos casos, el tipo debe ser explícitamente establecido.
Parámetros predeterminados
Los valores predeterminados para los parámetros de función solo se pueden especificar en las declaraciones de función.
int multiply(int a, int b = 7); // b has default value of 7.
int multiply(int a, int b)
{
return a * b; // If multiply() is called with one parameter, the
} // value will be multiplied by the default, 7.
En este ejemplo, se puede llamar a multiply()
con uno o dos parámetros. Si solo se proporciona un parámetro, b
tendrá un valor predeterminado de 7. Los argumentos predeterminados se deben colocar en los últimos argumentos de la función. Por ejemplo:
int multiply(int a = 10, int b = 20); // This is legal
int multiply(int a = 10, int b); // This is illegal since int a is in the former
Llamadas de Funciones Especiales - Operadores
Existen llamadas a funciones especiales en C ++ que tienen una sintaxis diferente a name_of_function(value1, value2, value3)
. El ejemplo más común es el de los operadores.
Ciertas secuencias de caracteres especiales que se reducirán a las llamadas de función del compilador, como !
, +
, -
, *
, %
y <<
y muchos más. Estos caracteres especiales se asocian normalmente con el uso no programado o se usan para la estética (por ejemplo, el carácter +
se reconoce comúnmente como el símbolo de adición tanto en la programación en C ++ como en matemáticas elementales).
C ++ maneja estas secuencias de caracteres con una sintaxis especial; pero, en esencia, cada aparición de un operador se reduce a una llamada de función. Por ejemplo, la siguiente expresión en C ++:
3+3
es equivalente a la siguiente llamada de función:
operator+(3, 3)
Todos los nombres de funciones del operador comienzan con el operator
.
Mientras que en el predecesor inmediato de C ++, C, a los nombres de funciones de operador no se les pueden asignar diferentes significados al proporcionar definiciones adicionales con diferentes tipos de firmas, en C ++, esto es válido. "Ocultar" las definiciones de funciones adicionales bajo un nombre de función único se conoce como sobrecarga de operadores en C ++, y es una convención relativamente común, pero no universal, en C ++.
Visibilidad de prototipos y declaraciones de funciones.
En C ++, el código debe ser declarado o definido antes de su uso. Por ejemplo, lo siguiente produce un error de tiempo de compilación:
int main()
{
foo(2); // error: foo is called, but has not yet been declared
}
void foo(int x) // this later definition is not known in main
{
}
Hay dos formas de resolver esto: poner la definición o la declaración de foo()
antes de su uso en main()
. Aquí hay un ejemplo:
void foo(int x) {} //Declare the foo function and body first
int main()
{
foo(2); // OK: foo is completely defined beforehand, so it can be called here.
}
Sin embargo, también es posible "declarar hacia adelante" la función poniendo solo una declaración "prototipo" antes de su uso y luego definiendo el cuerpo de la función más adelante:
void foo(int); // Prototype declaration of foo, seen by main
// Must specify return type, name, and argument list types
int main()
{
foo(2); // OK: foo is known, called even though its body is not yet defined
}
void foo(int x) //Must match the prototype
{
// Define body of foo here
}
El prototipo debe especificar el tipo de retorno ( void
), el nombre de la función ( foo
) y los tipos de variables de la lista de argumentos ( int
), pero los nombres de los argumentos NO son necesarios .
Una forma común de integrar esto en la organización de los archivos de origen es hacer un archivo de encabezado que contenga todas las declaraciones de prototipo:
// foo.h
void foo(int); // prototype declaration
y luego proporcionar la definición completa en otro lugar:
// foo.cpp --> foo.o
#include "foo.h" // foo's prototype declaration is "hidden" in here
void foo(int x) { } // foo's body definition
y luego, una vez compilado, vincule el archivo de objeto correspondiente foo.o
al archivo de objeto compilado donde se usa en la fase de enlace, main.o
:
// main.cpp --> main.o
#include "foo.h" // foo's prototype declaration is "hidden" in here
int main() { foo(2); } // foo is valid to call because its prototype declaration was beforehand.
// the prototype and body definitions of foo are linked through the object files
Se produce un error de "símbolo externo no resuelto" cuando existen la función prototipo y la llamada , pero el cuerpo de la función no está definido. Estos pueden ser más difíciles de resolver ya que el compilador no informará el error hasta la etapa final de vinculación, y no sabe a qué línea saltar en el código para mostrar el error.
El proceso de compilación estándar de C ++.
El código del programa ejecutable de C ++ generalmente es producido por un compilador.
Un compilador es un programa que traduce código de un lenguaje de programación a otra forma que es (más) directamente ejecutable para una computadora. Usar un compilador para traducir código se llama compilación.
C ++ hereda la forma de su proceso de compilación de su lenguaje "principal", C. A continuación se muestra una lista que muestra los cuatro pasos principales de la compilación en C ++:
- El preprocesador de C ++ copia el contenido de cualquier archivo de encabezado incluido en el archivo de código fuente, genera un código de macro y reemplaza las constantes simbólicas definidas usando #define con sus valores.
- El archivo de código fuente expandido producido por el preprocesador C ++ se compila en lenguaje ensamblador apropiado para la plataforma.
- El código del ensamblador generado por el compilador se ensambla en el código de objeto apropiado para la plataforma.
- El archivo de código de objeto generado por el ensamblador está vinculado junto con los archivos de código de objeto para cualquier función de biblioteca utilizada para producir un archivo ejecutable.
- Nota: algunos códigos compilados están vinculados entre sí, pero no para crear un programa final. Por lo general, este código "vinculado" también se puede empaquetar en un formato que puede ser usado por otros programas. Este "paquete de código empaquetado y utilizable" es lo que los programadores de C ++ denominan una biblioteca.
Muchos compiladores de C ++ también pueden combinar o deshacer ciertas partes del proceso de compilación para facilitar o para un análisis adicional. Muchos programadores de C ++ usarán diferentes herramientas, pero todas las herramientas generalmente seguirán este proceso generalizado cuando estén involucrados en la producción de un programa.
El siguiente enlace extiende esta discusión y proporciona un bonito gráfico para ayudar. [1]: http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html
Preprocesador
El preprocesador es una parte importante del compilador.
Edita el código fuente, recorta algunos bits, cambia otros y agrega otras cosas.
En los archivos de origen, podemos incluir directivas de preprocesador. Estas directivas le indican al preprocesador que realice acciones específicas. Una directiva comienza con un # en una nueva línea. Ejemplo:
#define ZERO 0
La primera directiva de preprocesador que encontrará es probablemente la
#include <something>
directiva. Lo que hace es toma todos something
y lo inserta en el archivo de donde estaba la directiva. El programa hola mundo comienza con la línea.
#include <iostream>
Esta línea agrega las funciones y objetos que le permiten usar la entrada y salida estándar.
El lenguaje C, que también utiliza el preprocesador, no tiene tantos archivos de encabezado como el lenguaje C ++, pero en C ++ puede usar todos los archivos de encabezado C.
La siguiente directiva importante es probablemente la
#define something something_else
directiva. Esto le dice al preprocesador que a medida que avanza en el archivo, debe reemplazar cada ocurrencia de something
con something_else
. También puede hacer cosas similares a las funciones, pero eso probablemente cuenta como C ++ avanzado.
El something_else
no es necesario, pero si se define something
como nada, entonces fuera de las directivas de preprocesador, todas las apariciones de something
se desvanecerá.
En realidad, esto es útil, debido a las #if
, #else
y #ifdef
directivas. El formato para estos sería el siguiente:
#if something==true
//code
#else
//more code
#endif
#ifdef thing_that_you_want_to_know_if_is_defined
//code
#endif
Estas directivas insertan el código que está en el bit verdadero y borran los bits falsos. Esto se puede usar para tener bits de código que solo se incluyen en ciertos sistemas operativos, sin tener que volver a escribir todo el código.