Está en la página 1de 14

4.

1 FUNCIONES DE BIBLIOTECA
Junto con los compiladores de C y C++, se incluyen ciertos archivos llamados
bibliotecas mas comúnmente librerías. Las bibliotecas contienen el código objeto
de muchos programas que permiten hacer cosas comunes, como leer el teclado,
escribir en la pantalla, manejar números, realizar funciones matemáticas, etc.

Las bibliotecas están clasificadas por el tipo de trabajos que hacen, hay bibliotecas
de entrada y salida, matemáticas, de manejo de memoria, de manejo de textos y
como imaginarás existen muchísimas librerías disponibles y todas con una función
especifica.

Nota: Existe una discusión sobre el nombre de estos archivos. Muchos personas


consideran que el nombre adecuado es archivos de biblioteca, y estan en lo
correcto. Sin embargo, la mayoría llamamos a estos archivos librerías, y también
me incluyo entre estos. El error proviene del nombre en inglés, que es library. Este
término se traduce como biblioteca, y no como librería. De este modo a lo largo de
esta sección las llamaré de cualquiera de las dos formas, para estár mas claros.

sólo usaremos algunas bibliotecas (o librerías) ANSI.

Nota 2: Sé que esto pinta aburrido, pero es muy útil y las librerías nos facilitan
enormemente el trabajo a la hora de programar. Recuerda que antes de hablar
librerías y demás es necesario dominar algunos conceptos de fundamentación en
general y otros temas importantes (ciclos, condicionales y demás) Ahora veamos
algunas librerías y como es su sintaxis.X

¿Qué son exactamente las librerías?


En C++, se conoce como librerías (o bibliotecas) a cierto tipo de archivos que
podemos importar o incluir en nuestro programa. Estos archivos contienen las
especificaciones de diferentes funcionalidades ya construidas y utilizables que
podremos agregar a nuestro programa, como por ejemplo leer del teclado o
mostrar algo por pantalla entre muchas otras más.

Al poder incluir estas librerías con definiciones de diferentes funcionalidades


podremos ahorrarnos gran cantidad de cosas, imaginemos por ejemplo que cada
vez que necesitemos leer por teclado, debamos entonces crear una función que lo
haga (algo realmente complejo), al poder contar con las librerías en C++,
podremos hacer uso de una gran variedad de funciones que nos facilitaran la vida y
aumentarán la modularidad de nuestros códigos.

Las librerías no son únicamente archivos externos creados por otros, también es
posible crear nuestras propias librerías y utilizarlas en nuestros programas. Las
librerías pueden tener varias extensiones diferentes, las más comunes
son: .lib, .bpl, .a, .dll, .h y algunas más ya no tan comunes.

En conclusión: Las librearías son archivos (no siempre externos) que nos permiten
llevar a cabo diferentes tareas sin necesidad de preocuparnos por cómo se hacen
sino simplemente entender cómo usarlas. Las librearías en C++ permiten hacer
nuestros programas más modulares y reutilizables, facilitando además crear
programas con funcionalidades bastante complejas en unas pocas líneas de
código.

SINTAXIS PARA DECLARAR LIBRERÍAS EN C++


Hay un conjunto de bibliotecas (o librerías) muy especiales, que se incluyen con
todos los compiladores de C y de C++. Son las librerías (o bibliotecas) ANSI o
estándar. También hay librerías que no son parte del estándar pero en esta sección

La declaración de librerías, tanto en C como en C++, se debe hacer al principio de


todo nuestro código, antes de la declaración de cualquier función o línea de
código, debemos indicarle al compilador que librerías usar, para el saber que
términos estaran correctos en la escritura de nuestro código y cuáles no. La sintaxis
es la siguiente: #include <nombre de la librería> o alternativamente #include
"nombre de la librería". Cualquiera de las 2 formas es válida en C++ (no estoy
seguro si en C sea válido), ten en cuenta que siempre el nombre de la librería debe
ir entre " y " o entre < y >. En tu código puedes declarar todas las librerías que
quieras aunque en realidad no tienen sentido declarar una librería que no vas a
usar en tu programa, sin embargo no existe límite para esto.
4.2 DEFINICION DE FUNCION
Una función es un bloque de código que realiza alguna operación. Una función
puede definir opcionalmente parámetros de entrada que permiten a los llamadores
pasar argumentos a la función. Una función también puede devolver un valor como
salida. Las funciones son útiles para encapsular las operaciones comunes en un
solo bloque reutilizable, idealmente con un nombre que describa claramente lo
que hace la función. La función siguiente acepta dos enteros de un llamador y
devuelve su suma; a y b son parámetros de tipo int.

