Sunteți pe pagina 1din 107

INSTITUTO TECNOLOGICO SUPERIOR DE

ESCARCEGA
INGENIERIA EN SISTEMAS COMPUTACIONALES

TOPICOS SELECTOS DE PROGRAMACION

INVESTIGACIONES
ERIC ADRIAN CONTRERAS ARJONA
Índice

GTK

GTK#

WINDOWS FORMS

QT

LIBRERIAS DINAMICAS

PUNTERO

CLASES

RECURSIVIDAD

LPP (PUERTO PARALELO)

COM(PUERTO SERIE)

RS-32 (PUERTO SERIAL)

FIREWIRE

LICENCIAS

COPYRIGHT

GPL

GNU

LGPL

CREATIVE COMMONS

MIT

VESTOR

LISTA

PILA

ITERADORES

CIN,COUT

WIDGETS

TEMPLATES

2
GTK

GTK+ o The GIMP Toolkit es un conjunto de bibliotecas multiplataforma para desarrollar


interfaces gráficas de usuario (GUI), principalmente para los entornos gráficos GNOME,
XFCE y ROX aunque también se puede usar en el escritorio de Windows, MacOS y otros.

Inicialmente fueron creadas para desarrollar el programa de edición de imagen GIMP, sin
embargo actualmente se usan mucho por muchos otros programas en los sistemas
GNU/Linux. Junto a Qt es uno de las bibliotecas más populares para X Window System.

GTK+ se ha diseñado para permitir programar con lenguajes como C, C++, C#, Java, Ruby,
Perl, PHP o Python.

Licenciado bajo los términos de LGPL, GTK+ es software libre y es parte del proyecto GNU.

GTK#

