Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ESCARCEGA
ISMA-III
GTK
GTK#
WINDOWS FORMS
QT
LIBRERIAS DINAMICAS
PUNTERO
CLASES
RECURSIVIDAD
COM(PUERTO SERIE)
FIREWIRE
CAMPOS DE BITS
HILOS
SYSTEM.OBJECT
SET(C#)
GET(C#)
LICENCIAS
COPYRIGHT
GPL
GNU
LGPL
CREATIVE COMMONS
MIT
VECTOR
LISTA
PILA
ITERADORES
WIDGETS
TEMPLATES
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
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.
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?
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 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
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
Pues no obliga a especificar el formato (como hace printf ). Para un puntero 'p' la salida en
pantalla sera algo similar a lo siguiente:
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)
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 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.
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 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
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;
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.
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'
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 '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).
Recursion
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.
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.
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:
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).
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:
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.
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
...
if (busca(key, ptr) != NULL){
...
}
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.
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:
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)
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)
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.
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);
Permutaciones(palabra);
cin.get();
return 0;
}
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
0 1 2 3 4
A B C D /0
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
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
0 1 2 3 4
A B C D /0
0 1 2 3 4
A C B D /0
0 1 2 3 4
A C B D /0
0 1 2 3 4
A C D B /0
Y así sucesivamente.
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.
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:
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:
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:
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:
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
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.
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
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.
Full 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 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
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:
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.
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.
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.
(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.
USB 3.0 consume menos electricidad, es más rápida y sus puertos son compatibles con los
puertos USB 2.0.
- Alcanzan una velocidad de 400 megabits por segundo, manteniéndola de forma bastante
estable.
- 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).
Firewire
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.
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).
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.
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.
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 FIREWIRE
REDES IP SOBRE FIREWIRE
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.
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.
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).
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:
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:
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:
Licencia copyright
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.
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
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.
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.
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.
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.
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.
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 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
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.
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
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
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
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.
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:
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.
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 para el
uso de la comunidad). Pero también un inconveniente si no deseamos que nuestro trabajo se
utilice en un producto cerrado.
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.
CAMPOS DE BITS
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 utilizar
miembros de tamaño arbitrario en estructuras, uniones y clases; independiente de la posibilidad
que proporcionan los tipos básicos 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.
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
D ECLARACIÓN
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
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.
DECLARAR CLASES
Las clases se definen mediante la palabra clave class, como se muestra en el ejemplo siguiente:
C#
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#
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;
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#
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.
C#
Casi todas las estructuras comparten la misma sintaxis que las clases, aunque están más
limitadas que éstas:
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.
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
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.
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;
th.Start();
th.Join();
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.
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.
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:
if (o==null)
return this==null;
else
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:
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) .
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.
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.
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
{
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.
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.
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.
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
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.
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.
using System;
using System.Threading;
using System.IO;
th.Start();
th.Join();
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.
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
{
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
TEMPLATES
Plantillas de función
Función C + + plantillas de las funciones que puede manejar diferentes tipos de datos sin 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 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 + + 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).
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.
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.
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 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.
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 + +.
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
/ / C + + _Class_Templates.cpp
# include <iostream.h>
# include <vector>
)
/ / Uso de C + + plantillas de clase
void main ()
(
MyQueue <int> q;
q.Add (1);
q.Add (2);
q.Remove ();
cout << "Después de la eliminación de datos" <<endl;
q.Print ();
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
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
final devuelve un iterador justo después del último elemento de un vector 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
max_size devuelve el número máximo de elementos que el vector puede 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 de cambiar el tamaño del vector
tamaño devuelve el número de elementos en el vector de
swap intercambiar el contenido de este vector con otra
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:
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;
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;
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
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.
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.
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);
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
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);
)
/ / 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;
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;
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');
)
/ / 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);
v2. insert (v2. final (), v1. begin (), v1. final ());
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 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:
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.
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.
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!");
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.
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);
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);
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) (
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>
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);
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.
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
/ / Uso de borrar para eliminar todos menos los dos primeros y tres últimos elementos
/ / 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);
)
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:
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.
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);
swap
Sintaxis:
# include <list>
void intercambio (la lista y desde);
ú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
Constructores de la pila
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);
tamaño
Sintaxis:
# include <stack>
size_type size () const;
El tamaño () devuelve el número de elementos en la pila actual.
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):
...
...
§2 L A CLASE ITERATOR
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:
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 {
};
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 están definidas en
subespacio distintos de std (recuerde que las clases constituyen ámbitos en sí mismas).
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.
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.
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
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()...
int main()
{
la pila de códigos de <char>;
codes.Push('a');
codes.Push('b');
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
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>
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;
}
Las wxWidgets
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
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.
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.
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>
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)
~ wxTextCtrl ()
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.
Devuelve true si hay un servicio disponible y rehacer la última operación se puede rehacer.
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 )
Crea el control de texto para la construcción de dos pasos. Las clases derivadas deben llamar o
sustituir esta función
DiscardEdits void ()
Restablece el indicador interno "modificado" como si las ediciones actuales se habían salvado.
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.
Compatibilidad
WXC ONTROL
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
Incluir archivos
<wx/control.h>
Ver también
wxValidator
Miembros
wxControl:: Command
wxControl:: getLabel
wxControl:: SetLabel
WXBUTTON
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
Incluir archivos
<wx/button.h>
Estilos de ventanas
WXBUTTON :: 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" )
~ wxButton ()
WXBUTTON :: 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.
Valor devuelto
Ver también
wxButton:: SetLabel
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.
WXT
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
WXSTRING
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
Derivado de
Ninguno
Incluir archivos
<wx/string.h>
Objetos predefinidos
Objetos:
wxEmptyString
WXSTRING:: WXSTRING
wxString ()
Constructor de copia.
WXSTRING:: IS WORD
Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.
WXSTRING:: ÚLTIMA
wxChar y Last ()
Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.
WXSTRING:: IZQUIERDA
WXSTRING:: L EN
WXSTRING:: L ONGITUD
Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.
WXSTRING:: BAJA
WXSTRING:: MINÚSCULAS
Minúsculas void ()
Esta es una wxWidgets 1.xx función de compatibilidad, usted no debe utilizar en el nuevo
código.