C++Copiar
int sum(int a, int b)
{
return a + b;
}

La función se puede invocar o llamar desde cualquier número de lugares del


programa. Los valores que se pasan a la función son los argumentos, cuyos tipos
deben ser compatibles con los tipos de parámetro de la definición de función.

C++Copiar
int main()
{
int i = sum(10, 32);
int j = sum(i, 66);
cout << "The value of j is" << j << endl; // 108
}

No hay ningún límite práctico para la longitud de la función, pero un buen diseño
tiene como objetivo funciones que realizan una sola tarea bien definida. Los
algoritmos complejos deben dividirse en funciones más sencillas y fáciles de
comprender siempre que sea posible.

Las funciones definidas en el ámbito de clase se denominan funciones miembro. En


C++, a diferencia de otros lenguajes, una función también pueden definirse en el
ámbito de espacio de nombres (incluido el espacio de nombres global implícito).
Estas funciones se denominan funciones libreso funciones que no son miembro; se
usan ampliamente en la biblioteca estándar.

Las funciones se pueden sobrecargar, lo que significa que distintas versiones de una
función pueden compartir el mismo nombre si difieren en el número o el tipo de
parámetros formales. Para obtener más información, vea Sobrecarga de funciones.
Elementos de una declaración de función

Una declaración de función mínima consta del tipo de valor devuelto, el nombre de


la función y la lista de parámetros (que pueden estar vacíos), junto con palabras
clave opcionales que proporcionan instrucciones adicionales al compilador. El
ejemplo siguiente es una declaración de función:

C++Copiar
int sum(int a, int b);

Una definición de función consta de una declaración, más el cuerpo, que es todo el
código entre las llaves:

C++Copiar
int sum(int a, int b)
{
return a + b;
}

Una declaración de función seguida de un punto y coma puede aparecer en varios


lugares de un programa. Debe aparecer antes de cualquier llamada a esa función
en cada unidad de traducción. La definición de función debe aparecer solo una vez
en el programa, según la regla de una definición (ODR).

Los elementos necesarios de una declaración de función son los siguientes:

1. Tipo de valor devuelto, que especifica el tipo del valor que devuelve la
función, void o si no se devuelve ningún valor. En C++11, es auto un
tipo de valor devuelto válido que indica al compilador que infiere el
tipo de la instrucción return. En C++14, decltype(auto) también se
permite. Para obtener más información, consulte más adelante
Deducción de tipos en tipos de valor devueltos.
2. El nombre de función, que debe comenzar con una letra o un carácter
de subrayado y no puede contener espacios. En general, un carácter de
subrayado inicial en los nombres de función de la biblioteca estándar
indica funciones de miembro privado o funciones no miembro que no
están pensadas para que las use el código.
3. La lista de parámetros, que es un conjunto delimitado por llaves y
separado por comas de cero o más parámetros que especifican el tipo
y, opcionalmente, un nombre local mediante el cual se puede acceder
a los valores de dentro del cuerpo de la función.
Los elementos opcionales de una declaración de función son los siguientes:

1. constexpr, que indica que el valor devuelto de la función es un valor


constante que se puede calcular en tiempo de compilación.

C++Copiar
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
};

2. Su especificación de vinculación, extern o static.

C++Copiar
//Declare printf with C linkage.
extern "C" int printf( const char *fmt, ... );

Para obtener más información, vea Unidades de traducción y


vinculación.

3. inline, que indica al compilador que reemplace todas las llamadas a la


función con el propio código de la función. La inserción en línea puede
mejorar el rendimiento en escenarios donde una función se ejecuta
rápidamente y se invoca varias veces en una sección del código crítica
para el rendimiento.

C++Copiar
inline double Account::GetBalance()
{
return balance;
}

Para obtener más información, vea Funciones insertadas.

4. Expresión noexcept que especifica si la función puede producir o no


una excepción. En el ejemplo siguiente, la función no produce una
excepción si la is_pod expresión se evalúa como true.