Gtk # es una interfaz gráfica de usuario Toolkit para mono y. Net. El proyecto se une la
GTK + (http://www.gtk.org/) kit de herramientas y una variedad de GNOME
(http://www.gnome.org/) las bibliotecas, permitiendo plenamente nativas de desarrollo de
GNOME gráfica de aplicaciones utilizando el Mono y. Net marcos de desarrollo.

WINDOWS FORMS

Windows Forms es el nombre dado a la interfaz gráfica de programación de aplicaciones


(API), incluido como una parte de. NET Framework de Microsoft, proporcionando acceso a
los elementos nativos interfaz de Microsoft Windows envolviendo la API de Windows
existentes en el código administrado. Si bien es visto como un reemplazo de la anterior y
más complejo de C + + basados en Microsoft Foundation Class Library, que no ofrece un
paradigma comparable al modelo-vista-controlador. Algunos después de mercado y las
bibliotecas de terceros han sido creadas para proporcionar esta funcionalidad. El más
utilizado de ellos es el Proceso de Interfaz de Usuario bloque de aplicación, que es liberado
por los patrones y prácticas Microsoft grupo como una descarga gratuita que incluye el
código fuente de ejemplos de inicio rápido.

3
QT

Qt o biblioteca Qt es una herramienta de programadores para desarrollar interfaces


gráficas de usuario. Es un sistema integral de desarrollo para aplicaciones multi-
plataforma.

Qt (que se pronuncia como la palabra Inglés "lindo" [2]), es una aplicación marco de la
plataforma de desarrollo, ampliamente utilizado para el desarrollo de los programas de
interfaz gráfica de usuario (en cuyo caso se conoce como un Widget Toolkit), y también se
utiliza para el desarrollo no programas de gráficas, tales como herramientas de la consola y
servidores. Qt es principalmente usado en KDE, Google Earth, Skype, Qt Extended, Adobe
Photoshop Album, VirtualBox y OPIE.

4
TEMAS

LIBRERIAS DINAMICAS

PUNTERO

CLASES

RECURSIVIDAD

LIBRERÍAS DINÁMICAS

Conocidas como DLLs, acrónimo de su nombre en inglés ("Dynamic Linked Library"). Estas
librerías se utilizan mucho en la programación para el SO Windows. Este Sistema contiene
un gran número de tales librerías de terminación .DLL, aunque en realidad pueden tener
cualquier otra terminación .EXE, .FON, .BPI, .DRV etc. Cualquiera que sea su terminación,
de forma genérica nos referiremos a ellas como DLLs, nombre por el que son más conocidas.

Una de las grandes ventajas del uso de librerías dinámicas, aparte de tener ficheros
ejecutables más pequeños, es que podemos modificar la implementación de las librerías sin
tener que recompilar los programas.

Que es un puntero

Un puntero es un tipo especial de variable, que almacena el valor de una direccion de


memoria, esta direccion puede ser la de una variable individual, pero mas frecuentemente
sera la de un elemento de un array, una estructura u objeto de una clase. Los punteros, al
igual que una variable comun, pertenecen a un tipo (type), se dice que un puntero 'apunta a'
ese tipo al que pertenece. Ejemplos:

int* pint; //Declara un puntero a entero


char* pchar; //Puntero a char
fecha* pfecha; //Puntero a objeto de clase 'fecha'

Independientemente del tamaño (sizeof) del objeto apuntado, el valor almacenado por el
puntero sera el de una unica direccion de memoria. En sentido estricto un puntero no puede
almacenar la direccion de memoria de 'un array' (completo), sino la de un elemento de un
array, y por este motivo no existen diferencias sintacticas entre punteros a elementos

5
individuales y punteros a arrays. La declaracion de un puntero a char y otro a array de char
es igual.

Al definir variables o arrays hemos visto que el tipo (type) modifica la cantidad de bytes
que se usaran para almacenar tales elementos, asi un elemento de tipo 'char' utiliza 1 byte,
y un entero 2 o 4. No ocurre lo mismo con los punteros, el tipo no influye en la cantidad de
bytes asociados al puntero, pues todas las direcciones de memoria se pueden expresar con
solo 2 bytes (o 4 si es una direccion de otro segmento)

Veamos los efectos de un codigo como el siguiente, en la zona de almancenamiento de


datos:

char cad[] = "hola";


char * p;
p = cad; //Puntero 'p' apunta a 'cad'

El puntero esta en la direccion 0xffee pero el valor que hay en esa localidad de memoria es
otra direccion, los bytes "F0 FF" indican que el puntero apunta a FFF0, donde comienza la
cadena de caracteres 'cad' con el contenido 'hola' mas el cero de fin de cadena.
En las lineas de codigo no hemos indicado a que caracter del array apunta el puntero, pero
esa notacion es equivalente a:

p = &cad[0];

que indica de modo mas explicito que se trata de la direccion del primer elemento de ese
array de caracteres. El juego con las direcciones puede ilustrarse tambien del siguiente
modo:

ffee F0 <----- El puntero ocupa dos bytes para representar la direccion FFF0,
direccion a la que 'apunta'.
ffef FF <-----

fff0 61 <------ cad[0]. .Primer char del array de caracteres, direccion apuntada por el
puntero
fff1 61 <------ cad[1]
fff2 61 <------ cad[2]
fff3 61 <------ cad[3]
fff4 0 <------ cad[4] Fin del array, caracter ascii = 0 de fin de cadena

Puesto que un puntero tiene como valor una direccion de memoria, es logico que al llamar a
funciones de impresion con un puntero como argumento, la salida en pantalla sea la de una

6
direccion de memoria. Para este tipo de pruebas es interesante usar la libreria iostream.h
de C++, pues no obliga a especificar el formato (como hace printf ). Para un puntero 'p' la
salida en pantalla sera algo similar a lo siguiente:

cout<<p; //sale: 0x8f82fff0;


printf("%p",p) //sale: FFF0

En este caso se trata de un puntero que almacena en 2 bytes una direccion de memoria, la
cual es FFF0. Porque razon la impresion con 'cout' nos da 4 bytes? Porque agrega 2 bytes
(8f y 82) para indicar el 'segmento' donde se encuentra esa direccion. Se trata en todo
caso de una misma localidad de memoria, con distinto formato de presentacion en pantalla.

La salida en pantalla de un puntero a char es diferente, pues es tratado como apuntando a


una cadena de caracteres, en tal caso no sale en pantalla una direccion de memoria, sino un
conjunto de caracteres hasta encontrar el '\0'.

Un puntero puede almacenar la direccion de ("apuntar a") muy diferentes entidades: una
variable, un objeto, una funcion, un miembro de clase, otro puntero, o un array de cada uno
de estos tipos de elementos, tambien puede contener un valor que indique que no apunta
actualmente a ningun objeto (puntero nulo).

Tipos definidos por el programador

Tipos como 'bool', 'int' o 'char', son "tipos predefinidos", pertenecientes al lenguaje. En
C++ al igual que otros lenguajes, es posible definir tipos nuevos. Las enumeraciones, uniones,
estructuras y clases, son tipos nuevos que implementa el programador.

La declaracion de un tipo no produce ningun efecto en memoria, no hay ningun identificador


donde almacenar un dato, por esa razon no tendria sentido, dentro de la definicion de una
estructura o clase , intentar dar un valor a sus datos, seria lo mismo que intentar dar un
valor a un tipo predefinido, por ejemplo:
long = 8;
Para asignar un valor necesitamos un objeto, pues un objeto implica una region de memoria
donde almacenar un valor.

El almacenamiento en memoria de una union, enumeracion o estructura (C), no presenta


importantes cambios respecto a los tipos predefinidos, sus elementos se ordenaran de
modo consecutivo de acuerdo a su 'sizeof'. Respecto a C, C++ aporta un nuevo tipo
predefinido, las clases, entidad que no solo es un agregado de datos sino tambien de
funciones, y que por ello presenta novedades de importancia respecto a los tipos
anteriores.

Punteros

Cada variable de un programa tiene una dirección en la memoria del ordenador. Esta
dirección indica la posición del primer byte que la variable ocupa. En el caso de una
estructura es la dirección del primer campo. En los ordenadores actuales la dirección de
inicio se considera la dirección baja de memoria. Como en cualquier caso las variables son
almacenadas ordenadamente y de una forma predecible, es posible acceder a estas y

7
manipularlas mediante otra variables que contenga su dirección. A este tipo de variables se
les denomina punteros.

Los punteros C son el tipo más potente y seguramente la otra clave del éxito del lenguaje.
La primera ventaja que obtenemos de los punteros es la posibilidad que nos dan de poder
tratar con datos de un tamaño arbitrario sin tener que moverlos por la memoria. Esto
puede ahorrar un tiempo de computación muy importante en algunos tipos de aplicaciones.
También permiten que una función reciba y cambie el valor de una variable. Recordemos que
todas las funciones C únicamente aceptan parámetros por valor. Mediante un puntero a una
variable podemos modificarla indirectamente desde una función cualquiera.

Un puntero se declara de la forma: tipo *nombre;

float *pf;

PLANETA *pp;

char *pc;

Para manipular un puntero, como variable que es, se utiliza su nombre; pero para acceder a
la variable a la que apunta se le debe preceder de *. A este proceso se le llama indirección.
Accedemos indirectamente a una variable. Para trabajar con punteros existe un operador,
&, que indica 'dirección de'. Con él se puede asignar a un puntero la dirección de una
variable, o pasar como parámetro a una función.

void prueba_puntero ( void ) {

long edad;

long *p;

p = &edad;

edad = 50;

printf("La edad es %ld\n", edad );

*p = *p / 2;

printf("La edad es %ld\n", edad );

void imprimir_string ( char string[] ) {

char *p;

for ( p = string; *p != '\0'; p++ )

imprimir_char(*p);

Definimos un vector de N_PLA componentes de tipo PLANETA. Este tipo está formado por
un registro. Vemos que en la función de inicialización del vector el puntero a la primera
componente se inicializa con el nombre del vector. Esto es una característica importante de
C. La dirección de la primera componente de un vector se puede direccionar con el nombre
del vector. Esto es debido a que en la memoria del ordenador, los distintos elementos están
ordenados de forma ascendente. Así, SSolar se puede utilizar como &SSolar[0]. A cada
iteración llamamos a una función que nos inicializará los datos de cada planeta. A esta
función le pasamos como argumento el puntero a la componente en curso para que,

8
utilizando la notación ->, pueda asignar los valores adecuados a cada campo del registro.
Debemos fijarnos en el incremento del puntero de control de la iteración, p++. Con los
punteros se pueden realizar determinadas operaciones aritméticas aunque, a parte del
incremento y decremento, no son muy frecuentes. Cuando incrementamos un puntero el
compilador le suma la cantidad necesaria para que apunte al siguiente elemento de la
memoria. Debemos fijarnos que esto es aplicable sólo siempre que haya distintas variables
o elementos situados consecutivamente en la memoria, como ocurre con los vectores.

De forma similar se pueden utilizar funciones que tengan como parámetros punteros, para
cambiar el valor de una variable. Veamos:

void intercambio ( void ) {

int a, b;

a = 1;

b = 2;

swap( &a, &b );

printf(" a = %d b = %d\n", a, b );

void swap ( int *x, int *y ) {

int tmp;

tmp = *x;

*x = *y;

*y = tmp;

La sintaxis de C puede, a veces, provocar confusión. Se debe distinguir lo que es un


prototipo de una función de lo que es una declaración de una variable. Así mismo, un puntero
a un vector de punteros, etc...

 int f1(); función que devuelve un entero


 int *p1; puntero a entero
 int *f2(); función que devuelve un puntero a entero
 int (*pf)(int); puntero a función que toma y devuelve un entero
 int (*pf2)(int *pi); puntero a función que toma un puntero a entero y devuelve un entero
 int a[3]; vector de tres enteros
 int *ap[3]; vector de tres punteros a entero
 int *(ap[3]); vector de tres punteros a entero
 int (*pa)[3]; puntero a vector de tres enteros
 int (*apf[5])(int *pi); vector de 5 punteros a función que toman un puntero a entero y
devuelven un entero.

En los programas que se escriban se debe intentar evitar declaraciones complejas que
dificulten la legibilidad del programa. Una forma de conseguirlo es utilizando typedef para
redefinir/renombrar tipos.

typedef int *intptr;

9
typedef intptr (*fptr) ( intptr );

fptr f1, f2;

Clases

Una clase es basicamente un agregado de datos y funciones para manipular esos datos. Las
clases, y la programacion 'orientada a objetos' en general, ha representado un gran avance
para produccion de software a gran escala, los recursos de herencia, encapsulamiento,
ocultacion de datos, clases virtuales, etc., estan pensados con esa finalidad. Aqui solo nos
detendremos en la nocion minima de 'clase' y el modo en que es almacenado un objeto en
memoria.

Supongamos una clase muy simple:

class gente
{
char nombre[10];
int edad;
public:
gente (char*cad, int a)
{
strcpy(nombre,cad);
edad = a;
}
};

Se trata de una clase cuyos miembros son dos datos y una sola funcion. Una vez declarada
la clase podemos definir objetos como pertenecientes a ese tipo. Una clase no ocupa
espacio, pero si un objeto perteneciente a esa clase. El espacio ocupado en memoria por tal
objeto puede ser conocido a traves de 'sizeof'.
gente pp1;
cout<<sizeof(pp1); //saca en pantalla '12'
El valor podria ser ligeramente diferente segun el compilador, por efecto de optimizacion.
Lo importante es observar que el monto de memoria del objeto (retornado por sizeof), esta
determinado por la suma del espacio ocupado por los datos, 'sizeof' no tiene en cuenta a la
funcion.
Cada objeto de tipo 'gente' ocupara 12 bytes, pues posee una copia individual de los datos
de clase, en cambio hay una sola copia del miembro funcion (aqui el constructor) utilizado
por todos los objetos.

Declaremos dos objetos de tipo 'gente':

gente pp1("gerardo", 33);


gente pp2("miguel",34);

Observaremos ahora que efectos producen estas entidades 'pp1' y 'pp2', en memoria. Los
datos que utilizaremos se obtienen en TurboC++ (cualquier version) posando el cursor sobre
el objeto que nos interesa (aqui 'pp1' y 'pp2') y pulsando 'Alt+f4', tambien consultaremos
los registros de la CPU (con "Windows/Registers"). En un programa, que define la clase

10
'gente' y dos objetos (pp1 y pp2) inicializados como muestran las lineas de codigo previas,
se puede observar lo siguiente:

El valor especifico de cada dato (como el valor de segmento) puede variar con cada
ejecucion, lo que cuenta es la relacion entre tales valores. Interpretemos estos datos.

1- En la ventana de cada objeto (pp1 y pp2) figura en primer lugar la direccion de memoria
donde almacena sus valores, ambas direcciones tienen el mismo valor de segmento
(0x8F86), que coincide por otra parte con el valor de DS (segmento de datos) y de SS
(segmento de stack) de la CPU. Sus direcciones difieren ligeramente en offset, la resta de
los mismos (0xFFEA - 0xFFDE) es igual a 12, que es el espacio que ocupa (en bytes) cada
objeto en memoria.

2- Esos 12 bytes por objeto corresponden a 10 para la cadena de caracteres ('cad') y 2


para almacenar el entero ('edad'). Estos datos estan almacenados alli donde indica el
offset, no en otro sitio, por lo tanto un puntero al objeto 'pp1' apuntara (en este caso) a la
misma direccion de memoria que un puntero a su elemento 'cad', y otro tanto para 'pp2'.
Las datos miembros se exponen con sus nombres a la izquierda y el valor que contienen a la
derecha. La cadena de caracteres es terminada en '\0' (seguido de caracteres aleatorios),
y el entero es mostrado en formato decimal y hexadecimal

3-Debajo, y separado por una linea, se encuentra un espacio donde se enumeran las
funciones miembro de la clase. Alli encontramos el prototipo de la funcion miembro y al lado
la direccion de memoria donde se inicia su codigo. Ese es el valor que almacenaria un
puntero a dicha funcion. Observese que tal direccion es la misma para ambos objetos, por
la razon antes mencionada de que hay solo una copia de funciones miembro por objeto. El
segmento donde se encuentra tal funcion se corresponde con el valor que muestra la
ventana CPU para CS (segmento de codigo).

Podemos sintetizar lo visto respecto a clases del siguiente modo:


-Una clase no es un 'dato' (es un tipo), no tiene una localidad de memoria asociada y por lo
tanto no puede almacenar ningun valor.
-Un objeto de tal clase si define una region de memoria, un espacio de almacenamiento de
datos. Esta es la diferencia entre 'clase' y 'objeto'.
-Cada objeto de una misma clase posee una copia propia de cada uno de los datos miembros
de la clase, pero comparte una misma copia de las funciones miembros.

Por otra parte, un array de objetos (instancias de clase) es almacenado como una sucesion
consecutiva, mientras que un puntero a objeto sera (como todo puntero) un par de bytes
que apunte a una direccion de memoria donde se almacena el objeto.

11
RECURSIÓN

Un tema fundamental para los próximos temas es el de recusrión. La recursión es muy


importante tanto en mateáticas como em computación, pues se usa recursión para definir
procedimientos autosimilares.

Definición 6 Decimos que un objeto es recursivo si en su definición se nombra a sí mismo.

En programación, una función es recursiva si en el ámbito de esa función hay una llamada a
sí misma, C/C++ permite esta clase de acciones. Los algoritmos recursivos dan elegancia a
las soluciones de los problemas. Un ejemplo clásico es el factorial de un número.

Una manera de definir el factorial de un número es:

es decir, el producto de todos los números enteros menores o guales que él, lo que se puede
resolver fácilmente con una función iterativa, esto es, una función con un ciclo que itere
suficientes veces, incrementando un valor y entonces ir almacenando en una variable el
resultado de esas multiplicaciones.

Una implementación de esta definición iterativa es:

(1) int i,n;


(2) long double valorAc;
(4) valorAc=1.0;
(5) std::cout << "Numero entero:";
(6) std::cin>> n;
(7) for(i=1; i<=n; i++) valorAc = valorAc*i;
(8) std::cout<<"El factorial de "<<n<<" es:"<<valorAc;

El ciclo principal es en la línea (7). No hay ningún truco hasta aquí. La única observación
importante es en la línea (2) en donde se declara el tipo long double para el valor del
resultado, la razón para tal acción es que el número factorial crece muy rápido y aún con
entradas en el rango de los caracteres (hasta 255), el factorial es muy grande. Este
procedimiento computacional no hace uso de técnicas especiales empleadas para tratar
números grandes.

Sin embargo una solución más elegante es usar la definición recursiva, y esta es:

El programa en C/C++ es el que se muestra a continuación:

( 1) double factorial(double a){

12
( 2) if (a<=1) return 1.0;
( 3) else return (a *factorial(a-1.0)); }
( 4)
( 5) int main (int argc, char * const argv[]) {
( 6) double n;
( 7) std::cout << "Numero entero:";
( 8) std::cin>> n;
( 9) std::cout<<"El factorial de "<<n<<" es: "<< factorial(n);
(10) return 0; }

Aquí hay varias cosas que señalar, en primer lugar se ha creado una nueva función, a
diferencia de la definición iterativa en donde era suficiente trabajar en el programa
principal. Esta función se llama factorial (como era de suponerse), y empieza su encabezado
en la línea (1).

Allí mismo en la misma línea (1), es de notar que hemos emplado ahora el tipo double tanto
para el tipo devuelto como para el tipo del argumento, a diferencia de la versión iterativa
en donde empleábamos tipos diferentes. La razón es que al iniciar la recursión el argumento
es del tipo devuelto, asi que deben ser del mismo tipo.

Cada llamada recursiva genera una entrada a una pila, en donde se guardan (como
elementos) los estados generales del sistema al momento de hacer la llamada, entonces,
cuando se termina la función se recupera una entrada de la pila. En la figura 16 ilustra cómo
funciona la recursividad cuando se intenta obtener el factorial(5).

Figura 16: Recursividad cuando se ejecuta factorial(5)

R ECURSIÓN

S INOPSIS

Se dice que una función es recursiva cuando se llama a sí misma. Es clásico el ejemplo de
cálculo del factorial de un número mediante el uso de este tipo de funciones:

int factorial (int x) { return ( x > 1) ? x * factorial(x-1): 1; }

13
Cada invocación sucesiva de estas funciones crea un nuevo juego de todas las variables
automáticas, con independencia de cuales sean sus valores en el conjunto previo. En cambio
existe una sola copia de las variables estáticas, que es compartida por todas las instancias
de la función. Esta circunstancia debe ser tenida en cuenta, cuando dichas variables sean
utilizadas en funciones que puedan llamarse a sí mismas.

La recursión ocupa espacio en la pila, porque se debe guardar una copia de cada juego de
variables y tampoco es muy rápida, pero tiene la ventaja de que resulta un código fácil de
interpretar. Es especialmente adecuada para estructuras que se definen recursivamente
(algunos miembros de estas estructuras son punteros que referencian a objetos del mismo
tipo que la que se está definiendo), como árboles y listas enlazadas (las hemos denominado
estructuras auto-referenciadas).

Hay que prestar atención a que en algunos casos de funciones recursivas es difícil de
manejar el valor devuelto. Como ejemplo tomemos la función búsqueda de un valor (key) en
un árbol binario que reproducimos aquí. Esta función aparentemente devuelve un puntero al
nodo buscado, o un nulo si fracasa la búsqueda.

struct base* busca(char key, struct base* ptr) { // buscar key


if (key == ptr->let) return ptr; // Ok. encuentro!
if (key < ptr->let) {
if (ptr->izq == NULL) return NULL;
busca(key, ptr->izq);
}
if (key > ptr->let) {
if (ptr->der == NULL) return NULL;
busca(key, ptr->der);
}
return NULL;
}

14
El problema aquí, es que la función busca en el árbol de forma recursiva, pero es imposible
saber "a priori" cuantas invocaciones anidadas se producirán. Además, ninguna función
aprovecha el valor devuelto por la anterior, por lo que salvo la primera, cuyo retorno si
puede ser utilizado por la función invocante, todos los demás valores de retorno se pierden
(una función puede devolver un
valor, pero es potestad de la
función invocante aprovecharlo o
no). En este contexto no tiene
sentido manejar directamente el
valor devuelto por busca tal como
se ha presentado. Por ejemplo,
sería inútil el siguiente trozo de
código para saber si la búsqueda
ha tenido éxito:

...
if (busca(key, ptr) != NULL){
...
}

La situación puede esquematizarse en la Fig.1. Cada nueva recursión recibe parámetros de


la anterior, pero esta no utiliza el valor devuelto.

La función usuaria (que hace la primera invocación a busca) siempre recibirá el resultado de
la primera invocación, de modo que si el resultado se ha producido a partir de la segunda, el
valor que recibe la función usuaria es irrelevante.

Para resolver el problema puede utilizarse una variable global que sea modificada por la
instancia que realiza el hallazgo, o un sistema más refinado. Por ejemplo el manejador de
excepciones, que como se ha indicado, puede utilizarse como mecanismo de return o break
multinivel, y además pasar un valor desde el origen hasta el punto de captura.

En el primer caso, la función modificada podría tener el siguiente diseño:

void busca(char key, struct base* ptr) { // buscar key


if (key == ptr->let){gptr = ptr; return; } // Ok. encuentro!
if (key < ptr->let) {
if (ptr->izq == NULL) return;
busca(key, ptr->izq);
}
if (key > ptr->let) {
if (ptr->der == NULL) return;

15
busca(key, ptr->der);
}
return;
}

El cambio consiste en que la función devuelve siempre void, pero cuando se produce el
encuentro modifica adecuadamente una constante global gptr (esta variable podría ser
inicializada a NULL antes de la primera invocación a busca).

RECURSIVIDAD

Se dice que una función es recursiva cuando se define en función de si misma. No todas la
funciones pueden llamarse a si mismas, deben estar diseñadas especialmente para que sean
recursivas, de otro modo podrían conducir a bucles infinitos, o a que el programa termine
inadecuadamente.

C++ permite la recursividad. Cuando se llama a una función, se crea un nuevo juego de
variables locales, de este modo, si la función hace una llamada a si misma, se guardan sus
variables y parámetros en la pila, y la nueva instancia de la función trabajará con su propia
copia de las variables locales, cuando esta segunda instancia de la función retorna,
recupera las variables y los parámetros de la pila y continua la ejecución en el punto en que
había sido llamada.

Por ejemplo:

Función recursiva para calcular el factorial de un número entero. El factorial se simboliza


como n!, se lee como "n factorial", y la definición es:

n! = n * (n-1) * (n-2) * ... * 1

No se puede calcular el factorial de números negativos, y el factorial de cero es 1, de modo


que una función bien hecha para cálculo de factoriales debería incluir un control para esos
casos:

/* Función recursiva para cálculo de factoriales */


int factorial(int n) {
if(n < 0) return 0;
else if(n > 1) return n*factorial(n-1); /* Recursividad */
return 1; /* Condición de terminación, n == 1 */
}

Veamos paso a paso, lo que pasa cuando se ejecuta esta función, por ejemplo: factorial(4):

1a Instancia
n=4
n>1
salida ← 4 * factorial(3) (Guarda el valor de n = 4)

16
2a Instancia
n>1
salida ← 3*factorial(2) (Guarda el valor de n = 3)

3a Instancia
n>1
salida ← 2*factorial(1) (Guarda el valor de n = 2)

4a Instancia
n == 1 → retorna 1

3a Instancia
(recupera n=2 de la pila) retorna 1*2=2

2a instancia
(recupera n=3 de la pila) retorna 2*3=6

1a instancia
(recupera n=4 de la pila) retorna 6*4=24
Valor de retorno → 24

La función factorial es un buen ejemplo para demostrar cómo se hace una función
recursiva, sin embargo la recursividad no es un buen modo de resolver esta función, que
sería más sencilla y rápida con un bucle "for". La recursividad consume muchos recursos de
memoria y tiempo de ejecución, y se debe aplicar a funciones que realmente le saquen
partido.

Por ejemplo: visualizar las permutaciones de n elementos.

Las permutaciones de un conjunto son las diferentes maneras de colocar sus elementos,
usando todos ellos y sin repetir ninguno. Por ejemplo para A, B, C, tenemos: ABC, ACB, BAC,
BCA, CAB, CBA.

#include <iostream>
using namespace std;

/* Prototipo de función */
void Permutaciones(char *, int l=0);

int main(int argc, char *argv[]) {


char palabra[] = "ABCDE";

Permutaciones(palabra);

cin.get();
return 0;
}

void Permutaciones(char * cad, int l) {

17
char c; /* variable auxiliar para intercambio */
int i, j; /* variables para bucles */
int n = strlen(cad);

for(i = 0; i < n-l; i++) {


if(n-l > 2) Permutaciones(cad, l+1);
else cout << cad << ", ";
/* Intercambio de posiciones */
c = cad[l];
cad[l] = cad[l+i+1];
cad[l+i+1] = c;
if(l+i == n-1) {
for(j = l; j < n; j++) cad[j] = cad[j+1];
cad[n] = 0;
}
}
}

El algoritmo funciona del siguiente modo:

Al principio todos los elementos de la lista pueden cambiar de posición, es decir, pueden
permutar su posición con otro. No se fija ningún elemento de la lista, l = 0:
Permutaciones(cad, 0)

0 1 2 3 4

A B C D /0

Se llama recursivamente a la función, pero dejando fijo el primer elemento, el 0:


Permutacion(cad,1)

0 1 2 3 4

A B C D /0

Se llama recursivamente a la función, pero fijando el segundo elemento, el 1:


Permutacion(cad,2)

0 1 2 3 4

A B C D /0

Ahora sólo quedan dos elementos permutables, así que imprimimos ésta permutación, e
intercambiamos los elementos: l y l+i+1, es decir el 2 y el 3.

0 1 2 3 4

A B D C /0

18
Imprimimos ésta permutación, e intercambiamos los elementos l y l+i+1, es decir el 2 y el 4.

0 1 2 3 4

A B /0 C D

En el caso particular de que l+i+1 sea justo el número de elementos hay que mover hacia la
izquierda los elementos desde la posición l+1 a la posición l:

0 1 2 3 4

A B C D /0

En este punto abandonamos el último nivel de recursión, y retomamos en el valor de l=1 e i =


0.

0 1 2 3 4

A B C D /0

Permutamos los elementos: l y l+i+1, es decir el 1 y el 2.

0 1 2 3 4

A C B D /0

En la siguiente iteración del bucle i = 1, llamamos recursivamente con l = 2:


Permutaciones(cad,2)

0 1 2 3 4

A C B D /0

Imprimimos la permutación e intercambiamos los elementos 2 y 3.

0 1 2 3 4

A C D B /0

19
TEMAS

LPP (PUERTO PARALELO)

COM(PUERTO SERIE)

RS-32 (PUERTO SERIAL)

FIREWIRE

LPT O PUERTO PARALELO.

20
Aunque utilizados con mucha anterioridad, hasta la norma IEEE1284 en el 1.994 no se
normaliza.

Teóricamente el sistema de comunicación entre la impresora y el ordenador es más o menos


simple, aunque varía según el conector. Pero básicamente el ordenador envía impulsos a la
impresora y esta responde conforme que puede seguir enviando o no, es lo que se suele
denominar una respuesta de tipo "Low", y si no da tiempo a la impresión (prácticamente
siempre será más rápido el envío que la salida impresa) se irá almacenando en el buffer de
memoria de la impresora. En el caso de que éste se agote y siga recibiendo datos,
responderá con un "busy" y la cola de impresión del ordenador se detendrá a la espera de
recibir el nuevo "Low".

Los puertos de impresión se configuran en la Bios del ordenador y se denominan LPT (Line
PrinTer) y hay algunas en que pueden configurarse 2 y en otras 4, las direcciones varían, y
cada uno tiene tres registros: el de datos, el de estado y el de control.

Los estándares iniciales, a partir de la normativa indicada, eran los SPP (Standard Parallel
Port), que es el original, o al menos el compatible, con lo que se denominó desde sus inicios
el puerto Centronics. Uno de los motivos de que impresoras antiguas no funcionen con BIOS
nuevas es que por defecto este venga deshabilitado, con lo que en la configuración del LPT
correspondiente hay que indicar que debe de ser compatible con estos. Este modo acepta
hasta un máximo de 150 kb por segundo.

http://www.elrinconcito.com/DiccAmpliado/LPT.htm

Parte transmisora:

La parte transmisora checa la línea busy para ver si la parte receptora está ocupada. Si
la línea busy está activa, la parte transmisora espera en un bucle hasta que la línea busy
esté inactiva.
La parte transmisora coloca la información en las líneas de datos.
La parte transmisora activa la línea de strobe.
La parte transmisora espera en un bucle hasta que la línea acknowledge está activa.
La parte transmisora inactiva la línea de strobe.
La parte transmisora espera en un bucle hasta que la línea acknowledge esté inactiva.
La parte transmisora repite los pasos anteriores por cada byte a ser transmitido.

Parte receptora:

La parte receptora inactiva la línea busy (asumiendo que está lista para recibir
información).
La parte receptora espera en un bucle hasta que la línea strobe esté activa.
La parte receptora lee la información de las líneas de datos (y si es necesario, procesa
los datos).
La parte receptora activa la línea acknowledge.
La parte receptora espera en un bucle hasta que esté inactiva la línea de strobe.
La parte receptora inactiva la línea acknowledge.
La parte receptora repite los pasos anteriores por cada byte que debe recibir.

21
El hardware del puerto paralelo

El puerto paralelo de una típica PC utiliza un conector hembra de tipo D de 25 patitas


(DB-25 S), éste es el caso más común, sin embargo es conveniente mencionar los tres tipos
de conectores definidos por el estándar IEEE 1284, el primero, llamado 1284 tipo A es un
conector hembra de 25 patitas de tipo D, es decir, el que mencionamos al principio. El
orden de las patitas del conector es éste:

El segundo conector se llama 1284 tipo B que es un conector de 36 patitas de tipo


centronics y lo encontramos en la mayoría de las impresoras; el tercero se denomina 1284
tipo C, se trata de un conector similar al 1284 tipo B pero más pequeño, además se dice que
tiene mejores propiedades eléctricas y mecánicas, éste conector es el recomendado para
nuevos diseños. La siguiente tabla describe la función de cada patita del conector 1284 tipo
A:

Patita E/S Polaridad activa Descripción


1 Salida 0 Strobe
Líneas de datos
2~9 Salida -
(bit 0/patita 2, bit 7/patita 9)
Línea acknowledge
10 Entrada 0
(activa cuando el sistema remoto toma datos)
Línea busy
11 Entrada 0
(si está activa, el sistema remoto no acepta datos)
Línea Falta de papel
12 Entrada 1
(si está activa, falta papel en la impresora)
Línea Select
13 Entrada 1
(si está activa, la impresora se ha seleccionado)
Línea Autofeed
14 Salida 0 (si está activa, la impresora inserta una nueva
línea por cada retorno de carro)
Línea Error
15 Entrada 0
(si está activa, hay un error en la impresora)
Línea Init
(Si se mantiene activa por al menos 50
16 Salida 0
micro-segundos, ésta señal
autoinicializa la impresora)
Línea Select input
17 Salida 0 (Cuando está inactiva, obliga a la
impresora a salir de línea)

22
18 ~ 25 - - Tierra eléctrica

Tabla 1: Configuración del puerto paralelo estándar

Observe que el puerto paralelo tiene 12 líneas de salida (8 líneas de datos, strobe,
autofeed, init, y select input) y 5 de entrada (acknowledge, busy, falta de papel, select y
error). El estándar IEEE 1284 define cinco modos de operación:

1. Modo compatible
2. Modo nibble
3. Modo byte
4. Modo EPP, puerto paralelo ampliado
5. Modo ECP, puerto de capacidad extendida

El objetivo del estándar es diseñar nuevos dispositivos que sean totalmente compatibles
con el puerto paralelo estándar (SPP) definido originalmente por la IBM (en éste artículo
trataré solamente el modo compatible). Hay tres direcciones de E/S asociadas con un
puerto paralelo de la PC, estas direcciones pertenecen al registro de datos, el registro de
estado y el registro de control. El registro de datos es un puerto de lectura-escritura de
ocho bits. Leer el registro de datos (en la modalidad unidireccional) retorna el último valor
escrito en el registro de datos. Los registros de control y estado proveen la interface a las
otras líneas de E/S. La distribución de las diferentes señales para cada uno de los tres
registros de un puerto paralelo esta dada en las siguientes tablas:

Dirección Nombre Lectura/Escritura Bit # Propiedades


Base + 0 Puerto de datos Escritura Bit 7 Dato 7
Bit 6 Dato 6
Bit 5 Dato 5
Bit 4 Dato 4
Bit 3 Dato 3
Bit 2 Dato 2
Bit 1 Dato 1
Bit 0 Dato 0

Tabla 2: Registro de datos

Dirección Nombre Lectura/Escritura Bit # Propiedades


Base + 1 Puerto de estado Sólo Lectura Bit 7 Busy
Bit 6 Acknowledge
Bit 5 Falta de papel
Bit 4 Select In
Bit 3 Error
Bit 2 IRQ (Not)

23
Bit 1 Reservado
Bit 0 Reservado

Tabla 3: Registro de estado

Dirección Nombre Lectura/Escritura Bit # Propiedades


Base + 2 Puerto de control Lectura/Escritura Bit 7 No usado
Bit 6 No usado
Permite puerto
Bit 5
bidireccional
Permite IRQ a
través de la
Bit 4
línea
acknowledge
Selecciona
Bit 3
impresora
Inicializa
Bit 2
impresora
Nueva línea
Bit 1
automática
Bit 0 Strobe

Tabla 4: Registro de control

Una PC soporta hasta tres puertos paralelo separados, por tanto puede haber hasta
tres juegos de registros en un sistema en un momento dado. Existen tres direcciones base
para el puerto paralelo asociadas con tres posibles puertos paralelo: 0x3BCh, 0x378h y
0x278h, nos referimos a éstas como las direcciones base para el puerto LPT1, LPT2 y
LPT3, respectivamente. El registro de datos se localiza siempre en la dirección base de un
puerto paralelo, el registro de estado aparece en la dirección base + 1, y el registro de
control aparece en la dirección base + 2. Por ejemplo, para un puerto LPT2 localizado en
0x378h, ésta es la dirección del registro de datos, al registro de estado le corresponde la
dirección 0x379h y su respectivo registro de control está en la dirección 0x37Ah. Cuando
la PC se enciende el BIOS ejecuta una rutina para determinar el número de puertos
presentes en el sistema asignando la etiqueta LPT1 al primer puerto localizado, si existen
más puertos entonces se asignarán consecutivamente las etiquetas LPT2 y LPT3 de acuerdo
a la siguiente tabla:

Dirección inicial Función


0000:0408 Dirección base para LPT1
0000:040A Dirección base para LPT2
0000:040C Dirección base para LPT3
0000:040E Dirección base para LPT4

24
Tabla 5: Direcciones base en el BIOS

PUERTO PARALELO CENTRONICS

El puerto paralelo más conocido es el puerto de impresora (que cumplen más o menos la
norma IEEE 1284, también denominados tipo Centronics) que destaca por su sencillez y que
transmite 8 bits. Se ha utilizado principalmente para conectar impresoras, pero también ha
sido usado para programadores EPROM, escáneres, interfaces de red Ethernet a 10 MB,
unidades ZIP, SuperDisk y para comunicación entre dos PC (MS-DOS trajo en las versiones
5.0 ROM a 6.22 un programa para soportar esas transferencias).

El puerto paralelo de las computadoras, de acuerdo a la norma Centronics, está compuesto


por un bus de comunicación bidireccional de 8 bits de datos, además de un conjunto de
líneas de protocolo. Las líneas de comunicación cuentan con un retenedor que mantiene el
último valor que les fue escrito hasta que se escribe un nuevo dato, las características
eléctricas son:

 Tensión de nivel alto: 3,3 o 5 V.


 Tensión de nivel bajo: 0 V.
 Intensidad de salida máxima: 2,6 mA.
 Intensidad de entrada máxima: 24 mA.

Los sistemas operativos basados en DOS y compatibles gestionan las interfaces de puerto
paralelo con los nombres LPT1, LPT2 y así sucesivamente, Unix en cambio los nombra como
/dev/lp0, /dev/lp1, y demás. Las direcciones base de los dos primeros puertos son:

 LPT1 = 0x378.
 LPT2 = 0x278

La estructura consta de tres registros: de control, de estado y de datos.

 El registro de control es un bidireccional de 4 bits, con un bit de configuración que


no tiene conexión al exterior, su dirección en el LPT1 es 0x37A.
 El registro de estado, se trata de un registro de entrada de información de 5 bits,
su dirección en el LPT1 es 0x379.
 El registro de datos, se compone de 8 bits, es bidireccional. Su dirección en el LPT1
es 0x378.
 Inicialmente se colocó al puerto paralelo en la tarjeta del "Adaptador de impresora
de IBM", o también con la tarjeta del "monitor monocromático y adaptador de
impresora de IBM".
 Con la llegada de clones al mercado, se crea un controlador de múltiples entradas y
salidas (Multi I/O) donde se instalan controladores de discos, puertos serie, puerto
de juegos y el puerto paralelo.
 En la actualidad (2009) el puerto paralelo se incluye comúnmente incluido en la
placa madre de la computadora (MotherBoard). No obstante, la conexión del puerto
con el mundo externo no ha sufrido modificaciones. Este puerto utiliza un conector
hembra DB25 en la computadora y un conector especial macho llamado Centronic
que tiene 36 pines.

25
26
PUERTO SERIE (COM).

Puerto en serie ATX

Un puerto serie o puerto serial es una interfaz de comunicaciones de datos digitales,


frecuentemente utilizado por computadoras y periféricos, en donde la información es
transmitida bit a bit enviando un solo bit a la vez, en contraste con el puerto paralelo que
envía varios bits simultáneamente. La comparación entre la transmisión en serie y en
paralelo se puede explicar con analogía con las carreteras. Una carretera tradicional de un
sólo carril por sentido sería como la transmisión en serie y una autovía con varios carriles
por sentido sería la transmisión en paralelo, siendo los coches los bits.

PUERTO SERIE ASINCRÓNICO

El puerto serie RS-232 (también conocido como COM) es del tipo asincrónico, utiliza
cableado simple desde 3 hilos hasta 25 y que conecta computadoras o microcontroladores a
todo tipo de periféricos, desde terminales a impresoras y módems pasando por mouses.

La interfaz entre el RS-232 y el microprocesador generalmente se realiza mediante una


UART 8250 (computadoras de 8 y 16 bits, PC XT) o 16550 (IBM Personal Computer/AT y
posteriores).

El RS-232 original tenía un conector tipo DB-25, sin embargo la mayoría de dichos pines no
se utilizaban, por lo que IBM estandarizó con su gama IBM Personal System/2 el uso del
conector DE-9 (ya introducido en el AT) mayoritariamente usado en computadoras. Por
contra, excepto en los mouses el resto de periféricos solían presentar el DB-25

En Europa la norma RS-422, similar al RS-232, es un estándar utilizado en el ámbito


industrial.

PUERTOS SERIE MODERNOS

Uno de los defectos de los puertos serie iniciales era su lentitud en comparación con los
puertos paralelos -hablamos de 19.2 kbits por segundo- sin embargo, con el paso del tiempo,
están apareciendo multitud de puertos serie de alta velocidad que los hacen muy
interesantes ya que utilizan las ventajas del menor cableado y solucionan el problema de la
velocidad con un mayor apantallamiento y más barato usando la técnica del par trenzado.
Por ello, el puerto RS-232 e incluso multitud de puertos paralelos están siendo
reemplazados por nuevos puertos serie como el USB, el FireWire o el Serial ATA.

Un puerto de red puede ser puerto serie o puerto paralelo.

TIPOS DE COMUNICACIONES SERIALES

27
Simplex

En este caso el transmisor y el receptor están perfectamente definidos y la


comunicación es unidireccional. Este tipo de comunicaciones se emplean usualmente
en redes de radiodifusión, donde los receptores no necesitan enviar ningún tipo de
dato al transmisor.

Duplex, half duplex o semi-duplex

En este caso ambos extremos del sistema de comunicación cumplen funciones de


transmisor y receptor y los datos se desplazan en ambos sentidos pero no
simultáneamente. Este tipo de comunicación se utiliza habitualmente en la
interacción entre terminales y un computador central.

Full Duplex

El sistema es similar al duplex, pero los datos se desplazan en ambos sentidos


simultáneamente. Para ello ambos transmisores poseen diferentes frecuencias de
transmisión o dos caminos de comunicación separados, mientras que la comunicación
semi-duplex necesita normalmente uno solo. Para el intercambio de datos entre
computadores este tipo de comunicaciones son más eficientes que las transmisiones
semi-duplex.

Puerto serial

Los puertos seriales (también llamados RS-232, por el nombre del estándar al que hacen
referencia) fueron las primeras interfaces que permitieron que los equipos intercambien
información con el "mundo exterior". El término serial se refiere a los datos enviados
mediante un solo hilo: los bits se envían uno detrás del otro (consulte la sección sobre
transmisión de datos para conocer los modos de transmisión).

Originalmente, los puertos seriales sólo podían enviar datos, no recibir, por lo que se
desarrollaron puertos bidireccionales (que son los que se encuentran en los equipos
actuales). Por lo tanto, los puertos seriales bidireccionales necesitan dos hilos para que la
comunicación pueda efectuarse.
La comunicación serial se lleva a cabo asincrónicamente, es decir que no es necesaria una
señal (o reloj) de sincronización: los datos pueden enviarse en intervalos aleatorios. A su
vez, el periférico debe poder distinguir los caracteres (un carácter tiene 8 bits de
longitud) entre la sucesión de bits que se está enviando.
Ésta es la razón por la cual en este tipo de transmisión, cada carácter se encuentra
precedido por un bit de ARRANQUE y seguido por un bit de PARADA. Estos bits de

28
control, necesarios para la transmisión serial, desperdician un 20% del ancho de banda
(cada 10 bits enviados, 8 se utilizan para cifrar el carácter y 2 para la recepción).
Los puertos seriales, por lo general, están integrados a la placa madre, motivo por el cual
los conectores que se hallan detrás de la carcasa y se encuentran conectados a la placa
madre mediante un cable, pueden utilizarse para conectar un elemento exterior.
Generalmente, los conectores seriales tienen 9 ó 25 clavijas y tienen la siguiente forma
(conectores DB9 y DB25 respectivamente):

Un PC posee normalmente entre uno y cuatro puertos seriales.

Puerto paralelo

La transmisión de datos paralela consiste en enviar datos en forma simultánea por varios
canales (hilos). Los puertos paralelos en los PC pueden utilizarse para enviar 8 bits (un
octeto) simultáneamente por 8 hilos.

Los primeros puertos paralelos bidireccionales permitían una velocidad de 2,4 Mb/s. Sin
embargo, los puertos paralelos mejorados han logrado alcanzar velocidades mayores:

 El EPP (puerto paralelo mejorado) alcanza velocidades de 8 a 16 Mbps


 El ECP (puerto de capacidad mejorada), desarrollado por Hewlett Packard y Microsoft.
Posee las mismas características del EPP con el agregado de un dispositivo Plug and Play que
permite que el equipo reconozca los periféricos conectados.

Los puertos paralelos, al igual que los seriales, se encuentran integrados a la placa madre.
Los conectores DB25 permiten la conexión con un elemento exterior (por ejemplo, una
impresora).

El nombre de “serie” viene por el hecho de que un puerto serie “serializa” los datos. Esto
significa que coge un byte de datos y transmite los 8 bits que contiene el byte uno a la vez.
La ventaja es que los puertos serie solo necesitan un hilo para transmitir los 8 bits,
mientras que los paralelo necesitan 8. La desventaja es que lleva 8 veces más tiempo que si
tuviera 8 hilos. Los puertos serie bajan el coste de los cables y hacen que sean más
pequeños.

29
(serial port). Puerto para conectar un dispositivo a una computadora. La información se
transmiten por un solo conducto y por lo tanto bit a bit de forma serial. Por esta razón los
puertos seriales tradicionales son sumamente lentos y son usados para conectar el mouse o
el teclado. En cambio el puerto paralelo puede enviar múltiples bits en forma paralela.

La mayoría de los puertos serie de las PC obedecen el estándar RS-232C o el RS-422.

Las computadoras tienen dos puertos seriales: COM1 y COM2

Actualmente los puertos seriales modernos poseen grandes velocidades como el puerto
USB, el firewire o el SATA.

USB.

(Universal Serial Bus) Puerto de gran velocidad para comunicar computadoras y


periféricos. Soporta plug & play y conexión en caliente (hot plugging).

Soporta transferencias de 12 MBps. Un sólo puerto USB permite ser usado para conectar
más de 127 dispositivos periféricos como ratones, módems, teclados, impresoras, etc.

Comenzó a ser utilizado en 1996, pero la popularidad llegó en las iMac en 1998.

Prácticamente reemplazó a los puertos serial y puertos paralelo.

Versiones USB más populares disponibles:


* USB 1.1
* USB 2.0 (HiSpeed)
* USB 3.0 (SuperSpeed USB)
Definición de USB 2.0

USB 2.0 es un bus externo que soporta hasta 480 Mbits/s de transferencia de datos. Se
trata de una extensión del USB 1.1, por lo tanto utiliza los mismos cables y conectores, y es
compatible con éste.

Fue desarrollado por Hewlett-Packard, Intel, Lucent, Microsoft, NEC y Philips.

USB 2.0 fue lanzado en abril de 2000.

Definición de USB 3.0

(SuperSpeed USB). USB 3.0 es una de las versiones del USB, sucesora de la versión USB
2.0. Permite transferencias teóricas de hasta 4,8 Gbps.

Se lo ha llamado SuperSpeed USB, a diferencia de su versión anterior, la 2.0, llamada

30
HiSpeed.

USB 3.0 consume menos electricidad, es más rápida y sus puertos son compatibles con los
puertos USB 2.0.

Su desarrollo fue terminado en noviembre de 2008.

QUE ES UN PUERTO FIREWIRE.

Firewire se denomina al tipo de puerto de comunicaciones de alta velocidad desarrollado


por la compañía Apple.
La denominación real de esta interfaz es la IEEE 1394. Se trata de una tecnología para la
entrada/salida de datos en serie a alta velocidad y la conexión de dispositivos digitales.

Esta interfaz se caracteriza principalmente por:

- Su gran rapidez, siendo ideal para su utilización en aplicaciones multimedia y


almacenamiento, como videocámaras, discos duros, dispositivos ópticos, etc...

- Alcanzan una velocidad de 400 megabits por segundo, manteniéndola de forma bastante
estable.

- flexibilidad de la conexión y la capacidad de conectar un máximo de 63 dispositivos.

- Acepta longitudes de cable de hasta 425 cm.

- Respuesta en el momento. FireWire puede garantizar una distribución de los datos en


perfecta sincronía.

- Alimentación por el bus. Mientras el USB 2.0 permite la alimentación de dispositivos que
consuman un máximo de 5v, , los dispositivos FireWire pueden proporcionar o consumir
hasta 25v, suficiente para discos duros de alto rendimiento y baterías de carga rápida. En
este punto hay que hacer reseña de que existe un tipo de puerto Firewire que no suministra
alimentación, tan sólo da servicio de comunicación de datos. Estos puertos tienen sólo 4
contactos, en lugar de los 6 que tiene un puerto Firewire alimentado.

- Conexiones de enchufar y listo, conocidas como plug & play. No tenemos más que enchufar
un dispositivo para que funcione.

- Conexión en caliente (permite conectar dispositivos con el PC encendido sin ningún riesgo
de rotura).

31
Firewire

Bus serial de Apple; es un solo enchufe, pero pueden conectarse hasta 63 dispositivos.
Transfiere información de hasta 400 MB por segundos.
IEEE 1394

Logotipo de FireWire. Conector FireWire de 6 pins.

Connectores de 6 y 4 pins.

El IEEE 1394 (conocido como FireWire por Apple Inc. y como i.Link por Sony) es un
estándar multiplataforma para entrada/salida de datos en serie a gran velocidad. Suele
utilizarse para la interconexión de dispositivos digitales como cámaras digitales y
videocámaras a computadoras.

HISTORIA

El Firewire fue desarrollado por Apple Computer a mediados de los 90, para luego
convertirse en el estándar multiplataforma IEEE 1394. A principios de este siglo fue
adoptado por los fabricantes de periféricos digitales hasta convertirse en un estándar
establecido. Sony utiliza el estándar IEEE 1394 bajo la denominación i.Link, y Texas
Instruments bajo la denominación Lynx.

VERSIONES

Su velocidad hace que sea la interfaz más utilizada para audio y vídeo digital. Así, se usa
mucho en cámaras de vídeo, discos duros, impresoras, reproductores de vídeo digital,
sistemas domésticos para el ocio, sintetizadores de música y escáneres.

Existen tres versiones:

FIRE WIRE 400 (IEEE 1394-1995)

32
Lanzado en 1995. Tiene un ancho de banda de 400 Mbit/s, 30 veces mayor que el USB 1.1
(12 Mbps) y similar a la del USB 2.0 (480 Mbps), aunque en pruebas realizadas, en
transferencias de lectura de 5000 ficheros con un total de 300 Mb, FireWire completó el
proceso con un 33% más de velocidad que USB 2.0, debido a su arquitectura peer-to-peer
mientras USB utiliza arquitectura slave-master [1]. La longitud máxima permitida con un
único cable es de 4,5 metros, pudiendo utilizarse hasta 16 repetidores para prolongar la
longitud (no pudiendo sobrepasar nunca la distancia de 72 metros). Su conector está
dotado de 6 pines, dos de ellos destinados a la alimentación del dispositivo (excepto en la
versión distribuida por sony, iLink, que carece de estos dos pines de alimentación)
ofreciendo un consumo de unos 7 u 8 W por puerto a 25 V (nominalmente).

R EVISIÓN IEEE 1394 A -1995

En 2000 se implementó una revisión de IEEE 1394-1995, añadiéndole características como


difusión asíncrona, una reconfiguración de bus más rápida, concatenación de paquetes, y
ahorro de energía en modo suspensión.

FIRE WIRE 800 (IEEE 1394 B-2000)

Lanzado en 2000. Duplica aproximadamente la velocidad del FireWire 400, hasta 786.5
Mbps con tecnología full-duplex, cubriendo distancias de hasta 100 metros por cable.
Firewire 800 reduce los retrasos en la negociación, utilizando para ello 8b10b (código que
codifica 8 bits en 10 bits, que fue desarrollado por IBM y permite suficientes transiciones
de reloj, la codificación de señales de control y detección de errores. El código 8b10b es
similar a 4B/5B de FDDI (que no fue adoptado debido al pobre equilibrio de corriente
continua), que reduce la distorsión de señal y aumenta la velocidad de transferencia. Así,
para usos que requieran la transferencia de grandes volúmenes de información, resulta muy
superior al USB 2.0. Posee compatibilidad retroactiva con Firewire 400 utilizando cables
híbridos que permiten la conexión en los conectores de Firewire400 de 6 pines y los
conectores de Firewire800, dotados de 9 pines. No fue hasta 2003 cuando Apple lanzó el
primer uso comercial de Firewire800.

FIRE WIRE S1600 Y S3200 (IEEE 1394-2008)

Anunciado en Diciembre de 2007. Permiten un ancho de banda de 1'6 y 3'2 Gbit/s,


cuadruplicando la velocidad del Firewire 800, utilizando el mismo conector de 9 pines de
Firewire800

FIRE WIRE S800T (IEEE 1394 C-2006)

Anunciado en Junio de 2007. Aporta mejoras técnicas que permite el uso de FireWire con
puertos RJ45 sobre cable CAT 5, combinando así las ventajas de Ethernet con
Firewire800.

CARACTERÍSTICAS GENERALES

 Soporta la conexión de hasta 63 dispositivos con cables de una longitud máxima de


425 cm con topología en árbol.
 Soporte Plug-and-play.

33
 Soporta comunicación peer-to-peer que permite el enlace entre dispositivos sin
necesidad de usar la memoria del sistema o la CPU
 Soporta conexión en caliente.
 Todos los dispositivos Firewire son identificados por un identificador IEEE EUI-64
exclusivo (una extensión de las direcciones MAC Ethernet de 48-bit)

APLICACIONES DE FIRE WIRE

EDICIÓN DE VÍDEO DIGITAL

La edición de vídeo digital con FireWire ha permitido que tuviera lugar una revolución en la
producción del vídeo con sistemas de escritorio. La incorporación de FireWire en cámaras
de vídeo de bajo costo y elevada calidad permite la creación de vídeo profesional en
Macintosh o PC. Atrás quedan las carísimas tarjetas de captura de vídeo y las estaciones
de trabajo con dispositivos SCSI de alto rendimiento. FireWire permite la captura de
vídeo directamente de las nuevas cámaras de vídeo digital con puertos FireWire
incorporados y de sistemas analógicos mediante conversores de audio y vídeo a FireWire.

REDES IP SOBRE FIRE WIRE

Como explica Apple, "con este software instalado, se pueden utilizar entre computadoras
Macintosh y periféricos los protocolos IP existentes, incluyendo AFP, HTTP, FTP, SSH,
etcétera. En todos los casos, se puede utilizar Bonjour (Rendezvous) para su configuración,
resolución de nombres y descubrimiento." Si unimos la posibilidad de usar las conexiones
FireWire para crear redes TCP/IP a las prestaciones de FireWire 2 (FireWire 800),
tenemos razones muy serias para que Apple recupere rápidamente la atención de los
fabricantes de periféricos para satisfacer las necesidades de los usuarios de aplicaciones
que requieren gran ancho de banda en redes locales, como todas las relacionadas con el
vídeo digital. Por no hablar de introducirse en un posible mercado nuevo.

TEMAS

LICENCIAS

COPYRIGHT

GPL

GNU

LGPL

CREATIVE COMMONS

MIT

34
¿QUÉ ES UNA LICENCIA ?

Voy a intentar hacer una serie de anotaciones tratando el tema de las licencias de

Software, dando una visión general para repasar tres de las licencias que creo son más

interesantes: la MIT, la BSD y la GPL.

Hay muchas más licencias Open Source, aunque no todas son Software Libre. Estas tres

que he elegido tienen en común 3 puntos importantes: son licencias válidas para Software

Libre, son fáciles de aplicar y son compatibles entre sí.

No me he fijado en su uso, aunque las licencias BSD y GPL (más su variante LGPL) son las

más usadas (alrededor de un 77.5% de los proyectos en Sourceforge es un buen indicador),

sino en sus posibilidades y en su complejidad, siendo la MIT la más simple y la GPL la más

complicada de entender de las tres.

Por último, y antes de entrar en el tema, notar que no soy jurista y no soy experto en leyes.

No hay que tomar estas anotaciones como referencia ni mucho menos. Son solo

explicaciones de estar por casa y deben tomarse como tal. No atendamos a la forma y con

suerte se sacará algo útil del contenido :P.

En primer lugar es necesario definir qué es una licencia:

Una licencia es un documento que da permiso a hacer algo.

35
No es complicado de entender. Esta definición unida a los derechos de autor y aplicado a

los programas de computador ('Software' de ahora en adelante), es lo que entenderemos

aquí como acuerdo de licencia para el usuario final (EULA, en inglés).

El poseedor del copyright, una marca, una patente, o cualquier otra forma de propiedad

intelectual protegida por los derechos de autor, tiene todos los derechos sobre ese

elemento con cobertura legal: en nuestro caso el Software.

El hecho de que un programa sea Copyright © año Fulanito López implica que solo Fulanito

López tiene los derechos sobre ese programa (derecho de uso, copia, distribución; por

simplificar, pondría un enlace a la legislación española, pero ese ladrillo aclararía poco).

Así que esta EULA es necesaria ya que el Software no se compra como otros productos de

consumo. Se adquiere una copia, por la que se paga o no en concepto de distribución de

Software, y una licencia de uso. Nunca tenedremos todos derechos sobre ese producto, ya

que los retiene el titular del copyright.

Es la licencia un acuerdo entre el usuario y el propietario de los derechos. Este acuerdo

permite acotar al usuario lo que puede hacer y no hacer con el Software. La formula es: si

cumples unas condiciones, puedes hacer estas cosas con mi Software .

En base al ciertos aspectos de la licencia podemos definir dos clases de Software: el

Software privativo y el Software Libre.

El Software privativo se centra, como elemento más destacable, en limitar lo que se puede

hacer con el producto. Por lo general se puede decir que el Software privativo cumple lo

siguiente:

 Hay restricciones a su uso.

 No está disponible el código fuente, por lo que su estudio está limitado y su

modificación es imposible.

 No pueden ser copiados y distribuidos.

El Software Libre, por el contrario, se centra en ceder parte de los derechos sobre el

producto, es decir, en dar libertades. Por lo general se puede decir que el Software Libre

cumple lo siguiente:

36
 Se puede usar por cualquiera para cualquier propósito: no hay restricciones de uso.

 Puede ser estudiado y modificado, para ello se dispone del código fuente.

 Se puede copiar y redistribuir, con o sin modificaciones.

Aunque las licencias del Software privativo siempre tienen una cláusula final en la que

limitan su responsabilidad o la garantía que proporcionan sobre el producto que cubren, en

el caso del Software Libre esto es indispensable.

Esta necesidad se deriva directamente del hecho de que cualquiera puede modificar el

producto y redistribuirlo con esos cambios. El titular del copyright nunca podrá ser

responsable de esos cambios realizados por terceros de los que puede que ni siquiera tenga

constancia.

De esta forma todas las licencias que voy a repasar tienen tres partes:

1. Unas condiciones a cumplir.

2. Unos derechos cedidos por el titular del copyright.

3. Una limitación de responsabilidad.

Licencia copyright

El derecho de autor y copyright constituyen dos concepciones sobre la propiedad literaria


y artística. El primero proviene de la familia delderecho continental, particularmente
del derecho francés, mientras que el segundo procede del derecho anglosajón (o common
law).

El derecho de autor se basa en la idea de un derecho personal del autor, fundado en una
forma de identidad entre el autor y su creación. El derecho moral está constituido como
emanación de la persona del autor: reconoce que la obra es expresión de la persona del
autor y así se le protege.

La protección del copyright se limita estrictamente a la obra, sin considerar atributos


morales del autor en relación con su obra, excepto la paternidad; no lo considera como un
autor propiamente tal, pero tiene derechos que determinan las modalidades de utilización
de una obra.

37
En 1790, la obras protegidas por la Copyright Act de Estados Unidos eran sólo los "mapas,
cartas de navegación y libros" (no cubría las obrasmusicales o de arquitectura).
Este copyright otorgaba al autor el derecho exclusivo a publicar las obras, por lo que sólo
se violaba tal derecho si reimprimía la obra sin el permiso de su titular. Además, este
derecho no se extendía a las "obras derivadas" (era un derecho exclusivo sobre la obra en
particular), por lo que no impedía las traducciones o adaptaciones de dicho texto. Con los
años, el titular del copyright obtuvo el derecho exclusivo a controlar cualquier publicación
de su obra. Sus derechos se extendieron, de la obra en particular, a cualquier "obra
derivada" que pudiera surgir en base a la "obra original".

Asimismo, el Congreso de Estados Unidos incrementó en 1831 el plazo inicial


del copyright de 14 a 28 años (o sea, se llegó a un máximo de 42 años de protección) y
en 1909 extendió el plazo de renovación de 14 a 28 años (obteniéndose un máximo de 56
años de protección). Y, a partir de los años 50, comenzó a extender los plazos existentes
en forma habitual (1962, 1976 y 1998).

El símbolo ℗ (una letra "P" mayúscula ubicada dentro de un círculo) representa la reserva
de los "derechos de autor sobre una grabación sonido" (música) y es la abreviatura para la
palabra "fonógrafo" (phonograph en inglés) o registro fonográfico. Este símbolo hace
referencia más directamente a la obra musical en sí grabada en un
determinado disco, casete, CD, etc., de hecho, es muy común verlo impreso en las
contraportadas de los álbumes musicales.

Por otro lado, el símbolo © (una letra "C" mayúscula dentro de una circunferencia) hace
referencia más propiamente al derecho de autor (copyright) sobre obras intelectuales de
otra índole, como por ejemplo: libros, folletos, obras dramáticas, obras cinematográficas y
audiovisuales; dibujos, pinturas etc.

La diferencia entre el significado de un símbolo y otro es muy tenue.

Licencia GPL

Una de las más utilizadas es la Licencia Pública General de GNU (GNU GPL). El autor
conserva los derechos de autor (copyright), y permite la redistribución y modificación bajo
términos diseñados para asegurarse de que todas las versiones modificadas del software
permanecen bajo los términos más restrictivos de la propia GNU GPL. Esto hace que sea
imposible crear un producto con partes no licenciadas GPL: el conjunto tiene que ser GPL.

38
Es decir, la licencia GNU GPL posibilita la modificación y redistribución del software, pero
únicamente bajo esa misma licencia. Y añade que si se reutiliza en un mismo programa
código "A" licenciado bajo licencia GNU GPL y código "B" licenciado bajo otro tipo de
licencia libre, el código final "C", independientemente de la cantidad y calidad de cada uno
de los códigos "A" y "B", debe estar bajo la licencia GNU GPL.

En la práctica esto hace que las licencias de software libre se dividan en dos grandes
grupos, aquellas que pueden ser mezcladas con código licenciado bajo GNU GPL (y que
inevitablemente desaparecerán en el proceso, al ser el código resultante licenciado bajo
GNU GPL) y las que no lo permiten al incluir mayores u otros requisitos que no contemplan
ni admiten la GNU GPL y que por lo tanto no pueden ser enlazadas ni mezcladas con código
gobernado por la licencia GNU GPL.

En el sitio web oficial de GNU hay una lista de licencias que cumplen las condiciones
impuestas por la GNU GPL y otras que no.4

Aproximadamente el 60% del software licenciado como software libre emplea una licencia
GPL.

A finales de 2005, la Free Software Foundation anunció que trabajaba en la versión 3 de la


licencia GPL, cuyo primer borrador fue presentado para su discusión pública el 16 de
enero de 2006. La discusión se alargó 18 meses, habiendo sido publicados cuatro
borradores. Finalmente, la versión oficial fue publicada el día 29 de junio de 2007 y es
accesible a través del Portal de GNU.4 La nueva versión contempla los siguientes aspectos:

 Las diversas formas en que alguna persona podría quitar libertades a los usuarios.
 Prohibir el uso de software libre en sistemas diseñados para quitar libertades (DRM).
 Resolver ambigüedades y aumentar la compatibilidad de GPLv3 con otras licencias.
 Facilitar su adaptación a otros países.
 Incluir cláusulas que defiendan a la comunidad de software libre del uso indebido de
las patentes de software.
 Mostrar usuarios registrados.
Licencia GNU

La Licencia Pública General de GNU o más conocida por su nombre en inglés GNU General
Public License o simplemente su acrónimo del inglés GNU GPL, es una licencia creada por
la Free Software Foundation a mediados de los 80, y está orientada principalmente a
proteger la libre distribución, modificación y uso de software. Su propósito es declarar que
el software cubierto por esta licencia essoftware libre y protegerlo de intentos de
apropiación que restrinjan esas libertades a los usuarios.

39
Existen varias licencias "hermanas" de la GPL, como la licencia de documentación libre de
GNU(GFDL) que cubre los artículos de la Wikipedia, la Open Audio License, para trabajos
musicales, etcétera, y otras menos restrictivas, como la MGPL, o la LGPL (Lesser General
Public License, antesLibrary General Public License), que permiten el enlace dinámico de
aplicaciones libres a aplicaciones no libres.

GNU/Linux (Linux) es uno de los términos empleados para referirse al sistema


operativo libre similar aUnix que utiliza el núcleo Linux y herramientas de sistema GNU. Su
desarrollo es uno de los ejemplos más prominentes de software libre; todo el código
fuente puede ser utilizado, modificado y redistribuido libremente por cualquiera bajo los
términos de la GPL (Licencia Pública General de GNU) y otras licencias libres.1

A pesar de que Linux sólo es el núcleo de este sistema operativo una parte significativa de
la comunidad, así como muchos medios generales y especializados, prefieren utilizar dicho
término. Para más información consulte la sección "Denominación GNU/Linux" o el
artículo "Controversia por la denominación GNU/Linux".

Las variantes de este sistema se denominan distribuciones y su objetivo es ofrecer una


edición que cumpla con las necesidades de determinado grupo de usuarios.

Algunas distribuciones son especialmente conocidas por su uso


en servidores y supercomputadoras.2No obstante, es posible instalar GNU/Linux en una
amplia variedad de hardware como computadoras de escritorio y portátiles.

En el caso de computadoras de bolsillo, teléfonos móviles, dispositivos


empotrados, videoconsolas y otros, puede darse el caso en que las partes de GNU se
remplacen por alternativas más adecuadas. Para saber más sobre las arquitecturas
soportadas, lea el artículo "Portabilidad del núcleo Linux y arquitecturas soportadas".

Licencia LGPL

La Licencia Pública General Reducida de GNU, o más conocida por su nombre en inglés GNU
Lesser General Public License (antes GNU Library General Public License o Licencia Pública
General para Bibliotecas de GNU), o simplemente por su acrónimo del inglés GNU LGPL es
una licencia de software creada por la Free Software Foundation. Los contratos
de licencia de la mayor parte delsoftware están diseñados para jugar con su libertad de
compartir y modificar dicho software. En contraste, la GNU General Public
License pretende garantizar su libertad de compartir y modificar el software "libre", esto
es para asegurar que el software es libre para todos sus usuarios. Esta licencia pública
general se aplica a la mayoría del software de la FSF o Free Software

40
Foundation (Fundación para el software libre) y a cualquier otro programa de software
cuyos autores así lo establecen. Algunos otros programas de software de la Free Software
Foundation están cubiertos por la "LGPL Lesser General Public License" (Licencia pública
general reducida), la cual puede aplicar a sus programas también.

Esta licencia permisiva se aplica a cualquier programa o trabajo que contenga una nota
puesta por el propietario de los derechos del trabajo estableciendo que su trabajo puede
ser distribuido bajo los términos de esta "GPL General Public License". El "Programa",
utilizado en lo subsecuente, se refiere a cualquier programa o trabajo original, y el "trabajo
basado en el Programa" significa ya sea el programa o cualquier trabajo derivado del mismo
bajo la ley de derechos de autor: es decir, un trabajo que contenga el Programa o alguna
porción de él, ya sea íntegra o con modificaciones o traducciones a otros idiomas.

Otras actividades que no sean copia, distribución o modificación si están cubiertas en esta
licencia y están fuera de su alcance. El acto de ejecutar el programa no está restringido, y
la salida de información del programa está cubierta sólo si su contenido constituye un
trabajo basado en el Programa (es independiente de si fue resultado de ejecutar el
programa). Si esto es cierto o no depende de la función del programa.

El proyecto OpenOffice.org de Sun Microsystems emplea la LGPL.

El término "GNU Library General Public License" daba la impresión de que la FSF quería que
todas las bibliotecas utilizaran la licencia LGPL y todos los programas utilizaran la licencia
GPL. En febrero de 1999 Richard Stallman escribió el documento "Por qué en su próxima
biblioteca no debería utilizar la GPL para Bibliotecas"1 explicando porqué este no era el
caso, y que la LGPL no se debería utilizar necesariamente para bibliotecas:

Qué licencia es la mejor para una cierta biblioteca es una cuestión de estrategia, y
depende de los detalles de la situación. Actualmente, la mayoría de las bibliotecas GNU
están cubiertas por la GPL para bibliotecas, y eso significa que estamos utilizando
únicamente una de estas dos estrategias, descuidando la otra. Así que ahora pretendemos
que se publiquen más bibliotecas bajo la GPL ordinaria.

Sin embargo, contrario a la impresión general, esto no significa que la FSF infravalore la
LGPL, sino simplemente dice que no debería ser utilizada para todas las bibliotecas. En el
mismo documento se lee:

Hay razones que pueden hacer más apropiado el uso de la GPL para bibliotecas en ciertos
casos. El caso más común es cuando las características de la biblioteca libre están ya
disponibles para software privativo a través de otras bibliotecas alternativas. En ese caso,
la biblioteca no puede dar al software libre ninguna ventaja en particular, así que es mejor
utilizar la GPL para bibliotecas para esa biblioteca.

41
De hecho, Stallman y la FSF abogan por el uso de licencias incluso menos restrictivas que la
LGPL como estrategia (para maximizar la libertad de los usuarios). Un ejemplo destacado
es la aprobación de Stallman para utilizar la licencia BSD en el proyecto Vorbis.2

Licencia creative commons

Creative Commons es una organización no gubernamental sin ánimo de lucro que desarrolla
planes para ayudar a reducir las barreras legales de la creatividad, por medio de
nueva legislacióny nuevas tecnologías. Fue fundada por Lawrence Lessig, profesor
de derecho en la Universidad de Stanford y especialista en ciberderecho, que la presidió
hasta marzo de 2008.

Creative Commons (en español: «bienes comunes creativos») es también el nombre dado a
laslicencias desarrolladas por esta organización.

Las licencias Creative Commons o CC están inspiradas en la licencia GPL (General Public
License) de la Free Software Foundation, sin embargo no son un tipo de licenciamiento de
software. La idea principal es posibilitar un modelo legal ayudado por
herramientas informáticaspara así facilitar la distribución y el uso de contenidos.

Existe una serie de licencias Creative Commons, cada una con diferentes configuraciones o
principios, como el derecho del autor original a dar libertad para citar su obra,
reproducirla, crear obras derivadas, ofrecerla públicamente y con diferentes restricciones
como no permitir el uso comercial o respetar la autoría original.

Una de las licencias que ofrecía Creative Commons es la que llevaba por nombre "Developing
Nations" (Naciones en Desarrollo), la cual permitía que los derechos de autor y regalías por
el uso de las obras se cobraran sólo en los países desarrollados del primer mundo, mientras
que se ofrecían de forma abierta en los países en vías de desarrollo. Esta licencia ha sido
retirada por problemas comerciales.

Aunque originalmente fueron redactadas en inglés, las licencias han sido adaptadas a varias
legislaciones en otros países del mundo. Entre otros idiomas, han sido traducidas al español,
al portugués, al gallego, al euskera y al catalán a través del proyecto Creative Commons
International. Existen varios países de habla hispana que están involucrados en este
proceso: España, Chile, Guatemala, Argentina, México,Perú, Colombia y Puerto Rico ya
tienen las licencias traducidas y en funcionamiento, en tanto que Ecuador y Venezuela se
encuentran en proceso de traducción e implementación de las mismas. Brasil también tiene
las licencias traducidas y adaptadas a su legislación.
Licencia MIT

42
Seguimos con esta serie sobre licencias de Software. Ya describí más o menos lo que es una

licencia, y ahora vamos a revisar la primera de la lista: la licencia MIT.

Se trata de una de tantas licencias que ha empleado el MIT ( Massachusetts Institute of

Technology) a lo largo de su historia, y quizás debería llamarse más correctamente 'licencia


X11', ya que es la licencia que llevaba este Software originario del MIT en los años 80. Pero

ya sea como MIT o X11, su forma es idéntica.

Es una licencia sin copyright, lo que nos permite modificarla y adaptarla a nuestras

necesidades. No obstante esto puede no ser recomendable, e incluso muchas voces dentro

del Open Source lo desaconsejan. Recordemos que las licencias es un terreno escabroso

difícil de transitar, y si un usuario o desarrollador ve que un paquete tiene licencia MIT

siempre sabrá a qué atenerse. La cosa es distinta si la licencia está 'basada en la licencia

MIT', lo que obligaría a una revisión para asegurarse de qué efectos tienen esas

modificaciones. Siempre es más fácil elegir una licencia existente, que las hay para todos

los gustos, en lugar de jugar a entender de leyes :).

Como ya veremos, la licencia BSD es muy parecida a la licencia MIT en cuanto a efectos.

Pero veamos la forma:

Copyright (c) <year> <copyright holders>

Permission is hereby granted, free of charge, to any

person obtaining a copy of this software and associated

documentation files (the "Software"), to deal in the

Software without restriction, including without limitation

the rights to use, copy, modify, merge, publish,

distribute, sublicense, and/or sell copies of the

Software, and to permit persons to whom the Software is

furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice

shall be included in all copies or substantial portions of

the Software.

43
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY

KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE

WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR

PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS

OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR

OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR

OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE

SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

El texto diferencia los tres puntos que comentamos en la pasada entrega: condiciones,

derechos y limitación de responsabilidad.

La condición es que la nota de copyright y la parte de los derechos se incluya en todas las

copias o partes sustanciales del Software. Esta es la condición que invalidaría la licencia en

caso de no cumplirse.

Los derechos son muchos: sin restricciones; incluyendo usar, copiar, modificar, integrar con

otro Software, publicar,sublicenciar y/o vender copias del Software, y además permitir a

las personas a las que se les entregue el Software hacer lo mismo.

Finalmente tenemos un disclaimer o nota de limitación de la responsabilidad estándar.

Ahora vamos a ver algunas características y usos de esta licencia.

Debido a la palabra resaltada en los derechos, tenemos que esta licencia permite reutilizar

el Software así licenciado tanto para ser Software Libre como para ser Software

privativo. Esto significa que el hecho de permitir sublicenciar puede llevar a un trabajo

derivado que sea cerrado, o incluso bajo la licencia BSD, GPL, u otra cualquiera compatible

con la MIT.

Esto puede ser una ventaja, en caso de hacer un producto que en un momento dado puede

aportar un beneficio por cerrarse (por ejemplo en esquemas de licencias duales: se trabaja

con MIT para uso comercial a cambio de una retribución económica, y se sublicencia GPL

44
para el uso de la comunidad). Pero también un inconveniente si no deseamos que nuestro

trabajo se utilice en un producto cerrado.

Su aplicación es muy sencilla. Solo tendremos que añadir al fuente el texto de la licencia

con el año en que liberamos ese fuente y nuestro nombre completo (y si puede ser una

dirección de contacto, el e-mail es suficiente).

Con esta licencia tenemos Software Libre. Nos puede interesar si tenemos una estrategia

comercial basada, por ejemplo, en las licencias duales; si pretendemos que nuestro

desarrollo se convierta en un estándar y queremos facilitar su implantación, o si

simplemente pretendemos que nuestro producto sea Libre sin mayores consideraciones.

Yo la empleo con frecuencia en desarrollos a medida en los que el cliente paga el I+D.

Obligatoriamente, y si no se pacta explícitamente otra cosa, he de entregar el fuente, ya

que es el cliente el que ha pagado el desarrollo y el producto le pertenece. El hecho de usar

la licencia MIT me permite beneficiarme de ese código para proyectos posteriores, y el

cliente no pone pegas porque reutilizo código existente y abarato el producto final.

TEMAS

CAMPOS DE BITS

HILOS

SYSTEM.OBJECT

SET(C#)

GET(C#)

CAMPOS DE BITS

S INOPSIS

Los campos de bits, o simplemente campos, son grupos de un número determinado de bits,
que pueden o no tener un identificador asociado. Representan un artificio que permite

45
utilizar miembros de tamaño arbitrario en estructuras, uniones y clases; independiente de
la posibilidad que proporcionan los tipos básicos ( 2.2.1) cuyo tamaño está
predeterminado por el lenguaje. Por ejemplo, en ocasiones es necesario almacenar
semáforos (flags) con determinados estados del programa, para los que en realidad solo
hace falta un bit, pero incluso una variable bool ocupa un octeto. Los campos de bits
permiten utilizar cada bit de un octeto independientemente, aumentando así su capacidad
de representación.

Nota: esta técnica, de manejo independiente de bits en una palabra, ha sido ampliamente
utilizada desde siempre en la programación, no solo de C/C++; casi todos los lenguajes
ofrecen la posibilidad de operadores "bitwise", que permiten esto de forma más o menos
artesanal.

Entre otros usos, los campos de bits se han utilizado históricamente para empaquetar
variables en un espacio más pequeño, pero obligan al compilador a generar código adicional
para manejarlos, lo que resulta costoso en términos de tamaño y velocidad del ejecutable.
El resultado es que frecuentemente, el código resulta mayor y más lento si se usan estos
tipos, por lo que generalmente se desaconseja su uso excepto para aplicaciones muy
específicas de bajo nivel, en las que la alineación exacta de los patrones de bits a utilizar
es un aspecto primordial. Por ejemplo, transmisiones de datos

Otra cuestión distinta, a veces decisiva para su utilización, es la significativa reducción de


espacio de almacenamiento externo (disco por ejemplo) que puede conseguirse cuando en
determinados casos, se almacena gran número de registros que utilizan campos de bits en
sustitución de tipos básicos.

D ECLARACIÓN

La sintaxis para declaración de campos es la siguiente:

especificador-de-tipo <identificador> : ancho;

Ejemplos:

int Uno : 8;
unsigned int Dos : 16;
int : 2;

El especificador-de-tipo puede ser alguno de los siguientes: bool; char; unsigned char;
short; unsigned short; long; unsigned long; int; unsigned int; __int64 o unsigned __int64.
Abreviadamente lo denominaremos tipo del campo.

Definición de Interfaz

1. En software, parte de un programa que permite el flujo de información entre un usuario


y la aplicación, o entre la aplicación y otros programas o periféricos. Esa parte de un

46
programa está constituida por un conjunto de comandos y métodos que permiten estas
intercomunicaciones.

2. Intefaz también hace referencia al conjunto de métodos para lograr interactividad


entre un usuario y una computadora. Una interaz puede ser del tipo GUI, o línea de
comandos, etc. También puede ser a partir de un hardware, por ejemplo, el monitor, el
teclado y el mouse, son interfaces entre el usuario y el ordenador.

En C#, una clase es un tipo de datos muy eficaz. Como las estructuras, las clases definen
los datos y el comportamiento del tipo de datos. Los programadores pueden crear objetos
que son instancias de una clase. A diferencia de las estructuras, las clases admiten
herencia, que es una parte fundamental de la programación orientada a objetos. Para
obtener más información, vea Herencia.

DECLARAR CLASES

Las clases se definen mediante la palabra clave class, como se muestra en el ejemplo
siguiente:

C#

public class Customer


{
//Fields, properties, methods and events go here...
}

El nivel de acceso precede a la palabra clave class. En este caso, se utiliza public, que
significa que cualquiera puede crear objetos a partir de esta clase. El nombre de la clase
sigue a la palabra clave class. El resto de la definición es el cuerpo de clase, donde se
definen el comportamiento y los datos. Los campos, propiedades, métodos y eventos de una
clase se conocen colectivamente como miembros de clase.

CREAR OBJETOS

Aunque se utilizan a veces de forma intercambiable, una clase y un objeto son cosas
diferentes. Una clase define un tipo de objeto, pero no es propiamente un objeto. Un
objeto es una entidad concreta basada en una clase y, a veces, se denomina instancia de una
clase.

Los objetos se pueden crear con la palabra clave new seguida del nombre de la clase en la
que se basará el objeto, de la manera siguiente:

C#

Customer object1 = new Customer();

47
Cuando se crea una instancia de una clase, una referencia al objeto se vuelve a pasar al
programador. En el ejemplo anterior, object1 es una referencia a un objeto basado en
Customer. Esta referencia hace referencia el nuevo objeto, pero no contiene los datos del
propio objeto. De hecho, se puede crear una referencia a objeto sin crear un objeto:

C#

Customer object2;

No se recomienda la creación de referencias a objetos como ésta, que no hace referencia a


un objeto, porque al intentar el acceso a un objeto a través de esa referencia se producirá
un error en tiempo de ejecución. Sin embargo, este tipo de referencia se puede crear para
hacer referencia a un objeto, ya sea creando un nuevo objeto o asignándola a un objeto
existente, de la forma siguiente:

C#

Customer object3 = new Customer();


Customer object4 = object3;

Este código crea dos referencias a objeto que se refieren al mismo objeto. Por
consiguiente, los cambios realizados en el objeto a través de object3 se reflejarán en los
usos posteriores de object4. El hecho de que las clases se conozcan como tipos de
referencia se debe a que se hace referencia a los objetos basados en clases por
referencia.

HERENCIA DE CLASE

La herencia se realiza a través de una derivación, lo que significa que una clase se declara
utilizando una clase base de la cual hereda los datos y el comportamiento. Una clase base
se especifica anexando dos puntos y el nombre de la clase base a continuación del nombre
de la clase derivada, del modo siguiente:

C#

public class Manager : Employee


{
// Employee fields, properties, methods and events are inherited
// New Manager fields, properties, methods and events go here...
}

Cuando una clase declara una clase base, todos los miembros de clase definidos para la
clase base también pasan a formar parte de la nueva clase. Dado que una clase base se
puede heredar de otra clase, que a su vez se heredó de otra clase y así sucesivamente, una
clase puede provenir de varias clases base.

Las estructuras se definen mediante la palabra clave struct, por ejemplo:

48
C#

public struct PostalAddress


{
// Fields, properties, methods and events go here...
}

Casi todas las estructuras comparten la misma sintaxis que las clases, aunque están más
limitadas que éstas:

 Dentro de una declaración de estructura, los campos no se pueden inicializar a


menos que se declaren como constantes o estáticos.
 Una estructura no puede declarar un constructor predeterminado (es decir, un
constructor sin parámetros) ni un destructor.

El compilador crea y destruye automáticamente copias de estructuras, de modo que un


constructor y destructor predeterminados son innecesarios. De hecho, el compilador
implementa el constructor predeterminado asignando a todos los campos sus valores
predeterminados (vea Tabla de valores predeterminados (Referencia de C#)). Las
estructuras no pueden heredar de clases u otras estructuras.

Las estructuras son tipos de valor; cuando un objeto se crea a partir de una estructura y
se asigna a una variable, la variable contiene el valor completo de la estructura. Cuando se
copia una variable que contiene una estructura, todos los datos se copian y cualquier
modificación a la nueva copia no cambia los datos de la copia antigua. Como las estructuras
no utilizan referencias, no tienen identidad; no existe ninguna forma de distinguir entre
dos instancias de un tipo de valor con los mismos datos. En C#, todos los tipos de valor
derivan inherentemente de ValueType, que hereda de Object.

El compilador puede convertir tipos de valor en tipos de referencia en un proceso conocido


como conversión boxing. Para obtener más información, vea Boxing y Unboxing.

INFORMACIÓN GENERAL SOBRE LAS ESTRUCTURAS

Las estructuras tienen las propiedades siguientes:

 Las estructuras son tipos de valor, mientras que las clases son tipos de referencia.
 A diferencia de las clases, se pueden crear instancias de las estructuras sin utilizar
un operador new.
 Las estructuras pueden declarar constructores, pero deben utilizar parámetros.
 Una estructura no puede heredar de otra estructura o clase, ni puede ser la base
de una clase. Todas las estructuras heredan directamente de System.ValueType,
que hereda de System.Object.
 Una estructura puede implementar interfaces.

HILOS

49
La creación de cada hilo se realiza mediante las líneas Thread th1 = new Thread(new
ThreadStart(msg.Mostrar1));. Esta línea indica que se crea una instancia de la clase
Thread, con nombre th1, a partir de un delegado de la clase ThreadStart, que apunta al
método Mostrar1 del objeto msg creado anteriormente.

Una vez creados los dos hilos hay que activarlos, para lo que se llama al método Start de
cada uno de ellos. Tras este punto cada hilo se ejecuta en paralelo entre si, y con el
programa principal, por lo que utilizamos el método Join de ambos hilos para esperar a que
terminen los hilos antes de finalizar el programa.

El delegado ThreadStart no acepta parámetros de entrada ni de salida, por lo que si


queremos crear un hilo sobre un método que los necesite, hay que utilizar algún mecanismo
auxiliar. Una posible forma de conseguir esto es crear una nueva clase con los parámetros
necesarios en la entrada y con un nuevo método sin parámetros que llame al método que
queremos hacer paralelo, enviándole estos parámetros. A partir de aquí tendríamos que
crear una instancia de dicha clase con los parámetros que queremos enviar al método
original, y hacer que el hilo se ejecutase sobre el nuevo método de la clase. En el caso de
que quisiéramos obtener el resultado de la ejecución, deberíamos crear una función que
acepte como parámetro de entrada el tipo del valor devuelto por el método original, y hacer
que la nueva clase creada disponga también de un delegado que indique la función a la que
llamar tras la ejecución.

Como esto puede parecer un poco lioso, vamos a ver otro ejemplo. En esta ocasión
disponemos de una clase de funciones matemáticas y queremos llamar de forma paralela a
una de ellas. Este método acepta un valor entero en la entrada y devuelve otro entero.

using System;
using System.Threading;
using System.IO;

public class EjemploMates{

public static int CalculoComplejo(int n)


{
// sumo uno y espero 5 segundos
n = n+1;
Thread.Sleep(5000);
return n;
}

public class HiloParaMates{


protected int n;
protected MatesCallback callback = null;
public HiloParaMates(int n, MatesCallback callback){
this.n = n;
this.callback = callback;
}
public void CalculoComplejo()

50
{
int result = EjemploMates.CalculoComplejo(n);
if(callback != null)
callback(result);
}
}

// creo un delegado con la firma necesaria para capturar


// el valor devuelto por el método CalculoComplejo
public delegate void MatesCallback(int n);

public class Ejemplo{

public static void Main()


{
HiloParaMates hpm = new HiloParaMates(1000, new MatesCallback(ResultCallback));

Thread th = new Thread(new ThreadStart(hpm.CalculoComplejo));

th.Start();
th.Join();

public static void ResultCallback(int n)


{
Console.WriteLine("Resultado de la operación: "+n);
}
}

En el anterior código la clase HiloParaMates es la que nos permite encapsular la llamada al


método EjemploMates.Calcular. Este método requiere un parámetro de tipo entero, por lo
que la clase requiere este parámetro en su constructor. Además se requiere en el
constructor otro parámetro más, un delegado MatesCallback, que acepta un entero en la
entrada. La idea es que tras realizar el cálculo se llame al método que se indique
proporcionándole el resultado.

Para hacer funcionar todo esto, en Main se crea una instancia de la clase HiloParaMates
indicándole que queremos utilizar el valor numérico 1000 y que se llame al método
(estático) ResultCallback cuando se obtenga el resultado. Para crear el hilo es suficiente
con indicar que se quiere hacer sobre el método CalculoComplejo de la instancia hpm.

System. Object

Ahora que sabemos lo que es la herencia es el momento apropiado para explicar que en
.NET todos los tipos que se definan heredan implícitamente de la clase System.Object
predefinida en la BCL, por lo que dispondrán de todos los miembros de ésta. Por esta razón
se dice que System.Object es la raíz de la jerarquía de objetos de .NET.

51
A continuación vamos a explicar cuáles son estos métodos comunes a todos los objetos:

 public virtual bool Equals(object o): Se usa para comparar el objeto sobre el que se
aplica con cualquier otro que se le pase como parámetro. Devuelve true si ambos
objetos son iguales y false en caso contrario.

La implementación que por defecto se ha dado a este método consiste en usar


igualdad por referencia para los tipos por referencia e igualdad por valor para los
tipos por valor. Es decir, si los objetos a comparar son de tipos por
referencia sólo se devuelve true si ambos objetos apuntan a la misma referencia en
memoria dinámica, y si los tipos a comparar son tipos por valor sólo se devuelve true
si todos los bits de ambos objetos son iguales, aunque se almacenen en posiciones
diferentes de memoria.

Como se ve, el método ha sido definido como virtual, lo que permite que los
programadores puedan redefinirlo para indicar cuándo ha de considerarse que son
iguales dos objetos de tipos definidos por ellos. De hecho, muchos de los tipos
incluidos en la BCL cuentan con redefiniciones de este tipo, como es el caso de
string, quien aún siendo un tipo por referencia, sus objetos se consideran iguales si
apuntan a cadenas que sean iguales carácter a carácter (aunque referencien a
distintas direcciones de memoria dinámica)

El siguiente ejemplo muestra cómo hacer una redefinición de Equals() de manera


que aunque los objetos Persona sean de tipos por referencia, se considere que dos
Personas son iguales si tienen el mismo NIF:

public override bool Equals(object o)

if (o==null)

return this==null;

else

return (o is Persona) && (this.NIF == ((Persona) o).NIF);

Hay que tener en cuenta que es conveniente que toda redefinición del método
Equals() que hagamos cumpla con una serie de propiedades que muchos de los
métodos incluidos en las distintas clases de la BCL esperan que se cumplan. Estas
propiedades son:

52
Reflexividad: Todo objeto ha de ser igual a sí mismo. Es decir, x.Equals(x)
siempre ha de devolver true.

Simetría: Ha de dar igual el orden en que se haga la comparación. Es decir,


x.Equals(y) ha de devolver lo mismo que y.Equals(x) .

Transitividad: Si dos objetos son iguales y uno de ellos es igual a otro,


entonces el primero también ha de ser igual a ese otro objeto. Es decir, si
x.Equals(y) e y.Equals(z) entonces x.Equals(z) .

Consistencia: Siempre que el método se aplique sobre los mismos objetos ha


de devolver el mismo resultado.

Tratamiento de objetos nulos: Si uno de los objetos comparados es nulo (null),


sólo se ha de devolver true si el otro también lo es.

Hay que recalcar que el hecho de que redefinir Equals() no implica que el operador
de igualdad (==) quede también redefinido. Ello habría que hacerlo de
independientemente como se indica en el Tema 11: Redefinición de operadores.

 public virtual int GetHashCode(): Devuelve un código de dispersión (hash) que


representa de forma numérica al objeto sobre el que el método es aplicado.
GetHashCode() suele usarse para trabajar con tablas de dispersión, y se cumple que
si dos objetos son iguales sus códigos de dispersión serán iguales, mientras que si
son distintos la probabilidad de que sean iguales es ínfima.

En tanto que la búsqueda de objetos en tablas de dispersión no se realiza


únicamente usando la igualdad de objetos (método Equals()) sino usando también la
igualdad de códigos de dispersión, suele ser conveniente redefinir GetHashCode()
siempre que se redefina Equals() De hecho, si no se hace el compilador informa de
la situación con un mensaje de aviso.

 public virtual string ToString(): Devuelve una representación en forma de cadena


del objeto sobre el que se el método es aplicado, lo que es muy útil para depurar
aplicaciones ya que permite mostrar con facilidad el estado de los objetos.

Object (Referencia de C#)

El tipo object es un alias de Object en .NET Framework. En el sistema de tipos unificado


de C#, todos los tipos (tipos de valor y de referencia predefinidos y definidos por el
usuario) se heredan directa o indirectamente de Object. Las variables de tipo object
pueden recibir valores de cualquier tipo. Cuando una variable de un tipo de valor se
convierte en un objeto, se dice que se le ha aplicado la conversión boxing. Cuando una
variable de objeto de tipo se convierte en un tipo de valor, se dice que se le ha aplicado la
conversión unboxing. Para obtener más información, vea Boxing y Unboxing.

53
Ejemplo

En el siguiente ejemplo se muestra cómo las variables de tipo object pueden aceptar
valores de cualquier tipo de datos y cómo pueden utilizar métodos de Object procedentes
de .NET Framework.

// keyword_object.cs
using System;
class SampleClass
{
public int i = 10;
}

class MainClass
{
static void Main()
{
object a;
a = 1; // an example of boxing
Console.WriteLine(a);
Console.WriteLine(a.GetType());
Console.WriteLine(a.ToString());

a = new SampleClass();
SampleClass classRef;
classRef = (SampleClass)a;
Console.WriteLine(classRef.i);
}
}

Hilo de Ejecucion

Un hilo de ejecución, en sistemas operativos, es una característica que permite a una


aplicación realizar varias tareas a la vez(concurrentemente). Los distintos hilos de
ejecución comparten una serie de recursos tales como el espacio de memoria, los archivos
abiertos, situación de autenticación, etc. Esta técnica permite simplificar el diseño de una
aplicación que debe llevar a cabo distintas funciones simultáneamente.

Los hilos de ejecución que comparten los mismos recursos, sumados a estos recursos, son
en conjunto conocidos como un proceso. El hecho de que los hilos de ejecución de un mismo
proceso compartan los recursos hace que cualquiera de estos hilos pueda modificar éstos.
Cuando un hilo modifica un dato en la memoria, los otros hilos acceden a ese dato
modificado inmediatamente.

Lo que es propio de cada hilo es el contador de programa, la pila de ejecución y el estado de


la CPU (incluyendo el valor de los registros).

54
El proceso sigue en ejecución mientras al menos uno de sus hilos de ejecución siga activo.
Cuando el proceso finaliza, todos sus hilos de ejecución también han terminado. Asimismo
en el momento en el que todos los hilos de ejecución finalizan, el proceso no existe más y
todos sus recursos son liberados.

Algunos lenguajes de programación tienen características de diseño expresamente creadas


para permitir a los programadores lidiar con hilos de ejecución (como Java o Delphi). Otros
(la mayoría) desconocen la existencia de hilos de ejecución y éstos deben ser creados
mediante llamadas de biblioteca especiales que dependen del sistema operativo en el que
estos lenguajes están siendo utilizados (como es el caso del C y del C++).

Un ejemplo de la utilización de hilos es tener un hilo atento a la interfaz gráfica (iconos,


botones, ventanas), mientras otro hilo hace una larga operación internamente. De esta
manera el programa responde de manera más ágil a la interacción con el usuario. También
pueden ser utilizados por una aplicación servidora para dar servicio a múltiples clientes.

Funcionalidad de los hilos

Al igual que los procesos, los hilos poseen un estado de ejecución y pueden sincronizarse
entre ellos para evitar problemas de compartimiento de recursos. Generalmente, cada hilo
tiene una tarea especifica y determinada, como forma de aumentar la eficiencia del uso del
procesador.

 Informática
 Diseño Web
 Proyectos
 Ocio

Muchos lenguajes de programación permiten la creación de hilos o threads en un programa.


De forma resumida, los hilos son un mecanismo mediante el cual podemos devidir una
aplicación en diferentes partes que se pueden ejecutar de forma paralela, existiendo
mecanismos por los que pueden compartir información.

C# ofrece un mecanismo muy sencillo de implementar hilos, basado en la utilización de la


clase Thread. El constructor de esta clase recibe como parámetro el método o función que
hay que ejecutar en paralelo. Este parámetro se indica mediante la utilización de un
delegado, que es el mecanismo que, entre otras cosas, se utiliza en .NET para utilizar
punteros a funciones de forma segura. La firma del delegado no incluye ningún parámetro,
por lo que únicamente es posible crear hilos de forma directa sobre métodos y funciones
que no requieran parámetros de entrada ni de salida. En los siguientes ejemplos muestro un
caso sencillo de creación de un hilo y otro en el que explico una forma de poder crear un
hilo con entrada y salida de parámetros.

En el siguiente ejemplo se dispone de una clase con dos métodos que muestran mensajes
por pantalla. El objetivo es crear dos hilos, uno para cada uno de los métodos y ejecutarlos
de forma paralela, de forma que podamos ver como resultado cómo se van intercalando los
mensajes escritos por cada método.

55
using System;
using System.IO;
using System.Threading;

public class Mensajes{


public void Mostrar1()
{
for(int i=0;i<10;i++){
Console.WriteLine("Escribiendo desde ==> 1″);
Thread.Sleep(1000);
}
}

public void Mostrar2()


{
for(int i=0;i<10;i++){
Console.WriteLine("Escribiendo desde ==> 2″);
Thread.Sleep(1000);
}
}
}

public class Ejemplo{

public static void Main()


{
Mensajes msg = new Mensajes();

Thread th1 = new Thread(new ThreadStart(msg.Mostrar1));


Thread th2 = new Thread(new ThreadStart(msg.Mostrar2));

th1.Start();
th2.Start();

th1.Join();
th2.Join();
}

La creación de cada hilo se realiza mediante las líneas Thread th1 = new Thread(new
ThreadStart(msg.Mostrar1));. Esta línea indica que se crea una instancia de la clase
Thread, con nombre th1, a partir de un delegado de la clase ThreadStart, que apunta al
método Mostrar1 del objeto msg creado anteriormente.

Una vez creados los dos hilos hay que activarlos, para lo que se llama al método Start de
cada uno de ellos. Tras este punto cada hilo se ejecuta en paralelo entre si, y con el
programa principal, por lo que utilizamos el método Join de ambos hilos para esperar a que
terminen los hilos antes de finalizar el programa.

56
El delegado ThreadStart no acepta parámetros de entrada ni de salida, por lo que si
queremos crear un hilo sobre un método que los necesite, hay que utilizar algún mecanismo
auxiliar. Una posible forma de conseguir esto es crear una nueva clase con los parámetros
necesarios en la entrada y con un nuevo método sin parámetros que llame al método que
queremos hacer paralelo, enviándole estos parámetros. A partir de aquí tendríamos que
crear una instancia de dicha clase con los parámetros que queremos enviar al método
original, y hacer que el hilo se ejecutase sobre el nuevo método de la clase. En el caso de
que quisiéramos obtener el resultado de la ejecución, deberíamos crear una función que
acepte como parámetro de entrada el tipo del valor devuelto por el método original, y hacer
que la nueva clase creada disponga también de un delegado que indique la función a la que
llamar tras la ejecución.

Como esto puede parecer un poco lioso, vamos a ver otro ejemplo. En esta ocasión
disponemos de una clase de funciones matemáticas y queremos llamar de forma paralela a
una de ellas. Este método acepta un valor entero en la entrada y devuelve otro entero.

using System;
using System.Threading;
using System.IO;

public class EjemploMates{

public static int CalculoComplejo(int n)


{
// sumo uno y espero 5 segundos
n = n+1;
Thread.Sleep(5000);
return n;
}

public class HiloParaMates{


protected int n;
protected MatesCallback callback = null;
public HiloParaMates(int n, MatesCallback callback){
this.n = n;
this.callback = callback;
}
public void CalculoComplejo()
{
int result = EjemploMates.CalculoComplejo(n);
if(callback != null)
callback(result);
}
}

// creo un delegado con la firma necesaria para capturar


// el valor devuelto por el método CalculoComplejo
public delegate void MatesCallback(int n);

57
public class Ejemplo{

public static void Main()


{
HiloParaMates hpm = new HiloParaMates(1000, new MatesCallback(ResultCallback));

Thread th = new Thread(new ThreadStart(hpm.CalculoComplejo));

th.Start();
th.Join();

public static void ResultCallback(int n)


{
Console.WriteLine("Resultado de la operación: "+n);
}
}

En el anterior código la clase HiloParaMates es la que nos permite encapsular la llamada al


método EjemploMates.Calcular. Este método requiere un parámetro de tipo entero, por lo
que la clase requiere este parámetro en su constructor. Además se requiere en el
constructor otro parámetro más, un delegado MatesCallback, que acepta un entero en la
entrada. La idea es que tras realizar el cálculo se llame al método que se indique
proporcionándole el resultado.

Para hacer funcionar todo esto, en Main se crea una instancia de la clase HiloParaMates
indicándole que queremos utilizar el valor numérico 1000 y que se llame al método
(estático) ResultCallback cuando se obtenga el resultado. Para crear el hilo es suficiente
con indicar que se quiere hacer sobre el método CalculoComplejo de la instancia hpm.

Set (Referencia de C#)

Define un método de descriptor de acceso en una propiedad o indizador que estableció el


valor de la propiedad o el elemento del indizador. Vea Propiedades e Indizadores para
obtener más información.

Éste es un ejemplo de un descriptor de acceso set para una propiedad denominada


Seconds:

class TimePeriod

58
{
private double _seconds;
public double Seconds
{
get { return _seconds; }
set { _seconds = value; }
}
}
Get (Referencia de C#)

Define un método de descriptor de acceso en una propiedad o indizador que recupera el


valor de la propiedad o el elemento del indizador. Vea Propiedades (Guía de programación
de C#) e Indizadores (Guía de programación de C#) para obtener más información.

Éste es un ejemplo de un descriptor de acceso get para una propiedad denominada


Seconds:

class TimePeriod
{
private double _seconds;
public double Seconds
{
get { return _seconds; }
set { _seconds = value; }
}
}

TEMAS

VESTOR

LISTA

PILA

ITERADORES

CIN,COUT

WIDGETS

TEMPLATES

TEMPLATES

Plantillas de función

Función C + + plantillas de las funciones que puede manejar diferentes tipos de datos sin

59
código separado para cada uno de ellos. Para una operación similar en varios tipos de tipos
de datos, un programador no necesita escribir diferentes versiones por la sobrecarga de
una función. Es suficiente si escribe un programa en C + + basados en función de
plantilla. Esto se hará cargo de todos los tipos de datos.

Hay dos tipos de plantillas en C + +, es decir., La función de las plantillas y plantillas de


clase. Este artículo trata de la única función de las plantillas.

Hay muchas ocasiones, cuando tengamos que escribir las mismas funciones para los
diferentes tipos de datos. Un ejemplo favorito puede ser, además de dos variables. La
variable puede ser un número entero, flotante o doble. El requisito será el de devolver el
tipo de cambio correspondiente en función del tipo de entrada. Si comenzamos a escribir
una función para cada uno de los tipos de datos, a continuación, vamos a terminar con 4 a 5
funciones diferentes, que puede ser una yegua de la noche para su mantenimiento.

C + + plantillas de venir a nuestro rescate en tales situaciones. Cuando usamos C + +


plantillas de función, sólo una firma de la función debe ser creado. El compilador C + +
generará automáticamente las funciones necesarias para la manipulación de los tipos de
datos individuales. Así es como la vida de un programador que se haga mucho más fácil.

C + + plantilla - Detalles:

Supongamos que un pequeño ejemplo para la función Agregar. Si el requisito es utilizar esta
función Añadir para ambos entero y flotante, entonces dos funciones se van a crear para
cada uno de los tipos de datos (sobrecarga).

int Add (int a, int b) (return a + b;) / / Sin la función de C + + plantilla


float Add (float a, float b) (return a + b;) / / Sin la función de C + + plantilla

Si hay más tipos de datos que se manejan, más funciones que debería añadirse.

Pero si usamos una función C + + plantilla, todo el proceso se reduce a un siguiente single de
C + + plantilla de función. La voluntad de ser el fragmento de código de función Agregar.

plantilla T> <class


T Add (T a, T b) / / C + + plantilla de función muestra
(
volver a + b;
)

Esta función C + + definición de plantilla será suficiente. Ahora, cuando la versión entera de
la función, el compilador genera un complemento compatible con la función del tipo de datos
entero y si flotan se llama genera tipo float y así sucesivamente.

Aquí T es la class. Esto viene determinado dinámicamente por el compilador de acuerdo con
el parámetro pasado. La palabra clave class medios, el parámetro puede ser de cualquier
tipo. Incluso puede ser una clase.

60
C + + plantilla - Aplicación:

Función C + + plantillas se pueden utilizar siempre que sea la misma funcionalidad que ha de
llevarse a cabo con una serie de tipos de datos. Aunque es muy útil, mucho se debe tener
cuidado a la prueba de C + + plantilla de funciones durante el desarrollo. Un bien escrito en
C + + plantilla de recorrer un largo camino en ahorro de tiempo para los programadores.

Plantilla de clase

C + + plantillas de clase se utilizan donde tenemos varias copias de código para diferentes
tipos de datos con la misma lógica. Si un conjunto de funciones o clases tienen la misma
funcionalidad para los diferentes tipos de datos, que se convierte en buenos candidatos
para ser escrito como plantillas.

Una buena zona donde esta plantillas C + + Class son adecuados pueden ser clases de
contenedores. Ejemplos muy famoso por estas clases de contenedores se las clases STL
como vector, etc lista, una vez el código está escrito como una clase C + + plantilla, que
puede soportar todos los tipos de datos. Aunque es muy útil, es recomendable escribir una
clase como una plantilla después de conseguir una buenas manos-en la experiencia de la
lógica (al escribir el código con tipos de datos normal). Hay casos en que es necesario la
especialización para escribir código optimizado para datos específicos tipos. Artículo
Esta clase C + + especialización de la plantilla da una breve descripción.

Este artículo describe cómo declarar, definir y utilizar las plantillas C + + Class en la
práctica. Esta trata de construir una cola muy preliminar, utilizando la STL:: clase de
contenedor Vector. Este código está escrito y probado con Microsoft Visual C + + 5.00.

La declaración de C + + plantillas de clase:

Declaración de la clase C + + plantilla debe comenzar con la palabra clave de plantilla. Un


parámetro debe ser incluido dentro de corchetes angulares. El parámetro dentro de los
paréntesis angulares, pueden ser la clase de palabra clave oclass. Esto es seguido por el
cuerpo de la clase de declaración con los datos de miembros y funciones miembro. La
siguiente es la declaración de una muestra de la clase de la cola.

/ / Fragmento de código de ejemplo para C + + plantilla de clase


template <class T>
clase MyQueue
(
std:: vector <T> de datos;
público:
void add (const T & D);
void remove ();
void imprimir ();
);

La clase de palabras clave resaltadas en color azul, no está relacionada con la class. Esta es
una palabra clave obligatorias que deben incluirse para declarar una clase de plantilla.

61
Definición de las funciones de miembro - C + + plantillas de clase:

Si se definen las funciones fuera de la plantilla del cuerpo de clase, que siempre deben ser
definidos con la completa definición de plantilla. Otros convenios de la escritura de la
función en C + + plantillas de clase son los mismos que la escritura normal de C + +.

template <class T> void MyQueue <T>:: Add (const T & D)


(
data.push_back (d);
)

template <class T> void MyQueue <T>:: Eliminar ()


(
(data.begin data.erase () + 0, data.begin () + 1);
)

template <class T> void MyQueue <T>:: Imprimir ()


(
std:: vector <int>:: IT1 repetidor;
It1 = data.begin ();
for (IT1 = data.begin (); IT1! = data.end (); IT1 + +)
cout << "" <<* IT1 <<endl;

La función Añadir agrega los datos al final del vector. La función elimina quitar
el primer elemento. Estas funcionalidades hacen de este clase C + + plantilla se comportan
como una cola normal. La función de impresión imprime todos los datos utilizando el
repetidor.

Programa completo - C + + plantillas de clase:

/ / C + + _Class_Templates.cpp

# include <iostream.h>
# include <vector>

template <class T>


clase MyQueue
(
std:: vector <T> de datos;
público:
void add (const T &);
void remove ();
void imprimir ();
);

template <class T> void MyQueue <T>:: Add (const T & D)


(

62
data.push_back (d);
)

template <class T> void MyQueue <T>:: Eliminar ()


(
(data.begin data.erase () + 0, data.begin () + 1);
)

template <class T> void MyQueue <T>:: Imprimir ()


(
std:: vector <int>:: IT1 repetidor;
It1 = data.begin ();
for (IT1 = data.begin (); IT1! = data.end (); IT1 + +)
cout << "" <<* IT1 <<endl;

)
/ / Uso de C + + plantillas de clase
void main ()
(
MyQueue <int> q;
q.Add (1);
q.Add (2);

cout << "Antes de extraer los datos" <<endl;


q.Print ();

q.Remove ();
cout << "Después de la eliminación de datos" <<endl;
q.Print ();
)

Ventajas de C + + plantillas de clase:

 Uno de C + + plantilla de clase puede manejar diferentes tipos de parámetros.


 Compilador genera las clases sólo para los tipos utilizados. Si la plantilla se crea una
instancia de tipo int, el compilador genera sólo una versión int para el c + + clase de
plantilla.
 Plantillas de reducir el esfuerzo de codificación para los diferentes tipos de datos
a un único conjunto de código.
 Pruebas y los esfuerzos de depuración se reducen.

Vector

C + + Vectores
Vectores contienen elementos contiguos almacenados como una matriz.
Acceso a los miembros de un vector se puede hacer en tiempo constante, añadiendo
elementos a un vector se puede hacer en tiempo constante amortizado, mientras que la
localización de un valor específico o insertar elementos en el vector toma un tiempo lineal.
Constructores crear e inicializar los vectores con algunos datos

63
Operadores comparar, asignar, y los elementos de acceso de un vector de
asignar asignar elementos a un vector
en devolver una referencia a un elemento en un lugar específico
espalda devuelve una referencia al último elemento de un vector de
empezar devuelve un iterador al principio del vector
capacidad devuelve el número de elementos que el vector puede contener
claro Elimina todos los elementos del vector
vacío true si el vector no tiene elementos
devuelve un iterador justo después del último elemento de un vector
final
de
borrar elimina los elementos de un vector de
frente devuelve una referencia al primer elemento de un vector de
insertar elementos insertos en el vector
devuelve el número máximo de elementos que el vector puede
max_size
contener
pop_back Elimina el último elemento de un vector de
push_back agregar un elemento al final del vector
rbegin devuelve un reverse_iterator hasta el final del vector
rend devuelve un reverse_iterator al principio del vector
reserva establece la capacidad mínima del vector
cambiar el tamaño
cambiar el tamaño del vector
de
tamaño devuelve el número de elementos en el vector de
swap intercambiar el contenido de este vector con otra
Edit

Notas:
Tenga en cuenta que un vector booleano (vector <bool>) es una especialización del vector de
plantilla que está diseñado para utilizar menos memoria. Una variable booleana normal por lo
general utiliza 1-4 bytes de memoria, sino un vector booleano debe utilizar sólo un bit por
valor booleano.

C + + Vectores
Vectores contienen elementos contiguos almacenados como una matriz.
Acceso a los miembros de un vector se puede hacer en tiempo constante, añadiendo
elementos a un vector se puede hacer en tiempo constante amortizado, mientras que la
localización de un valor específico o insertar elementos en el vector toma un tiempo lineal.
Constructores crear e inicializar los vectores con algunos datos
Operadores comparar, asignar, y los elementos de acceso de un vector de
asignar asignar elementos a un vector
en devolver una referencia a un elemento en un lugar específico
espalda devuelve una referencia al último elemento de un vector de

64
empezar devuelve un iterador al principio del vector
capacidad devuelve el número de elementos que el vector puede contener
claro Elimina todos los elementos del vector
vacío true si el vector no tiene elementos
devuelve un iterador justo después del último elemento de un vector
final
de
borrar elimina los elementos de un vector de
frente devuelve una referencia al primer elemento de un vector de
insertar elementos insertos en el vector
devuelve el número máximo de elementos que el vector puede
max_size
contener
pop_back Elimina el último elemento de un vector de
push_back agregar un elemento al final del vector
rbegin devuelve un reverse_iterator hasta el final del vector
rend devuelve un reverse_iterator al principio del vector
reserva establece la capacidad mínima del vector
cambiar el tamaño
cambiar el tamaño del vector
de
tamaño devuelve el número de elementos en el vector de
swap intercambiar el contenido de este vector con otra
Edit

Notas:
Tenga en cuenta que un vector booleano (vector <bool>) es una especialización del vector de
plantilla que está diseñado para utilizar menos memoria. Una variable booleana normal por lo
general utiliza 1-4 bytes de memoria, sino un vector booleano debe utilizar sólo un bit por
valor booleano.

Los operadores de Vector


Sintaxis:
# include <vector>
TIPO & operator [] (índice size_type);
TIPO const & operador [] (índice size_type) const;
Vector & operator = (const Vector & c2);
bool operator == (const Vector & c1, const Vector & c2);
bool operator! = (const Vector & c1, const Vector & c2);
bool operator <(const vector & c1, const Vector & c2);
bool operator> (const Vector & c1, const Vector & c2);
bool operator <= (const Vector & c1, const Vector & c2);
bool operator> = (const Vector & c1, const Vector & c2);
Todos los contenedores de C + + se pueden comparar y asignados con los operadores de
comparación estándar: ==,! =, <=,> =, <,>, Y =. Los elementos individuales de un vector puede
ser examinada con el operador [].
Realizar una comparación o asignación de un vector a otro requiere un tiempo lineal.

65
El operador [] se ejecuta en tiempo constante.
Dos vectores son iguales si:
1. Su tamaño es el mismo, y
2. Cada miembro de i ubicación en un vector es igual a miembros de la i en la ubicación en
el otro vector.
Las comparaciones entre los vectores se hacen lexicográficamente.
Por ejemplo, el siguiente código utiliza el operador [] para acceder a todos los elementos de
un vector:
vector <int> v (5, 1);
for (int i = 0; i <v. size (); i + +) (
tribunal << "Elemento" <<i << "es" <<v [i] <<endl;
)

Constructores Vector
Sintaxis:
# include <vector>
using namespace std;
Vector ();
vector (const & c);
Vector explícita (num size_type, const TIPO & val = TIPO ());
template <input_iterator class>
(inicio de vectores input_iterator, input_iterator final);
~ Vector ();
El constructor por defecto vector no tiene argumentos, crea una nueva instancia de ese
vector.
El segundo constructor es un constructor de copia por defecto que se puede utilizar para
crear un nuevo vector que es una copia del vector dado c.
El tercer constructor crea un vector con objetos num. Si no se especifica Val, cada uno de
esos objetos se dará ese valor, de lo contrario, los objetos son de determinado tipo de
constructor predeterminado de valor. Por ejemplo, el código siguiente se crea un vector
que se compone de cinco ejemplares de los 42 entero:
vector <int> v1 (5, 42);
El último constructor crea un vector que se inicia para contener los elementos entre el
comienzo y final. Por ejemplo:
/ / Crear un vector de corte aleatorio enteros << "vector original:"; vector <int> v; for
(int i = 0; i <10; i + +) (int num = (int) rand ()% 10 ; tribunal <<num << ""; v. push_back
(NUM);) tribunal <<endl; / / Buscar el primer elemento de V que es aún vector <int>::
iterator iter1 = v. begin (), mientras que (iter1! v. = end () & & * iter1% 2! = 0) (+ + iter1;)
/ / buscar el último elemento de V que es aún vector <int>:: iterator iter2 v. = end (); do
(- iter2;) while (iter2! = v. begin () & & * iter2% 2! = 0); / / sólo procederá si nos
encontramos con dos números, si (iter1! v. = end () & & iter2! = v. comenzar ()) (tribunal
<< "incluso el primer número:" <<* iter1 << ", número par pasada:" <<* iter2 <<endl; tribunal
<< "nuevo vector:"; vector <int> v2 (iter1, iter2); for (int i = 0; i <v2. size (); i + +)
(tribunal <<v2 [i] << "";) tribunal <<endl;)
Cuando se ejecuta, este código muestra el resultado siguiente:
vector original: 1 9 7 9 2 7 2 1 9 8

66
número par primero: 2, número par última: 8
nuevo vector: 2 7 2 1 9
El último constructor prevé una forma práctica para inicializar un vector de STL con los
datos de una matriz de estilo antiguo.
Ejemplo:
fp_values float [] = (0,1, 0,2, 0,3, 0,4) / / Se crea una matriz en algún lugar
...
vector <float> fp_vector (fp_values, fp_values + 4) / / elementos de la matriz se
copian en fp_vector
Tenga en cuenta que los punteros son sólo una forma elemental posible de los iteradores.
Todos estos constructores se ejecutan en un tiempo lineal, excepto la primera, que se
ejecuta en tiempo constante.
El destructor por defecto es llamado para cada elemento cuando se destruye el vector.

asignar
Sintaxis:
# include <vector>
void assign (num size_type, const TIPO & val);
void assign (inicio input_iterator, final input_iterator);
La función assign () o bien le da el vector de los valores actuales de principio a fin, o le da
copias de val num.
Esta función va a destruir el contenido previo del vector.
Por ejemplo, el uso de código siguiente asignar () para poner 10 copias de el entero 42 en un
vector:
vector <int> v;
v. asignar (10, 42);
for (vector <int>:: size_type i = 0; i <v. size (); i + +) (
tribunal <<v [i] << "";
)
<tribunal <endl;
El código anterior muestra el resultado siguiente:
42 42 42 42 42 42 42 42 42 42
El siguiente ejemplo muestra cómo asignar () se puede usar para copiar un vector a otro:
vector <int> v1; for (int i = 0; i <10; i + +) (v1. push_back (i);) vector <int> v2; v2.
asignar (V1. begin (), v1. final ( )); para (vector <int>:: size_type i = 0; i <v2. size (); i + +)
(tribunal <<v2 [i] << "";) tribunal <<endl;
Cuando se ejecuta, el código de arriba muestra el resultado siguiente:
0123456789

en
Sintaxis:
# include <vector>
TIPO Y al (size_type loc);
TIPO const al (size_type loc) const;

67
En el () devuelve una referencia al elemento en el vector en loc índice. En el () es más
seguro que el operador [], porque no te dejan puntos de referencia fuera de los límites del
vector.
Por ejemplo, consideremos el siguiente código:
vector <int> v (5, 1);
for (int i = 0; i <10; i + +) (
tribunal << "Elemento" <<i << "es" <<v [i] <<endl;
)
Este sobrecostos código al final del vector, produciendo resultados potencialmente
peligrosos. El siguiente código sería mucho más seguro:
vector <int> v (5, 1);
for (int i = 0; i <10; i + +) (
tribunal << "Elemento" <<i << "es" <<v.: (i) <<endl;
)
En lugar de intentar leer los valores de la basura de la memoria, en la función () se dará
cuenta de que está a punto de saturación y el vector de una excepción (out_of_range).

espalda
Sintaxis:
# include <vector>
TIPO & back ();
TIPO const & back () const;
La parte de atrás () devuelve una referencia al último elemento en el vector. Por ejemplo:
vector <int> v; for (int i = 0; i <5; i + +) (v. push_back (i);) tribunal << "El primer
elemento es" <<c. delante () << "y El último elemento es "<<Volver v. () <<endl;
Este código genera el siguiente resultado:
El primer elemento es 0 y el último elemento es de 4
La parte de atrás () la función se ejecuta en tiempo constante.

empezar
Sintaxis:
# include <vector>
iterator begin ();
const_iterator begin () const;
La función de comenzar () devuelve un iterador al primer elemento del vector, y se ejecuta
en tiempo constante.
Por ejemplo, el código siguiente se utiliza comenzar () para inicializar un iterador que se
utiliza para recorrer los elementos de un vector:
vector <string> palabras;
string str;

while (cin>> str) palabras. push_back (str);

for (vector <string>:: = iter const_iterator palabras. begin ();


iter! palabras =. end (); iter + +) (
<tribunal <* iter <<endl;
)

68
Cuando se administra esta entrada:
Hey Mickey you're so fine
... El código anterior genera el siguiente resultado:
¡eh!
mickey
eres
tan
estupendo

capacidad
Sintaxis:
# include <vector>
capacidad size_type () const;
La capacidad () devuelve el número de elementos que el vector puede contener antes de que
se tendrán que asignar más espacio.
Por ejemplo, el código siguiente utiliza dos métodos diferentes para establecer la
capacidad de los dos vectores. Un método pasa un argumento al constructor que inicializa el
vector con 10 elementos de valor 0, el otro método llama a la función de reserva. Sin
embargo, el tamaño real del vector es cero.
vector <int> v1 (10); tribunal << "La capacidad de V1 es" <<v1. capacidad () <<endl;
tribunal << "El tamaño de V1 es" <<v1. size () <<endl ; vector <int> v2; v2. reserva (20);
tribunal << "La capacidad de v2 es" <<v2. capacidad () <<endl; tribunal << "El tamaño de v2
es" <<v2. tamaño () <<endl;
Cuando se ejecuta, el código anterior genera el siguiente resultado:
La capacidad de V1 es de 10
El tamaño de V1 es de 10
La capacidad de v2 es de 20
El tamaño de los V2 es 0
C + + contenedores están diseñados para crecer en tamaño dinámicamente. Esto libera al
programador de tener que preocuparse de almacenar un número arbitrario de elementos en
un contenedor. Sin embargo, a veces, el programador puede mejorar el rendimiento de su
programa, dando consejos para el compilador sobre el tamaño de los contenedores que el
programa va a utilizar. Estas sugerencias vienen en la forma de la función de reserva y el
constructor utilizado en el ejemplo anterior, que indica al compilador cuán grande es el
recipiente que se espera obtener.
La capacidad de función () se ejecuta en tiempo constante.

claro
Sintaxis:
# include <vector>
void clear ();
La función Clear () elimina todos los elementos en el vector. Para ello, será el destructor de
todos los elementos en el vector.
Después de una llamada al claro, el tamaño del vector nuevo será cero. La capacidad del
vector, sin embargo, no será cambiado, y el vector no dará a conocer su memoria asignada.

69
Si desea vaciar un vector de todos sus elementos, así como su capacidad, entonces puede
utilizar el truco de intercambio (este truco no funciona con todos los ambientes por
ejemplo, no con el compilador de Intel 10.0.69 y Linux 2.6.9-89 x 64):
std:: vector unVector;
[...]
unVector. swap (std:: vector ());
Esto creará un nuevo vector vacío temporal, lo que cambiará con el vector que desea vaciar.
clear () se ejecuta en tiempo lineal.

vacío
Sintaxis:
# include <vector>
bool empty () const;
El vacío () devuelve true si el vector no tiene elementos, false en caso contrario.
Por ejemplo, el código siguiente se utiliza vacío () como la condición de parada en un bucle
while para eliminar un vector y mostrar su contenido en orden inverso:
vector <int> v; for (int i = 0; i <5; i + +) (v. push_back (i);) while (! v. vacío ()) (tribunal
<<Volver v. () << endl; v. pop_back ();)

final
Sintaxis:
# include <vector>
iterator end ();
const_iterator end () const;
El final () devuelve un iterador justo después del final del vector. Tenga en cuenta que
antes de poder acceder al último elemento del vector mediante un repetidor que recibe de
una llamada a la final (), que tendrá que disminuir el iterador primero. Esto es porque el fin
de () no indica el final del vector, que apunta justo después del final del vector.
Por ejemplo, en el siguiente código, el resultado de la Corte Primera de "declaración
es undefined mientras que la segunda declaración de hecho se mostrará el último elemento
del vector:
vector <int> v1;
v1. push_back (0);
v1. push_back (1);
v1. push_back (2);
v1. push_back (3);

bad_val int i = * (V1. final ());


tribunal << "bad_val es" <<bad_val <<endl;

good_val int i = * (V1. final () - 1);


tribunal << "good_val es" <<good_val <<endl;
El siguiente ejemplo muestra cómo iniciar () y final () se puede utilizar para iterar a través
de todos los miembros de un vector.
vector <int> v1 (3, 5);

for (vector <int>:: const_iterator it = v1. begin ();

70
It! = v1. end (); + + que) (
<tribunal <* it <<endl;
)
El repetidor se inicia con una llamada para comenzar (). Después de que el cuerpo del bucle
se ha ejecutado, se incrementa el iterador y probado para ver si es igual al resultado de la
llamada final (). Desde finales () devuelve un iterador que apunta a un elemento justo
después del último elemento del vector, el ciclo sólo se detendrá una vez que todos los
elementos del vector se han exhibido.
end () se ejecuta en tiempo constante.

borrar
Sintaxis:
# include <vector>
iterator erase (loc iterador);
iterator erase (iterator inicio, iterator final);
La borrar () funciona bien elimina el elemento en loc ubicación o elimina los elementos entre
el comienzo y el final (incluyendo el arranque pero sin incluir el final). El valor de retorno es
el elemento después de que el último elemento borrado.
La primera versión de borrar (la versión que elimina un elemento único en la ubicación loc)
se ejecuta en tiempo constante para las listas y el tiempo lineal de vectores, dequeues y
cuerdas. La versión de múltiples elementos de borrar siempre toma un tiempo lineal.
Por ejemplo:
/ / Crear un vector, la carga con los diez primeros caracteres del alfabeto
<char vector> alfa;
for (int i = 0; i <10; i + +) (
alfas. push_back (I + 65);
)
vector <char>:: size_type size = alfas. size ();
vector <char>:: startIterator repetidor;
vector <char>:: tempIterator repetidor;
for (vector <char>:: size_type i = 0; i <size; i + +) (
startIterator = alfas. begin ();
alfas. erase (startIterator);
/ / Mostrar el vector
for (tempIterator = alfas. begin (); tempIterator! = alfa. end (); tempIterator + +) (
<tribunal <* tempIterator;
)
<tribunal <endl;
)
Ese código se mostrará el resultado siguiente:
BCDEFGHIJ
CDEFGHIJ
DEFGHIJ
Efghij
FGHIJ
GHIJ
HIJ

71
IJ
J
En el siguiente ejemplo, borrar () se llama con dos iteradores para eliminar una serie de
elementos de un vector:
/ / Crear un vector, cargar con los diez primeros caracteres del alfabeto
<char vector> alfa;
for (int i = 0; i <10; i + +) (
alfas. push_back (I + 65);
)
/ / Mostrar el vector completo
for (vector <char>:: size_type i = 0; i <alfas. size (); i + +) (
tribunal <<alfa [i];
)
<tribunal <endl;

/ / Uso de borrar para eliminar todos menos los dos primeros y tres últimos
elementos
/ / Del vector
alfas. erase (alphas. begin () + 2, alfas. end () - 3);
/ / Mostrar el vector modificado
for (vector <char>:: size_type i = 0; i <alfas. size (); i + +) (
tribunal <<alfa [i];
)
<tribunal <endl;
Cuando se ejecuta, se muestra el código de arriba:
ABCDEFGHIJ
ABHIJ
Con todos los tipos de contenedores que hay que tener cuidado al insertar o borrar
elementos, ya que puede conducir a los iteradores no válido.
Aquí hay un ejemplo que funciona para vector std::. Especialmente, vector:: erase () invalida
todos los iteradores punteros (y) a continuación del elemento que desea borrar. El ejemplo
borra algunos de los elementos en función de una condición (que borra las letras B y D).
<iostream> # include # include # include <vector> <iterator> using namespace std; int
main () (vector <char> alfa; for (int i = 0; i <10; i + +) (alfa. push_back ( i + 65);) vector
<char>:: Iterator iter = alfa. begin (), mientras que (ITER! = alfa. final ()) (if (* iter == '|
B' | * iter == 'D ') iter = alfa. erase (ITER); otro iter + +;) copia (alphas. begin (), alfas.
end (), <ostream_iterator char> (corte, "")); tribunal <<endl;)
Al ejecutarse, se muestra el código de arriba:
ACEFGHIJ

frente
Sintaxis:
# include <vector>
TIPO & front ();
TIPO const & front () const;

72
La parte delantera () devuelve una referencia al primer elemento del vector, y se ejecuta
en tiempo constante.
Por ejemplo, el código siguiente se utiliza un vector y la clase () _algorithm para mostrar la
primera palabra (en orden alfabético) introducidas por un usuario:
vector <string> palabras;
string str;

while (cin>> str) palabras. push_back (str);

sort (words. begin (), las palabras. final ());

tribunal << "En orden alfabético, la primera palabra es" "<<palabras. frontal () <<" "."
<<endl;
Cuando se suministran con esta entrada:
ahora es el momento de que todos los hombres de bien a acudir en ayuda de su país
... Se muestra el código de arriba:
En orden alfabético, la primera palabra es «ayuda».

insertar
Sintaxis:
# include <vector>
insertar iterador (loc iterador, const TIPO & val);
void insert (loc iterador, num size_type, const TIPO & val);
void insert (loc iterador, inicie input_iterator, final input_iterator);
El método de inserción o bien:
 inserta val antes de loc volviendo un iterador al elemento insertado,
 inserta ejemplares num de val antes de loc o
 introduce los elementos de start a end antes de loc
Tenga en cuenta que la inserción de elementos en un vector puede ser relativamente
intensivas en el tiempo, ya que la estructura de datos subyacente de un vector es una
matriz.Con el fin de insertar datos en una matriz, puede que tenga que desplazar a muchos
de los elementos de esa matriz, y esto puede tomar un tiempo lineal. Si usted está
planeando en hacer una gran cantidad de inserciones en su vector y la atención de la
velocidad, puede ser mejor usar un recipiente que tenga una lista enlazada como estructura
de base de datos (como una lista o un deque).
Por ejemplo, el código siguiente se utiliza la inserción () para empalmar cuatro copias del
carácter 'C' en un vector de caracteres:
/ / Crear un vector, la carga con los primeros 10 caracteres del alfabeto
<char vector> alphaVector;
for (int i = 0; i <10; i + +) (
alphaVector. push_back (i + 'A');
)

/ / Inserte cuatro C's en el vector


vector <char>:: theIterator iterador = alphaVector. begin ();
alphaVector. insert (theIterator, 4, 'C');

73
/ / Mostrar el vector
for (theIterator = alphaVector. begin (); theIterator! = alphaVector. end ();
theIterator + +) (
<tribunal <* theIterator;
)
Este código se muestra:
CCCCABCDEFGHIJ
He aquí otro ejemplo del método de inserción. En este código, insertar es usado para
adicionar el contenido de un vector en el final de otro:
vector <int> v1;
v1. push_back (0);
v1. push_back (1);
v1. push_back (2);
v1. push_back (3);

vector <int> V2;


v2. push_back (5);
v2. push_back (6);
v2. push_back (7);
v2. push_back (8);

tribunal << "Antes, v2 es:";


for (vector <int>:: size_type i = 0; i <v2. size (); i + +) (
tribunal <<v2 [i] << "";
)
<tribunal <endl;

v2. insert (v2. final (), v1. begin (), v1. final ());

tribunal << "Después, v2 es:";


for (vector <int>:: size_type i = 0; i <v2. size (); i + +) (
tribunal <<v2 [i] << "";
)
<tribunal <endl;
Cuando se ejecuta, se muestra este código:
Antes, v2 es: 5 6 7 8
Después, v2 es: 5 6 7 8 0 1 2 3

max_size
Sintaxis:
# include <vector>
max_size size_type () const;
El max_size () devuelve el número máximo de elementos que el vector puede contener. El
max_size () no debe confundirse con el tamaño o la capacidad de funciones, que devuelven
el número de elementos en la actualidad en el vector y el número de los elementos que el

74
vector se pueda celebrar antes de que más memoria tienen que ser destinados,
respectivamente, .

pop_back
Sintaxis:
# include <vector>
pop_back void ();
La pop_back () La función elimina el último elemento del vector.
pop_back () se ejecuta en tiempo constante.
Temas relacionados: atrás, borrar, push_back

push_back
Sintaxis:
# include <vector>
push_back void (const TIPO & val);
El push_back () añade la función val hasta el final del vector. Por ejemplo, el código se pone
a 10 enteros en un vector:
vector <int> the_vector;
for (int i = 0; i <10; i + +) (
the_vector. push_back (i);
)
Cuando se visualiza, el vector resultante se vería así:
0123456789
push_back () se ejecuta en tiempo constante, en el mejor de los casos.

rbegin
Sintaxis:
# include <vector>
reverse_iterator rbegin ();
const_reverse_iterator rbegin () const;
El rbegin () devuelve un reverse_iterator hasta el final del vector actual (la posición del
último elemento).
rbegin () se ejecuta en tiempo constante.

rend
Sintaxis:
# include <vector>
reverse_iterator rend ();
const_reverse_iterator rend () const;
El rend function () devuelve un reverse_iterator al inicio del vector actual (la posición
antes de que el primer elemento).
rend () se ejecuta en tiempo constante.

75
reserva
Sintaxis:
# include <vector>
reserva de vacío (tamaño size_type);
La reserva de función () establece la capacidad del vector a por lo menos tamaño.
reserva () se ejecuta en tiempo lineal.

cambiar el tamaño de
Sintaxis:
# include <vector>
void redimensionar (num size_type, TIPO val = TIPO ());
El tamaño de la función () cambia el tamaño del vector a num Si val se especifica a
continuación, los elementos recién creado será inicializado a tener un valor de val El
contenido de los vectores de hasta num se mantendrán sin cambios.
Ejemplo:
vector <int> v;
for (int i = 0; i <10; + + i) v. push_back (i);
v. cambiar el tamaño (20, 0); / / añade un adicional de 10 ceros a la final de v
Esta función se ejecuta en tiempo lineal.

tamaño
Sintaxis:
# include <vector>
size_type size () const;
El tamaño () devuelve el número de elementos en el vector actual.
Si usted desea saber si el vector está vacío, por lo general es preferible (para mayor
claridad, si no otra cosa) para llamar al () vacío función miembro, en vez de comprobar el
tamaño en contra: 0.
Tenga en cuenta que esto es diferente de la de la capacidad () la función miembro, que
devuelve cuántos elementos del vector podría sostener.

swap
Sintaxis:
# include <vector>
void swap (vector & de);
El intercambio () intercambios función de los elementos del vector actual con los de
de. Esta función opera en tiempo constante.
Por ejemplo, el código siguiente se utiliza el swap () para cambiar el contenido de dos
vectores:
vector <string> v1;
v1. push_back ( "Estoy en v1!");

vector <string> V2;


v2. push_back ( "Y yo estoy en v2!");

v1. swap (v2);

76
tribunal << "El primer elemento de v1 es" <<v1. frontal () <<endl;
tribunal << "El primer elemento de v2 es" <<v2. frontal () <<endl;
Aparece el código de arriba:
El primer elemento de V1 Y estoy en v2!
El primer elemento de v2 es que estoy en v1!

Listas

Las listas son secuencias de elementos almacenados en una lista enlazada. En comparación
con los vectores, que permiten la inserción rápida y eliminaciones, pero el acceso más lento
al azar.

Constructores crear listas de e inicializar con algunos datos


Operadores asignar y comparar las listas
asignar asignar elementos a una lista
espalda devuelve una referencia al último elemento de una lista de
empezar devuelve un iterador al principio de la lista de
claro Elimina todos los elementos de la lista de
vacío true si la lista no tiene elementos
devuelve un iterador justo después del último elemento de una lista
final
de
borrar elimina los elementos de una lista de
frente devuelve una referencia al primer elemento de una lista de
insertar inserta elementos en la lista
max_size devuelve el número máximo de elementos que la lista puede contener
fusionar fusionar dos listas
pop_back Elimina el último elemento de una lista de
pop_front quita el primer elemento de la lista de
push_back agregar un elemento al final de la lista
push_front agregar un elemento al frente de la lista de
rbegin devuelve un reverse_iterator al final de la lista de
eliminar elimina los elementos de una lista de
remove_if elimina los elementos condicional
rend devuelve un reverse_iterator al principio de la lista de
cambiar el tamaño
cambiar el tamaño de la lista de
de
inversa invertir la lista
tamaño devuelve el número de elementos en la lista
tipo Ordena una lista en orden ascendente

77
empalme combinar dos listas en la constante de tiempo
swap intercambiar el contenido de esta lista con otro
único consecutivos elimina elementos duplicados

Lista de constructores
Sintaxis:
# include <list>
lista ();
lista (lista const & c);
lista explícita (num size_type, const TIPO & val = TIPO ());
lista (inicio input_iterator, final input_iterator);
~ list ();
El constructor de la lista por defecto no tiene argumentos, crea una nueva instancia de la
lista.
El segundo constructor es un constructor de copia por defecto que se puede utilizar para
crear una nueva lista que es una copia de la lista que figura C.
El tercer constructor crea una lista con espacio para objetos num. Si no se especifica Val,
cada uno de esos objetos se dará ese valor. Por ejemplo, el siguiente código crea una lista
compuesta por cinco ejemplares de los 42 entero:
lista <int> L1 (5, 42);
El último constructor crea una lista que se inicia para contener los elementos entre el
comienzo y final. Por ejemplo:
/ / Crear un vector de corte aleatorio enteros << "lista original:"; lista <int> l; for (int i
= 0; i <20; i + +) (int num = (int) rand ()% 10 ; tribunal <<num << ""; L. push_back (NUM);)
tribunal <<endl; / / eliminar 5 y 7 de la lista <int>:: iterator iter1 = L. begin (), mientras
que (iter1! = l . final ()) (list <int>:: thisone iterador = iter1; + + iter1, si (* thisone == 5 | |
* thisone == 7) (tribunal << "borrar" <<* thisone <<endl ; L. borrar (thisone);)) / / Buscar
el primer elemento de l que es aún lista <int>:: iterator iter2 = L. begin (), mientras que
(iter2! l. = end () & & *% iter2 2! = 0) (+ + iter2;) / / buscar el último elemento de l que
es aún lista <int>:: iterator iter3 l. = end (); do (- iter3;) while (iter3! = l . begin () & & *
iter3% 2! = 0); tribunal << "incluso el primer número:" <<* iter2 << ", número par pasada:"
<<* iter3 <<endl; tribunal << "nueva lista "; lista <int> L2 (iter2, iter3); lista <int>:: iterator
iter4 = L2. begin (), mientras que (iter4! = L2. final ()) (tribunal <<* iter4 <<" " ; iter4 +
+;) tribunal <<endl;
Cuando se ejecuta, este código muestra el resultado siguiente:
lista original: 7 9 3 8 0 2 4 8 3 9 0 5 2 2 7 3 7 9 0 2
borrar 7
Borrar 5
borrar 7
borrar 7
número par primero: 8, último número par: 2
nueva lista: 8 0 2 4 8 3 9 0 2 2 3 9 0
Todos estos constructores se ejecutan en un tiempo lineal, excepto la primera, que se
ejecuta en tiempo constante.
El destructor por defecto llama al destructor para cada objeto en la lista con la
complejidad lineal.

78
Lista de operadores de
Sintaxis:
# include <list>
Lista & operator = (const Lista & c2);
bool operator == (const Lista & c1, const Lista & c2);
bool operator! = (const Lista & c1, const Lista & c2);
bool operator <(const Lista & c1, const Lista & c2);
bool operator> (const Lista & c1, const Lista & c2);
bool operator <= (const Lista & c1, const Lista & c2);
bool operator> = (const Lista & c1, const Lista & c2);
Todos los contenedores de C + + se pueden comparar y asignados con los operadores de
comparación estándar: ==,! =, <=,> =, <,>, Y =. Realizar una comparación o asignación de una
lista a otra toma tiempo lineal.
Dos listas son iguales si:
1. Su tamaño es el mismo, y
2. Cada miembro de i ubicación en una lista es igual a miembros de la i en la ubicación en
la otra lista.
Las comparaciones entre las listas se hacen lexicográficamente.

asignar
Sintaxis:
# include <list>
void assign (num size_type, const TIPO & val);
void assign (inicio input_iterator, final input_iterator);
La función assign () o bien da la lista actual de los valores de principio a fin, o le da copias
de val num.
Esta función va a destruir el contenido anterior de la lista.
Por ejemplo, el uso de código siguiente asignar () para poner 10 copias de el entero 42 en
una lista:
lista <int> l;
L. asignar (10, 42);
de (lista <int>:: size_type i = 0; i <l. size (); i + +) (
tribunal <<l [i] << "";
)
<tribunal <endl;
El código anterior muestra el resultado siguiente:
42 42 42 42 42 42 42 42 42 42
El siguiente ejemplo muestra cómo asignar () se puede usar para copiar una lista a otra:
lista <int> L1;
for (int i = 0; i <10; i + +) (
l1. push_back (i);
)

lista <int> L2;


L2. assign (l1. begin (), L1. final ());

de (lista <int>:: size_type i = 0; i <l2. size (); i + +) (

79
tribunal <<L2 [i] << "";
)
<tribunal <endl;
Cuando se ejecuta, el código de arriba muestra el resultado siguiente:
0123456789

empezar
Sintaxis:
# include <list>
iterator begin ();
const_iterator begin () const;
La función de comenzar () devuelve un iterador al primer elemento de la lista. Begin () debe
ejecutar en tiempo constante.
Por ejemplo, el código siguiente se utiliza comenzar () para inicializar un iterador que se
utiliza para recorrer una lista:
/ / Crear una lista de caracteres
<char lista> my_list;
for (int i = 0; i <10; i + +) (
my_list. push_front (i + 'a');
)

/ / Mostrar la lista de
lista <char>:: iterator it;
for (it = my_list. begin (); it! = my_list. end (); + + que) (
tribunal <<* it;
)

espalda
Sintaxis:
# include <list>
TIPO & back ();
TIPO const & back () const;
La parte de atrás () devuelve una referencia al último elemento de la lista.
Por ejemplo:
lista <int> l;
for (int i = 0; i <5; i + +) (
L. push_back (i);
)
tribunal << "El primer elemento es" <<L. delante ()
<< "Y el último elemento es" <<Volver L. () <<endl;
Este código genera el siguiente resultado:
El primer elemento es 0 y el último elemento es de 4
La parte de atrás () la función se ejecuta en tiempo constante.

claro
Sintaxis:
# include <list>

80
void clear ();
La función Clear () elimina todos los elementos en la lista. clear () se ejecuta en tiempo
lineal.

vacío
Sintaxis:
# include <list>
bool empty () const;
El vacío () devuelve true si la lista no tiene elementos, false en caso contrario. Por ejemplo,
el código siguiente se utiliza vacío () como la condición de parada en un bucle, mientras
quepara borrar una lista y mostrar su contenido en orden inverso:
lista <int> v; for (int i = 0; i <5; i + +) (v. push_back (i);) while (! v. vacío ()) (tribunal
<<Volver v. () << endl; v. pop_back ();)

final
Sintaxis:
# include <list>
iterator end ();
const_iterator end () const;
El final () devuelve un iterador justo después del final de la lista.
Tenga en cuenta que antes de poder acceder al último elemento de la lista con un iterador
que usted obtiene de un llamado a terminar con (), que tendrá que disminuir el repetidor
primero.
Por ejemplo, el código siguiente se utiliza begin () y final () para recorrer todos los
miembros de una lista:
lista <int> v1 (5, 789);
lista <int>:: iterator it;
for (it = v1. begin (); it! = v1. end (); + + que) (
<tribunal <* it <<endl;
)
El repetidor se inicia con una llamada para comenzar (). Después de que el cuerpo del bucle
se ha ejecutado, se incrementa el iterador y probado para ver si es igual al resultado de la
llamada final (). Desde finales () devuelve un iterador que apunta a un elemento justo
después del último elemento del vector, el ciclo sólo se detendrá una vez que todos los
elementos del vector se han exhibido.
end () se ejecuta en tiempo constante.

borrar
Sintaxis:
# include <list>
iterator erase (loc iterador);
iterator erase (iterator inicio, iterator final);
El método de borrado o bien elimina el elemento en loc ubicación o elimina los elementos
entre el start y end (incluyendo start pero no como end El valor de retorno es el elemento
después de que el último elemento borrado.

81
La primera versión de borrar (la versión que elimina un elemento único en la ubicación loc se
ejecuta en tiempo constante. La versión de múltiples elementos de borrar siempre tomaun
tiempo lineal.
Las listas tienen la importante propiedad de que la inserción y el empalme no invalidan los
iteradores a elementos de la lista, y que incluso la eliminación sólo invalida los iteradores
que apuntan a los elementos que se eliminan.
El orden de los iteradores se puede cambiar (es decir, <T> lista:: iterador podría tener un
predecesor o sucesor diferentes después de una operación de la lista que antes), pero los
iteradores mismos no serán invalidadas o puesto a punto a diferentes elementos a menos
que la anulación o la mutación es explícita.
Por ejemplo:
/ / Crear una lista, cargar con los diez primeros caracteres del alfabeto
<char lista> alphaList;
for (int i = 0; i <10; i + +) (
alphaList. push_back (I + 65);
)
int size = alphaList. size ();
lista <char>:: startIterator repetidor;
lista <char>:: tempIterator repetidor;
for (int i = 0; i <size; i + +) (
startIterator = alphaList. begin ();
alphaList. erase (startIterator);
/ / Mostrar la lista de
copia (alphaList. begin (),. alphaList final (), <ostream_iterator char> (tribunal));
<tribunal <endl;
)
Ese código se mostrará el resultado siguiente:
BCDEFGHIJ
CDEFGHIJ
DEFGHIJ
Efghij
FGHIJ
GHIJ
HIJ
IJ
J
En el siguiente ejemplo, borrar () se llama con dos iteradores para eliminar una serie de
elementos de una lista:
/ / Crear una lista, cargar con los diez primeros caracteres del alfabeto
<char lista> alphaList;
for (int i = 0; i <10; i + +) (
alphaList. push_back (I + 65);
)
/ / Mostrar la lista completa
copia (alphaList. begin (),. alphaList final (), <ostream_iterator char> (tribunal));
<tribunal <endl;

/ / Uso de borrar para eliminar todos menos los dos primeros y tres últimos
elementos

82
/ / De la lista de
alphaList. borrar (anticipo (alphaList. begin (), 2), (anticipo alphaList. final (), - 3));
/ / Mostrar la lista modificada
copia (alphaList. begin (),. alphaList final (), <ostream_iterator char> (tribunal));
<tribunal <endl;
Cuando se ejecuta, se muestra el código de arriba:
ABCDEFGHIJ
ABHIJ

frente
Sintaxis:
# include <list>
TIPO & front ();
TIPO const & front () const;
La parte delantera () devuelve una referencia al primer elemento de la lista, y se ejecuta
en tiempo constante.

insertar
Sintaxis:
# include <list>
insertar iterador (loc iterador, const TIPO & val);
void insert (loc iterador, num size_type, const TIPO & val);
template <Tipo> void insert (loc iterador, inicie input_iterator, final input_iterator);
El inserto () funciona bien:
 val inserta antes de loc, devuelve un iterador al elemento insertado,
 num inserta copias de val antes de loc, o
 introduce los elementos de principio a fin antes de loc.
Por ejemplo:
/ / Crear una lista, lo carga con los primeros 10 caracteres del alfabeto
<char lista> alphaList;
for (int i = 0; i <10; i + +) (
alphaList. push_back (I + 65);
)

/ / Inserte cuatro C's en la lista


lista <char>:: theIterator iterador = alphaList. begin ();
alphaList. insert (theIterator, 4, 'C');

/ / Mostrar la lista de
for (theIterator = alphaList. begin (); theIterator! = alphaList. end ();
TheIterator + +) (
<tribunal <* theIterator;
)
Este código se muestra:
CCCCABCDEFGHIJ

83
max_size
Sintaxis:
# include <list>
max_size size_type () const;
El max_size () devuelve el número máximo de elementos que la lista puede contener. El
max_size () no debe confundirse con la función de tamaño, que devuelven el número de
elementos que están actualmente en la lista.

fusionar
Sintaxis:
# include <list>
void mezcla (la lista y otros);
void mezcla (la lista y otros, compfunction BinPred);
La función de combinación de correspondencia () combina todos los elementos
de other en *this lo vacía other La lista resultante se ordena en relación con el operador
<. Si no se especifica compfunction, entonces se utiliza como la función de comparación de
las listas en lugar de <.
merge () se ejecuta en tiempo lineal.

pop_back
Sintaxis:
# include <list>
pop_back void ();
La pop_back () La función elimina el último elemento de la lista.
pop_back () se ejecuta en tiempo constante.

pop_front
Sintaxis:
# include <list>
pop_front void ();
La pop_front function () elimina el primer elemento de la lista.
El pop_front () la función se ejecuta en tiempo constante.

rbegin
Sintaxis:
# include <list>
reverse_iterator rbegin ();
const_reverse_iterator rbegin () const;
La rbegin () devuelve un reverse_iterator hasta el final de la lista actual (la posición del
último elemento).
rbegin () se ejecuta en tiempo constante.

84
eliminar
Sintaxis:
# include <list>
void remove (const TIPO & val);
La función remove () elimina todos los elementos que son iguales a val de la lista. Por
ejemplo, el siguiente código crea una lista de los primeros 10 caracteres del alfabeto, a
continuación, utiliza remove () para eliminar la letra «E» de la lista :
/ / Crear una lista que tiene las primeras 10 letras del alfabeto lista <> char charlist;
for (int i = 0; i <10; i + +) charlist. Push_front (I + 65) / / Eliminar todas las instancias
de 'charlist E'. remove ( 'E');
Eliminar ejecuta en tiempo lineal.

remove_if
Sintaxis:
# include <list>
void remove_if (PR UnPred);
La remove_if () La función elimina todos los elementos de la lista para que el pr predicado
unario es cierto.
remove_if () se ejecuta en tiempo lineal.

rend
Sintaxis:
# include <list>
reverse_iterator rend ();
const_reverse_iterator rend () const;
El rend function () devuelve un reverse_iterator a un elemento justo antes del primer
elemento de la lista actual.
rend () se ejecuta en tiempo constante.

cambiar el tamaño de
Sintaxis:
# include <list>
void cambiar el tamaño (tamaño size_type, TIPO val = TIPO ());
Los cambios de método de cambiar el tamaño el tamaño de la lista para size Si val se
especifica a continuación, los elementos recién creado será inicializado a tener un valor
de val
Esta función se ejecuta en tiempo lineal.

inversa
Sintaxis:
# include <list>
void reverse ();
El reverso de la función () invierte la lista, y toma tiempo lineal.

85
tamaño
Sintaxis:
# include <list>
size_type size () const;
El tamaño () devuelve el número de elementos en la lista actual.

tipo
Sintaxis:
# include <list>
void ordenar ();
void (tipo P BinPred);
La función sort () se utiliza para ordenar las listas en orden ascendente. Pedido se realiza
mediante el operador <, a menos que p se ha especificado, en cuyo caso se utiliza para
determinar si un elemento es menor que otro.
Clasificación N toma el tiempo de registro N.
Temas relacionados: invertir
Código de ejemplo simple: # include # include <iostream> <list> using namespace std; / /
Asume Tipo T; cout <<t; es válido. Plantilla <tipo de clase> inline ostream & operator
<<(ostream & theOstream, la lista de const <TIPO> & theList) (list class <Tipo>:: =
ListIterator const_iterator theList. begin (); for (int i = 0; ListIterator! = theList. end ();
ListIterator + +, i + +) theOstream << "[" <<i << "]: \" "<<(* ListIterator) <<" \ "" <<endl;
theOstream return;) (struct funtor bool operator () (const char * const char a, * b)
(return strcmp (a, b) <0;)) int main () (list <char *> l / * Cargue algunos datos de ejemplo
de la prueba ... * / Char s [3], s [2] = '\ 0'; for (s [0] = 'c', s [0]> = 'a', s [0] -) para la (s [
1] = 'c', s [1]> = 'a', s [1] -) L. push_back (strdup (s)); / * Mostrar los datos de prueba de
que nosotros ... * / Tribunal <<<l <endl; / * Ordenar la lista. * / Funtor f; L. tipo (f); / *
Mostrar nosotros lo que tenemos ahora ... * / Tribunal <<<l <endl;)

empalme
Sintaxis:
# include <list>
empalme void (POS iterador, la lista y LST);
empalme void (POS iterador, la lista y LST, del iterador);
empalme void (POS iterador, la lista y LST, inicie iterator iterator end);
La función de empalme se mueve uno o más elementos de
derecho lst antes pos ubicación. La sobrecarga se mueve primero todos los elementos
a lst el segundo sólo se mueve el tema en del y el tercio se mueve todos los artículos
incluidos en el rango de start y exclusiva de end
de empalme se mueve simplemente elementos de una lista a otra, y realmente no hace
ninguna copia o eliminación. Debido a esto, se ejecuta en el empalme de tiempo
constante,excepto por la sobrecarga de terceros que no necesita más que el tiempo lineal
en el caso de que lst no es la misma que this Sin embargo, si es de tamaño complejidad
lineal de tiempo después de empalme es constante para los tres.

86
swap
Sintaxis:
# include <list>
void intercambio (la lista y desde);
El intercambio () intercambios función de los elementos de la lista actual con los de
de. Esta función opera en tiempo constante.
Por ejemplo, el código siguiente se utiliza el swap () para intercambiar los valores de dos
listas:
lista <string> L1;
l1. push_back ( "Estoy en L1!");

lista <string> L2;


L2. push_back ( "Y yo estoy en L2");

l1. swap (L2);

tribunal << "El primer elemento de L1 es" <<l1. frontal () <<endl;


tribunal << "El primer elemento de L2 es" <<L2. frontal () <<endl;
Aparece el código de arriba:
El primer elemento de L1 es y estoy en L2!
El primer elemento de L2 es que estoy en L1!

único
Sintaxis:
# include <list>
void () exclusiva;
void única (pr BinPred);
La función única () elimina todos los elementos consecutivos duplicados de la lista.
Tenga en cuenta que sólo se eliminan duplicados consecutivos, lo que puede requerir que
sort () de la primera lista.
La igualdad es probada usando el operador ==, a menos que pr se especifica como un
reemplazo. El orden de los elementos en una lista no debe cambiar después de una llamada a
la única ().
() exclusiva se ejecuta en tiempo lineal.

Pila

El C + + es un adaptador de pila de contenedores que proporciona al programador de la


funcionalidad de una pila - específicamente, un FILO (primero en entrar, último out) la
estructura de datos.
Constructores construcción de una nueva pila
vacío true si la pila no tiene elementos
pop elimina el elemento superior de una pila de

87
empujar añade un elemento a la parte superior de la pila
tamaño devuelve el número de elementos de la pila de
superior devuelve una referencia al elemento superior de la pila de

Constructores de la pila
Sintaxis:
# include <stack>
pila ();
pila explícita (const Container & con);
Las pilas tienen un constructor vacío y un constructor que se puede utilizar para
especificar un tipo de contenedor.

vacío
Sintaxis:
# include <stack>
bool empty () const;
El vacío () devuelve true si la pila no tiene elementos, false en caso contrario.
Por ejemplo, el código siguiente se utiliza vacío () como la condición de parada en un bucle
while para eliminar un montón y mostrar su contenido en orden inverso:
Pila <int> s;
for (int i = 0; i <5; i + +) (
s. push (i);
)
while (! s. vacío ()) (
<tribunal <s. superior () <<endl;
s. pop ();
)

pop
Sintaxis:
# include <stack>
pop void ();
El pop function () elimina el elemento superior de la pila y lo elimina.

empujar
Sintaxis:
# include <stack>
void push (const TIPO & val);
El impulso de la función () agrega val a la parte superior de la pila actual.
Por ejemplo, el código siguiente se utiliza el push () para sumar diez números enteros a la
parte superior de una pila:
Pila <int> s;
for (int i = 0; i <10; i + +) s. push (i);

88
tamaño
Sintaxis:
# include <stack>
size_type size () const;
El tamaño () devuelve el número de elementos en la pila actual.

superior
Sintaxis:
# include <stack>
TIPO Y arriba ();
TIPO const & top () const;
La parte superior function () devuelve una referencia al elemento superior de la pila.
Por ejemplo, el código siguiente elimina todos los elementos de una pila y los usos arriba ()
para mostrarlas:
while (! s. vacío ()) (
tribunal <<s. superior () << "";
s. pop ();
)

I TERADORES

Nota: el diseño de la STL permite que cualquier función genérica que acepte un iterador
funcione igualmente bien aceptando un puntero ordinario.

Nota: los iteradores no solo sirven para señalar elementos dentro de los contenedores de la
STL, también se utilizan para señalar elementos dentro de otras estructuras: flujos
("Streams") y bufers de flujo ("Buffers streams") [4]. Además se han definido de modo
que cuando los elementos de matriz están definidos mediante subíndices son también
iteradores. La consecuencia es que ciertos algoritmos pueden aplicarse también sobre las
matrices (recuerde las matrices son un tipo de estructura de datos, y que el operador
elemento de matriz [] se define como la indirección de un puntero 4.9.16).

La cosa funciona más o menos según el siguiente esquema (observe su paralelismo con los
punteros):

vector<int> cInt; // contenedor tipo vector para enteros

... // introducimos algunos enteros en cInt

std::vector<int>::iterator iT1; // iterador-a-vector-de-int

89
...

iT1 = cInt.begin(); // iT1 señala al primer miembro de cInt

...

std::cout << *iT1; // muestra el primer miembro de cInt

...

++iT1; // desplaza iT1 al segundo miembro

std::cout << *iT1; // muestra el segundo miembro de cInt

§2 L A CLASE ITERATOR

La sentencia anterior, donde se declara un iterador iT1 de la clase vector<int> es


fundamental para entender la naturaleza de los iteradores

std::vector<int>::iterator iT1;

En efecto: esta sentencia intancia un objeto iT1 de la clase iterator que pertenece al
espacio de una instanciación concreta, vector<int>, de una clase genérica vector<T>. Esto
significa que la clase iterator para vectores-de-int está definida en el ámbito de la clase
genérica vector<T>. Es decir, la definición de la clase vector es algo como:

template <class T, ...> vector {

public:

class iterator;

};

A su vez esta clase iterator debe dispone de su propia definición en algún punto de la
cabecera <vector>:

class vector<T>::iterator {

/* definición dependiente de la implementación */

};

Esta es la razón por la que coloquialmente se dice que un contenedor puede generar un
iterador adecuado. Como puede verse, existen tantas clases iterator como contenedores
distintos; todas ellas son distintas e independientes. Aunque comparten el mismo nombre y

90
están definidas en subespacio distintos de std (recuerde que las clases constituyen
ámbitos en sí mismas).

typedef implementation defined iterator;


typedef implementation defined const_iterator;
typedef implementation defined size_type;
typedef implementation defined difference_type;

typedef std::reverse_iterator<iterator> reverse_iterator;


typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

§2 C ARACTERÍSTICAS

Existen diversas características principales que distinguen unos iteradores de otros.


Podemos resumirlas como sigue:

 Capacidad de modificar los datos subyacentes. En este sentido pueden ser de solo
lectura; solo escritura, o lectura/escritura.

 Tipo de desplazamiento que puede realizarse con ellos para recorrer el contenedor.
Puede ser de avance secuencial; avance y retroceso secuencial, o acceso aleatorio.

 Otras características adicionales. Por ejemplo, la posibilidad de ser utilizados por


algoritmos que permiten insertar o borrar elementos del contenedor asociado.

La tabla siguiente muestra los modos en que son generadas las diversas categorías de
iteradores por los contenedores STL.

Categoría Generado por

Iterador de entrada istream_iterator

Iterador de salida ostream_iterator


insert_iterator
front_insert_iterator
back_insert_iterator
Iterador bidireccional list
set y multiset
map y multimap
Iterador de acceso aleatorio Punteros ordinarios
vector
deque

91
Lista STL

Una lista es un contenedor secuencial optimizado para las inserciones y eliminaciones de los
elementos de datos en ubicaciones arbitrarias dentro de la colección.

Sin embargo, una lista no proporciona acceso basado en el índice a los elementos de la
colección. Lista STL se implementa como una lista doblemente vinculada. Una lista
doblemente vinculada es una estructura de datos en el que cada elemento tiene un vínculo
en el siguiente elemento y un vínculo al elemento anterior. Se debe usar una lista cuando el
orden de los elementos dentro de la lista y eficientes arbitrarias inserciones y
eliminaciones requeridos por la aplicación.

Los siguientes son algunos de los principales métodos de clase de lista de STL. Estos no
incluyen los métodos relacionados con iteradores, que se describen en la siguiente sección.

Método Descripción

List() Crea una lista vacía.

lista (size_type n) Crea una lista de n elementos inicializada a su valor predeterminado.

lista (size_type n, T const y valor) Crea una lista de n elementos inicializada al valor.

T & back(void) Devuelve una referencia para el último elemento en la lista.

T & front(void) Devuelve una referencia al primer elemento en la lista.

anular push_back(const T& value) Inserta un valor al final de la lista.

anular push_front(const T& value) Inserta un valor al principio a la lista.

anular pop_back(void) Elimina el último elemento de la lista.

anular pop_front(void) Elimina el primer elemento de la lista.

void quitar (const T & valor) Elimina todos los elementos que coinciden con el valor. Comparación
se realiza mediante el operador ==.

anular reverse(void) Invierte el orden de los elementos en la lista.

size_type size(void) Devuelve el número de entradas de la lista.

anular sort(void) Ordena las entradas contenidas en la lista utilizando el < operador.

Stack

LA PILA DE <>CLASE CONTAINER

En este artículo trataremos sobre unSencillo clase de contenedor Pila.

92
Esto representa una pila de su tipo de datos. Pila de <>se modela utilizando un deque (O un
doble terminó cola). Todos los operadores <, > < =, > =,! =, == están sobrecargados de la clase
de contenedor de pila. Esto significa que puede comprobar dos pilas al igual que dos enteros
o dos tipos de datos integrada. Por ejemplo, hay dos pilas s1 y s2 y desea comparar, puede
escribir

if(S1==S2) y así sucesivamente para otros operadores

Stack<>-Una sobre otra

MÉTODOS DE CLASE DE PILA

 Empty()
 get_allocator()
 pop()
 Push()
 Size()
 Top()
 operador ==
 operador < =
 operador > =
 operador! =
 operador <
 operador >

Aquí vamos a hablar acerca de cada método, le mostrará lo que hace y, a continuación, al
final nos dará ejemplo donde se puede utilizar estos métodos together….

EMPTY () Y SIZE ()

El método empty() se utiliza para comprobar si una pila está vacía o no. Este método
devuelve un valor bool. El valor es true que si la pila está vacía, de lo contrario devolverá
false valor. Aquí es un código que lo hará entender mejor cómo se utiliza empty()...

Size() devuelve el número de elementos presentes en la pila.

# include <iostream>
# include <stack>
# include <conio.h>

utilizando el espacio de nombres std;

int main()
{
la pila de códigos de <char>;
codes.Push('a');
codes.Push('b');

93
cout << "tamaño de la pila is:"<<codes.size<<endl;
¿//Checking si la pila está vacía o no?
if(codes.Empty()==true)
cout << "La pila está vacía"; //prints el tamaño de la pila
getch();
devolver 0;
}

Se puede eliminar la "true" en la anterior cada bloque. Pero es recomendable escribir true,
ya que hace su intención más claro a otros programadores

El resultado de este programa será 2 ya que hay dos elementos en la pila.

PUSH() Y TOP()

Push() se utiliza para insertar un elemento en la parte superior de pila. Sólo necesitamos
pasar el argumento para empujar en la parte superior de la pila. El tipo de devolución de
este método es nulo. Por lo que no se devuelve sólo los valores se insertan en la parte
superior de pila.

Top(), como sugiere el nombre utilizado para el elemento MRA(Most Recently Added) de la
pila que se encuentra en la parte superior de pop. El código siguiente pone algunos entero
en una pila de entero y, a continuación, muestra el elemento ARM.

# include <iostream>
# include <stack>
# include <conio.h>

utilizando el espacio de nombres std;

int main()
{
la pila de códigos de <int>;
for(int i=0;i<10;i++)
//Pushing elementos en la parte superior de la pila.
codes.Push(i);
cout<<codes.Top() << endl; //Displaying el elemento de la parte superior
getch();
devolver 0;
}

El resultado de este código será 9.

Las wxWidgets

son unas bibliotecas multiplataforma y libres, para el desarrollo de interfaces gráficas


programadas en lenguaje C++. Están publicadas bajo una licencia LGPL, similar a la GPL con
la excepción de que el código binario producido por el usuario a partir de ellas, puede ser
propietario, permitiendo desarrollar aplicaciones empresariales sin coste.

94
Las wxWidgets proporcionan una interfaz gráfica basada en las bibliotecas ya existentes
en el sistema (nativas), con lo que se integran de forma óptima y resultan muy portables
entre distintos sistemas operativos. Están disponibles para Windows, MacOS, GTK+, Motif,
OpenVMS y OS/2.

También pueden ser utilizadas desde otros lenguajes de programación, aparte del C++:
Java, Javascript, Perl, Python, Smalltalk, Ruby .

APLICACIÓN

La biblioteca wxWidgets se implementa en C + +, con los enlaces disponibles para muchos


lenguajes de programación de uso común, entre ellos, Python (wxPython), Erlang (wxErlang),
Haskell (wxHaskell), Lua (wxLua), Perl (wxPerl), Ruby (wxRuby) , Smalltalk (wxSqueak),
Common Lisp (wxCL), Básico (wxBasic), C (WXC), D (WXD), Euphoria (wxEuphoria). NET
Framework (wx.NET), Java (wx4j) e incluso JavaScript (wxJavaScript / GLUEScript).
Para obtener una lista completa, con enlaces a los sitios de los proyectos respectivos, ver
las referencias externas al final de este artículo. También hay PLT Scheme, que utiliza una
rama de incompatibilidad de wxWindows (versión 1), creada en 1995. El kit de
herramientas está totalmente integrada con la carrera de idiomas a tiempo (la recolección
de basura, la administración de recursos) a diferencia de en otros idiomas, que se limitan a
establecer una biblioteca de carácter vinculante.

El uso
Todos los usos de los wxWidgets se derivan de wxApp, y necesitan simplemente eliminar a
un solo miembro, wxApp:: OnInit, y crea una ventana. Mientras la ventana esté abierta, el
uso está también.

DEFINICIÓN

Un Frame es una ventana cuyo tamaño y posición pueden (usualmente) ser cambiados por el
usuario.Esta usualmente tiene unas fronteras gruesas y un titulo de barra, y puede
contener opcionalmente una barra de menú, una barra de herramientas y una barra de
estado. Un Frame puede contener cualquier ventana que no sea un diálogo. Un Frame va a
tener una barra de estado, que es creada por la función CreateStatusBar y una barra de
herramientas que es creada por la función CreateToolBar que manejara la ventana.

MÉTODOS
Estos son algunos métodos del Frame:

wxFrame::Centre Centra la ventana en la pantalla.


wxFrame::CreateStatusBar Crea una barra de estado en el fondo del Frame. Recibe un
entero que dividirá la barra de estado.
wxFrame::CreateToolBar Crea una barra de herramientas en la parte superior o la
izquierda del Frame.
wxFrame::GetMenuBar Regresa un indicador a la barra de menú, asociado actualmente con
el Frame.
wxFrame::Iconize Minimiza o maximiza.Recibe un parámetro verdadero o falso.
wxFrame::IsFullScreen Retorna verdadero si el Frame el modo pantalla completa.

95
wxFrame::Maximize Maximiza o restaura el Frame.
wxFrame::GetTitle Retorna la cadena que tiene el título del Frame.
wxFrame::GetToolBar Regresa un indicador a la barra de herramientas asociado
actualmente al Frame.
wxFrame::SetIcon Fija el icono para este Frame.
wxFrame::SetStatusText Fija el texto de la barra de estado y rediseña la barra de estado.
wxFrame::SetTitle Fija el título del Frame.

CONSTRUCTORA

wxFrame( parent, id, const title, const wxPoin pos =


wxDefaultPosition, const size = 0, long style =
wxDEFAULT_FRAME_STYLE, name = "frame")

PARÁMETROS DE LA CONSTRUCTORA
Parent:
El padre de la ventana. Este puede ser NULL. si es non-NULL, el frame será exhibido
siempre encima de la ventana del padre en Windows.
Id: El identificador de la ventana. Puede tomar el valor de -1 para que se le asigne un valor
predeterinado.
Title: El subtitulo que se exhibirá en la barra del título del Frame.
Pos: La posición de la ventana. Un valor de (-1,-1) indica una posición del defecto, elegida
por el sistema o los wxWidgets del windowing, dependiendo de la plataforma.
Size: El tamaño de la ventana. Un valor de (-1,-1) indica un tamaño predeterminado, elegido
por el sistema, dependiendo de la ventana.
Style: El estilo de la ventana.
Name: El nombre de la ventana. Este parámetro se utiliza para asociar un nombre a la
ventana.

wxTextCtrl

Un control de texto permite que el texto que se mostrará y editado. Puede ser de una
sola línea o de varias líneas.

Derivado de

streambuf
wxControl
wxWindow
wxEvtHandler
wxObject

Incluir archivos

<wx/textctrl.h>

96
WXTEXT CTRL :: WXTEXT C TRL

wxTextCtrl ()

Default constructor.

wxTextCtrl (wxWindow padre *, wxWindowID id, wxString const & value = "", wxPoint
const & POS = wxDefaultPosition, wxSize const & size = wxDefaultSize, long style = 0,
wxValidator const & validador = wxDefaultValidator, wxString const & name =
wxTextCtrlNameStr)

Constructor, crear y mostrar un control de texto.

WXTEXT CTRL :: ~ WX TEXT CTRL

~ wxTextCtrl ()

Destructor, destruyendo el control de texto.

WXTEXT CTRL :: APPENDTEXT

void AppendText (wxString const y texto)

Añade el texto al final del control de texto.

WXTEXT CTRL :: CANCOPY

virtual bool CanCopy ()

Devuelve true si la selección se puede copiar en el portapapeles.

WXTEXT CTRL :: CANCUT

virtual bool CanCut ()

Devuelve true si la selección puede ser cortado en el portapapeles.

WXTEXT CTRL :: CANPASTE

CanPaste bool virtual ()

97
Devuelve true si el contenido del portapapeles puede pegarse en el control de texto. En
algunas plataformas (Motif, GTK) Esta es una aproximación y devuelve true si el control se
puede editar, false en caso contrario.

WXTEXT CTRL :: CANREDO

virtual bool CanRedo ()

Devuelve true si hay un servicio disponible y rehacer la última operación se puede rehacer.

WXTEXT CTRL :: CANUNDO

virtual bool CanUndo ()

Devuelve true si existe la posibilidad de deshacer disponible y la última operación se puede


deshacer.

WXTEXT CTRL :: CLEAR

virtual void Clear ()

Borra el texto en el control.

Tenga en cuenta que esta función generará un evento de


wxEVT_COMMAND_TEXT_UPDATED.

WXTEXT CTRL :: COPIAR

virtual void Copy ()

Copia el texto seleccionado al portapapeles con Motif y MS Windows.

WXTEXT CTRL :: CREATE

bool Crear (* wxWindow padre, wxWindowID id, wxString const & value = "", wxPoint
const & POS = wxDefaultPosition, wxSize const & size = wxDefaultSize, long style = 0,
wxValidator const & validador = wxDefaultValidator, wxString const & name =
wxTextCtrlNameStr )

98
Crea el control de texto para la construcción de dos pasos. Las clases derivadas deben
llamar o sustituir esta función

WXTEXT CTRL :: CORTE

virtual void Cut ()

Copia el texto seleccionado en el portapapeles y elimina la selección.

WXTEXT CTRL :: DISCARDEDITS

DiscardEdits void ()

Restablece el indicador interno "modificado" como si las ediciones actuales se habían


salvado.

WXTEXT CTRL :: EMULATE KEYPRESS

EmulateKeyPress bool (wxKeyEvent const & event)

Esto inserta funciones en el control del personaje que se han insertado si el


acontecimiento clave dada se han producido en el control de texto. El objeto de evento
debe ser el mismo que el que pasó a EVT_KEY_DOWN controlador anteriormente por
wxWidgets.

Tenga en cuenta que esta función actualmente no funciona correctamente para todas las
claves en cualquier plataforma, pero los RSU.

Valor devuelto

true si el evento dio lugar a un cambio en el control, false en caso contrario.

WXTEXT CTRL :: GET DEFAULT STYLE

wxTextAttr const GetDefaultStyle () const

Devuelve el estilo utilizado actualmente para el nuevo texto.

Compatibilidad

Aplicada en wxMSW / wxGTK comenzando con wxWidgets 2.3.2.

99
WXTEXT CTRL :: OPERATOR <<

wxTextCtrl & operator <<(wxString const & s)

wxTextCtrl & operator <<(int i)

wxTextCtrl & operator <<(long i)

wxTextCtrl & operator <<(float f)

wxTextCtrl & operator <<(double d)

wxTextCtrl & operator <<(char c)

WXCONTROL

Esta es la clase base para un control o widget''.

Un control es generalmente una pequeña ventana que los procesos de entrada de usuario y
/ o mostrar uno o más tema de los datos.

Derivado de

wxWindow
wxEvtHandler
wxObject

Incluir archivos

<wx/control.h>

Ver también

wxValidator

Miembros

100
wxControl:: Command
wxControl:: getLabel
wxControl:: SetLabel

WXCONTROL :: COMMAND

void Comando (wxCommandEvent & event)

Simula el efecto de que el usuario se da la orden al tema. Ver wxCommandEvent.

WXCONTROL :: GET LABEL

wxString & getLabel ()

Devuelve el texto del control.

WXCONTROL :: SET LABEL

void setLabel (wxString const & etiqueta)

WXB UTTON

Un botón es un control que contiene una cadena de texto, y es uno de los elementos más
comunes de una GUI. Puede ser colocado en un cuadro de diálogo o panel, o de hecho, casi
cualquier otra ventana.

Derivado de

wxControl
wxWindow
wxEvtHandler
wxObject

Incluir archivos

<wx/button.h>

Estilos de ventanas

wxBU_LEFT Izquierda-justifica la etiqueta. Windows y

101
GTK + solamente.

wxBU_TOP Alinea la etiqueta a la parte superior del


botón. Windows y GTK + solamente.

wxBU_RIGHT Haga justifica la etiqueta de mapa de bits.


Windows y GTK + solamente.

wxBU_BOTTOM Alinea la etiqueta en la parte inferior del


botón. Windows y GTK + solamente.

wxBU_EXACTFIT Crea el botón tan pequeñas como sea posible


en lugar de hacerlo del tamaño estándar (que
es el comportamiento por defecto).

wxNO_BORDER Crea un botón plano. Windows y GTK +


solamente.

WXB UTTON:: WXBUTTON

wxButton ()

Default constructor.

(wxButton wxWindow padre *, wxWindowID id, wxString const & label = wxEmptyString,
wxPoint const & POS = wxDefaultPosition, wxSize const & size = wxDefaultSize, long style
= 0, wxValidator const & validador = wxDefaultValidator, wxString const & name = "botón"
)

Constructor, crear y mostrar un botón.

La mejor manera de crear botones estándar es utilizar el valor predeterminado de la


etiqueta. Si no se suministra y la etiqueta de identificación es uno de los identificadores
estándar de esta lista, con etiqueta estándar se usará. Además de eso, el botón estará
decorado con iconos en GTK + 2.

WXB UTTON:: ~ WX BUTTON

~ wxButton ()

Destructor, destruyendo el botón.

102
WXB UTTON:: CREATE

bool Crear (* wxWindow padre, wxWindowID id, wxString const & label = wxEmptyString,
wxPoint const & POS = wxDefaultPosition, wxSize const & size = wxDefaultSize, long style
= 0, wxValidator const y validador, wxString const & name = "button")

La función de creación de botones para la creación de dos pasos. Para más detalles, véase
wxButton:: wxButton.

WXB UTTON:: GET L ABEL

getLabel wxString () const

Devuelve la etiqueta de cadena para el botón.

Valor devuelto

La etiqueta del botón.

Ver también

wxButton:: SetLabel

WXB UTTON:: GET DEFAULTSIZE

GetDefaultSize wxSize ()

Devuelve el tamaño por defecto de los botones. Se recomienda hacer todos los botones de
diálogo del mismo tamaño y esta función permite recuperar la (plataforma y tamaño actual
depende de fuentes) que debe ser el más adecuado para ello.

WXB UTTON:: POR DEFECTO

Por defecto void ()

Esto establece el botón para ser el tema por defecto para el grupo especial o cuadro de
diálogo.

WXB UTTON:: SETL ABEL

void setLabel (wxString const & etiqueta)

103
Establece la etiqueta de cadena para el botón

WXT

wxChar wxT (char ch)

wxChar const char * wxT (const char * s)

wxT () es una macro que puede ser utilizado con carácter y literales de cadena (en otras
palabras, "x" o "foo") para convertir automáticamente a Unicode en Unicode configuración
de generación. Por favor vea el resumen Unicode para más información.

Esta macro es simplemente devuelve el valor que se le pasa sin cambios en ASCII
construir. De hecho, su definición es:

# ifdef UNICODE
# define wxT (x) L # # x
# else / /! Unicode
# define wxT (x) x
# endif

WXS TRING

wxString es una clase que representa una cadena de caracteres. Por favor vea el resumen
wxString para obtener más información al respecto.

Como se explica allí, wxString implementa la mayoría de los métodos de la std:: clase
String. Estas funciones estándar no están documentadas en este manual, consulte la
documentación de STL). El comportamiento de todas estas funciones es idéntico al
comportamiento descrito allí.

Usted puede notar que wxString a veces tiene muchas funciones que hacer lo mismo, como,
por ejemplo, Longitud (), Len () y longitud (), que todos los devolverá la longitud de cadena.
En todos los casos de esa duplicación de la std:: cadena método compatible (longitud () en
este caso, siempre la versión en minúsculas) se debe usar ya que asegurará un suave
transición a std:: string wxWidgets cuando comienza a utilizar en lugar de wxString.

Derivado de

104
Ninguno

Incluir archivos

<wx/string.h>

Objetos predefinidos

Objetos:

wxEmptyString

WXS TRING :: WXS TRING

wxString ()

Default constructor. Inicializa la cadena "" (cadena vacía).

wxString (const wxString & x)

Constructor de copia.

wxString (wxChar ch, size_t n = 1)

Construye una cadena de n copias de carácter ch

WXS TRING :: IS WORD

IsWord bool () const

Devuelve true si la cadena es una palabra.

Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.

WXS TRING :: ÚLTIMA

Última wxChar () const

Devuelve el último carácter.

wxChar y Last ()

105
Devuelve una referencia al último carácter (modificable).

Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.

WXS TRING :: IZQUIERDA

wxString izquierda (size_t count) const

Devuelve los caracteres primer recuento de la cadena.

WXS TRING :: LEN

size_t len () const

Devuelve la longitud de la cadena.

WXS TRING :: LONGITUD

size_t length () const

Devuelve la longitud de la cadena (al igual que Len).

Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.

WXS TRING :: BAJA

Baja wxString () const

Devoluciones esta cadena convertida a la minúscula.

WXS TRING :: MINÚSCULAS

Minúsculas void ()

Igual que MakeLower.

Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.

106
WXS TRING :: MAKELOWER

wxString & MakeLower ()

Convierte todos los caracteres a minúsculas y devuelve el resultado.

WXS TRING :: MAKEUPPER

wxString & MakeUpper ()

Convierte todos los caracteres a mayúsculas y devuelve el resultado

107

S-ar putea să vă placă și