C++Copiar
#include <type_traits>
template <typename T>
T copy_object(T& obj) noexcept(std::is_pod<T>) {...}

Para obtener más información, vea noexcept.

5. (Solo funciones miembro) Calificadores cv, que especifican si la función


es const o volatile.
6. (Solo funciones miembro) virtual, overrideo final. virtual especifica
que una función se puede reemplazar en una clase
derivada. override significa que una función de una clase derivada
reemplaza una función virtual. final significa que una función no se
puede reemplazar en ninguna otra clase derivada. Para obtener más
información, vea Funciones virtuales.
7. (solo funciones miembro) static aplicado a una función miembro
significa que la función no está asociada a ninguna instancia de objeto
de la clase .
8. (Solo funciones miembro no estáticas) Calificador ref, que especifica al
compilador qué sobrecarga de una función elegir cuando el parámetro
de objeto implícito (*this) es una referencia de valor r frente a una
referencia lvalue. Para obtener más información, vea Sobrecarga de
funciones.

La ilustración siguiente muestra las partes de una definición de función. El área


sombreada es el cuerpo de la función.

Elementos de una definición de función

Definiciones de función

Una definición de función consta de la declaración y el cuerpo de la función, entre


llaves, que contiene declaraciones de variables, instrucciones y expresiones. En el
ejemplo siguiente se muestra una definición de función completa:

C++Copiar
int foo(int i, std::string s)
{
int value {i};
MyClass mc;
if(strcmp(s, "default") != 0)
{
value = mc.do_something(i);
}
return value;
}

Las variables declaradas dentro del cuerpo se denominan variables locales. Se salen
del ámbito cuando finaliza la función; por lo tanto, una función nunca debe
devolver una referencia a una variable local.

C++Copiar
MyClass& boom(int i, std::string s)
{
int value {i};
MyClass mc;
mc.Initialize(i,s);
return mc;
}
Funciones const y constexpr

Puede declarar una función miembro como para const especificar que la función no


puede cambiar los valores de los miembros de datos de la clase . Al declarar una
función miembro como const, ayuda al compilador a aplicar la const-correctness. Si
alguien intenta modificar por error el objeto mediante una función declarada
como const, se produce un error del compilador. Para obtener más información,
vea const.

Declare una función como constexpr cuando el valor que genera se puede


determinar posiblemente en tiempo de compilación. Por lo general, una función
constexpr se ejecuta más rápido que una función normal. Para obtener más
información, vea constexpr.

Plantillas de función

Una plantilla de función es parecida a una plantilla de clase; genera funciones


concretas que se basan en los argumentos de plantilla. En muchos casos, la
plantilla es capaz de inferir los argumentos de tipo, por lo que no es necesario
especificarlos de forma explícita.

C++Copiar
template<typename Lhs, typename Rhs>
auto Add2(const Lhs& lhs, const Rhs& rhs)
{
return lhs + rhs;
}

auto a = Add2(3.13, 2.895); // a is a double


auto b = Add2(string{ "Hello" }, string{ " World" }); // b is a std::string

Para obtener más información, vea Plantillas de función.

Parámetros de función y argumentos

Una función tiene una lista de parámetros separados por comas de cero o más
tipos, cada uno de los cuales tiene un nombre mediante el cual se puede acceder a
ellos dentro del cuerpo de la función. Una plantilla de función puede especificar
parámetros adicionales de tipo de valor. El llamador pasa argumentos, que son
valores concretos cuyos tipos son compatibles con la lista de parámetros.

De forma predeterminada, los argumentos se pasan a la función por valor, lo que


significa que la función recibe una copia del objeto que se pasa. En el caso de los
objetos grandes, puede resultar costoso realizar una copia y no siempre es
necesario. Para hacer que los argumentos se pasen por referencia (específicamente
la referencia lvalue), agregue un cuantificador de referencia al parámetro :

C++Copiar
void DoSomething(std::string& input){...}

Cuando una función modifica un argumento que se pasa por referencia, modifica el
objeto original, no una copia local. Para evitar que una función modifique este tipo
de argumento, califique el parámetro como const&:

C++Copiar
void DoSomething(const std::string& input){...}

C++ 11: Para controlar explícitamente los argumentos que pasan rvalue-reference


o lvalue-reference, use una instrucción double-ampersand en el parámetro para
indicar una referencia universal:

C++Copiar
void DoSomething(const std::string&& input){...}

Una función declarada con la palabra clave single void en la lista de declaraciones


de parámetros no toma ningún argumento, void siempre y cuando la palabra clave
sea el primer y único miembro de la lista de declaraciones de argumentos. Los
argumentos de tipo en void otra parte de la lista generan errores. Por ejemplo:

C++Copiar

// OK same as GetTickCount()
long GetTickCount( void );

Tenga en cuenta que, aunque no es válido especificar un argumento excepto como


se describe aquí, void los tipos derivados del tipo (como punteros void a void y
matrices de void) pueden aparecer en cualquier lugar de la lista de declaraciones
de argumentos.

Argumentos predeterminados

Es posible asignar un argumento predeterminado al último parámetro o


parámetros de una firma de función, lo que significa que el llamador puede omitir
el argumento cuando se llama a la función, a menos que desee especificar otro
valor.

C++Copiar
int DoSomething(int num,
string str,
Allocator& alloc = defaultAllocator)
{ ... }

// OK both parameters are at end


int DoSomethingElse(int num,
string str = string{ "Working" },
Allocator& alloc = defaultAllocator)
{ ... }

// C2548: 'DoMore': missing default parameter for parameter 2


int DoMore(int num = 5, // Not a trailing parameter!
string str,
Allocator& = defaultAllocator)
{...}

Para obtener más información, vea Argumentos predeterminados.

Tipos de valor devuelto de función

Es posible que una función no devuelva otra función o una matriz integrada; sin
embargo, puede devolver punteros a estos tipos, o una expresión lambda, que
genera un objeto de función. Excepto en estos casos, una función puede devolver
un valor de cualquier tipo que esté en el ámbito o no devolver ningún valor, en
cuyo caso el tipo de valor devuelto es void.

Tipos de valor devueltos finales

Un tipo de valor devuelto "normal" se encuentra en el lado izquierdo de la firma de


función. Un tipo de valor devuelto final se encuentra en el lado derecho de la firma
y está precedido por el -> operador . Los tipos de valor devueltos finales son
especialmente útiles en plantillas de función cuando el tipo del valor devuelto
depende de los parámetros de plantilla.

C++Copiar
template<typename Lhs, typename Rhs>
auto Add(const Lhs& lhs, const Rhs& rhs) -> decltype(lhs + rhs)
{
return lhs + rhs;
}

Cuando auto se usa junto con un tipo de valor devuelto final, solo sirve como
marcador de posición para cualquier expresión decltype que produzca y no realiza
por sí mismo la deducción de tipos.

Variables locales de función

Una variable que se declara dentro de un cuerpo de función se denomina variable


local o simplemente local. Las variables locales no estáticas solo son visibles dentro
del cuerpo de función y, si se declaran en la pila, se salen del ámbito cuando
finaliza la función. Al construir una variable local y devolverla por valor, el
compilador normalmente puede realizar la optimización del valor devuelto
con nombre para evitar operaciones de copia innecesarias. Si una variable local se
devuelve por referencia, el compilador emitirá una advertencia, ya que cualquier
intento por parte del llamador de usar esa referencia se producirá después de la
destrucción de la variable local.

En C++, una variable local se puede declarar como estática. La variable solo es
visible dentro del cuerpo de la función, pero existe una copia única de la variable
para todas las instancias de la función. Los objetos estáticos locales se destruyen
durante la finalización especificada por atexit. Si no se crea un objeto estático
porque el flujo de control de programa omitió su declaración, no se realiza ningún
intento de destruir ese objeto.
Deducción de tipos en los tipos de valor devueltos (C++14)

En C++14, auto puede usar para indicar al compilador que infiera el tipo de valor


devuelto del cuerpo de la función sin tener que proporcionar un tipo de valor
devuelto final. Tenga en cuenta auto que siempre se deduce en un valor devuelto
por valor. Use auto&& para indicar al compilador que deduzca una referencia.

En este ejemplo, auto se deducirá como una copia de valor no const de la suma de


lhs y rhs.

C++Copiar
template<typename Lhs, typename Rhs>
auto Add2(const Lhs& lhs, const Rhs& rhs)
{
return lhs + rhs; //returns a non-const object by value
}

Tenga en auto cuenta que no conserva la const-ness del tipo que deduce. Para las
funciones de reenvío cuyo valor devuelto necesita conservar la const-ness o ref-
ness de sus argumentos, decltype(auto) puede usar la palabra clave , decltype que
usa las reglas de inferencia de tipos y conserva toda la información de
tipo. decltype(auto)Puede usar como valor de retorno normal a la izquierda o
como valor devuelto final.

En el ejemplo siguiente (basado en código de N3493), decltype(auto) se muestra


cómo se usa para habilitar el reenvío perfecto de argumentos de función en un
tipo de valor devuelto que no se conoce hasta que se crea una instancia de la
plantilla.

C++Copiar
template<typename F, typename Tuple = tuple<T...>, int... I>
decltype(auto) apply_(F&& f, Tuple&& args, index_sequence<I...>)
{
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...);
}

template<typename F, typename Tuple = tuple<T...>,


typename Indices = make_index_sequence<tuple_size<Tuple>::value >>
decltype( auto)
apply(F&& f, Tuple&& args)
{
return apply_(std::forward<F>(f), std::forward<Tuple>(args), Indices());
}
Devolver varios valores de una función

Hay varias maneras de devolver más de un valor de una función:

1. Encapsular los valores de una clase con nombre o un objeto de


estructura. Requiere que la definición de clase o estructura sea visible
para el autor de la llamada:

C++Copiar
#include <string>
#include <iostream>

using namespace std;

struct S
{
string name;
int num;
};

S g()
{
string t{ "hello" };
int u{ 42 };
return { t, u };
}

int main()
{
S s = g();
cout << s.name << " " << s.num << endl;
return 0;
}

2. Devuelve un objeto std::tuple o std::p air:

C++Copiar
#include <tuple>
#include <string>
#include <iostream>

using namespace std;

tuple<int, string, double> f()


{
int i{ 108 };
string s{ "Some text" };
double d{ .01 };
return { i,s,d };
}
int main()
{
auto t = f();
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) <<
endl;

// --or--

int myval;
string myname;
double mydecimal;
tie(myval, myname, mydecimal) = f();
cout << myval << " " << myname << " " << mydecimal << endl;

return 0;
}

3. Visual Studio 2017 versión 15.3 y posteriores (/std:c++17disponible en


modo y versiones posteriores): use enlaces estructurados. La ventaja de
los enlaces estructurados es que las variables que almacenan los
valores devueltos se inicializan al mismo tiempo que se declaran, lo
que en algunos casos puede ser significativamente más eficaz. En la
instrucción , auto[x, y, z] = f(); los corchetes introducen e inicializan
nombres que están en el ámbito de todo el bloque de función.

C++Copiar
#include <tuple>
#include <string>
#include <iostream>

using namespace std;

tuple<int, string, double> f()


{
int i{ 108 };
string s{ "Some text" };
double d{ .01 };
return { i,s,d };
}
struct S
{
string name;
int num;
};

S g()
{
string t{ "hello" };
int u{ 42 };
return { t, u };
}

int main()
{
auto[x, y, z] = f(); // init from tuple
cout << x << " " << y << " " << z << endl;

auto[a, b] = g(); // init from POD struct


cout << a << " " << b << endl;
return 0;
}

4. Además de usar el propio valor devuelto, puede "devolver" valores


definiendo cualquier número de parámetros para usar pass-by-
reference para que la función pueda modificar o inicializar los valores
de los objetos que proporciona el autor de la llamada. Para obtener
más información, vea Argumentos de función de tipo de referencia.

Punteros de función

C++ admite punteros de función de la misma manera que el lenguaje C. Sin


embargo, una alternativa con mayor seguridad de tipos suele ser usar un objeto de
función.

Se recomienda usar para typedef declarar un alias para el tipo de puntero de


función si se declara una función que devuelve un tipo de puntero de función. Por
ejemplo

C++Copiar
typedef int (*fp)(int);
fp myFunction(char* s); // function returning function pointer

Si no es así, la sintaxis correcta para la declaración de la función se puede deducir


de la sintaxis de declarador del puntero a función, mediante la sustitución del
identificador (fp en el ejemplo anterior) por el nombre y la lista de argumentos de
las funciones, como sigue:

C++Copiar
int (*myFunction(char* s))(int);

La declaración anterior es equivalente a la declaración que se usa


anteriormente typedef 

También podría gustarte