Etiquetas

C (31) Cpp (28) Linux (14) asm (8) Telegram (5) bot (5) libreria (5) Algoritmo (3) Errores comunes (3) python (3) Opengl (2) kali (2) Android (1) Snippet (1) nano (1) recursividad (1)

lunes, 25 de marzo de 2024

Programacion Orientada a Objetos I

/*Esta entrada no fue hecha por mí. Fue hecha por el autor del blog analisisyprogramacionoop*/ Principios de la programación orientada a objetos Introducción La programación orientada a objetos (POO) o por sus siglas en inglés (OOP) es un paradigma que enfoca la programación como si trabajásemos con objetos del mundo real, esto es muy atractivo desde el punto de vista de la clasificación y análisis de las partes que integrarán un programa pues es posible pensar en objetos del mundo real y sus interacciones entre ellos. Así pues el concepto más importante de dicho paradigma es la Clase que establece la definición genérica de un Objeto o Instancia dentro de un programa, en el mundo real una clase es un Coche, un Animal, una Factura o cualquier cosa tangible o intangible del mundo real. El objeto o instancia es la ocurrencia concreta de la clase. Así, mi coche es un objeto de la clase coche, un coche tiene 4 ruedas, un volante, un motor, faros, etc, etc. Mi coche particular es de un modelo concreto, es rojo o amarillo, tiene x kilómetros pero hay muchos coches concretos, cada uno con sus atributos, así una clase es un Molde que establece las Propiedades (color, marca, modelo) de cada coche concreto, objeto. Además de propiedades un coche puede interaccionar con el mundo, por ejemplo puede acelerar, frenar, girar a la derecha a izquierda, este tipo de interacción se llama Método o Función y se define en cada clase junto con las propiedades.
De este modo tenemos la clase coche con las propiedades color, marca, modelo, etc y los métodos acelerar, frenar, girar. Todo esto se encapsula y sirve de molde para implementar diferentes objetos u ocurrencias concretas, coche azul marca X que acelera de 0 a 100 en 7 segundos, etc, etc. La OOP nos permite pensar en el mundo real y diseñar inmediatamente el código que maneje cualquier información. Podemos pensar en una clase Factura que tiene unas propiedades: Importe, datos de cliente, datos de cabecera, etc y unos métodos: Imprimir, borrar, grabar, etc. Toda esta operativa se programa en un mismo módulo (Encapsulación) y ya no es necesario tocar pues permite crear un código de cliente que opere con los objetos de cada clase sin necesidad de tocar el código de las clases. Las clases soportan la Herencia, Un Animal puede ser un perro o un gato, del mimo modo que la clase animal puede derivarse en otras clases perro o gato que generen propiedades concretas de perro o gato pero posean los mismos métodos (como comer) aunque definidos de forma diferente.(Polimorfismo) Los métodos pueden cambiar los atributos o propiedades de un objeto, así por ejemplo si tengo Un objeto cuadrado con un valor del lado y uso el método crecer puedo cambiar su valor del lado. La encapsulación permite la reutilización del código, la clase Imprimir, si está bien diseñada se puede utilizar para imprimir cualquier cosa de tal modo que al programar ya nunca tendremos que programar de nuevo dicha operativa y bastará con escribir NombreObjeto.Imprimir. Resumiendo: Un programa orientado a objetos tiene una serie de Moldes (Clases) que contienen la información genérica de cada objeto, (Métodos y Propiedades) dentro de un mismo contenedor (Encapsulación), las clases permiten la herencia y por tanto definir los mismos métodos de diferente forma (Polimorfismo). Cada Ocurrencia concreta de una clase se llama objeto o Instancia y representa un objeto concreto del mundo real como un coche azul o una factura del cliente X por importe Y.

Introduccion al lenguaje ASM

/*Este texto no es de mi autoria. Viene del blog analisisyprogramacionoop*/ El lenguaje ensamblador es un lenguaje de programación de bajo nivel para microprocesadores y microcontroladores. Implementa una representación simbólica del códigos de máquina binario y otras constantes necesarias para programar una arquitectura dada de la CPU y consiste en la representación má El ensamblador realiza una traducción más o menos isomorfa desde las sentencias mnemónicas a las instrucciones y datos de máquina. Actualmente se utiliza cuando se requiere la manipulación directa del hardware, alto rendimiento, o un uso de recursos controlado y reducido, controladores de dispositivo y en el desarrollo de sistemas operativos. Características El lenguaje ensamblador no suele ser portable, en otras palabras, el código para un microprocesador no sirve para ejecutarse en otro (modelo o marca diferentes) por lo que es necesario modificarlo para usarlo en otro microprocesador de diferente modelo o arquitectura diferentes. En estos casos el código debe reescribirse. El lenguaje ensamblador permite controlar exactamente las tareas realizadas por el microprocesador y es capaz de crear código imposible de imitar en un lenguaje de alto nivel, ya que el lenguaje ensamblador dispone de instrucciones que no están disponibles en los lenguajes de alto nivel.s directa del código máquina específico para cada arquitectura legible por un programador. Está basada en mnemónicos que simbolizan las instrucciones, registros del procesador, y posiciones de memoria. El ensamblador realiza una traducción más o menos isomorfa desde las sentencias mnemónicas a las instrucciones y datos de máquina. Actualmente se utiliza cuando se requiere la manipulación directa del hardware, alto rendimiento, o un uso de recursos controlado y reducido, controladores de dispositivo y en el desarrollo de sistemas operativos. Características El lenguaje ensamblador no suele ser portable, en otras palabras, el código para un microprocesador no sirve para ejecutarse en otro (modelo o marca diferentes) por lo que es necesario modificarlo para usarlo en otro microprocesador de diferente modelo o arquitectura diferentes. En estos casos el código debe reescribirse. El lenguaje ensamblador permite controlar exactamente las tareas realizadas por el microprocesador y es capaz de crear código imposible de imitar en un lenguaje de alto nivel, ya que el lenguaje ensamblador dispone de instrucciones que no están disponibles en los lenguajes de alto nivel. Programas ensambladores Son programas que traducen desde el lenguaje nemónico ensamblador al código máquina real de ceros y unos que realmente se almacena en la memoria del microprocesador. No hay que confundirlos con el lenguaje en ensamblador que es un lenguaje sencillo creado para no programar directamente en código máquina. Son programas que permiten escribir directamente los nemónicos y nos evita teclear los códigos correspondientes a cada instrucción. Han estado disponibles desde los años 1950. Los ensambladores modernos, optimizan la planificación de instrucciones para explotar la CPU de forma eficiente. Hay dos tipos de lenguaje ensamblador dependiendo de los pasos que pasan a través del código fuente. • Los de un paso pasan a través del código fuente una vez y asumen que todos los símbolos se definirán antes de cualquier instrucción que los refiera. • Los de dos pasos crean una tabla con todos los símbolos y sus valores en el primer paso, después en un segundo paso utilizan la tabla para generar el código definitivo. En el primer paso se debe por lo menos poder determinar la longitud de cada instrucción para que se posible calcular las direcciones de los símbolos. Un lenguaje ensamblador de un solo paso es más rápido mientras que un ensamblador de dos pasos permite al programa ser definido de manera más lógica de modo que será más fácil de programar y de leer. La palabra ensamblador se utiliza para referirse al lenguaje ensamblador y también al programa ensamblador. Operaciones Las instrucciones de la CPU pueden agruparse, según su funcionalidad, en: Operaciones con enteros: (de 8, 16, 32 y 64 bits dependiendo de la arquitectura de la CPU, Estas son las operaciones que realiza la ALU (enlace a Arquitectura Básica) de la CPU • Operaciones aritméticas. • Operaciones booleanas. • Operaciones de bits. • Comparaciones Operaciones de movimiento de datos: Entre los registros y la memoria: Aunque la instrucción se llama "mover", en la CPU, "mover datos" significa en realidad copiar datos, desde un origen a un destino, sin que el dato desaparezca del origen. Se pueden mover valores: • desde un registro a otro • desde un registro a una dirección de memoria • desde una dirección de memoria a un registro • desde una dirección de memoria a otra • asignar un valor inmediato a un registro • asignar un valor inmediato a una dirección de memoria Operaciones de pila: La pila es una serie de posiciones de memoria especiales donde los datos se almacenan como en una caja. El primer dato en entrar será el último en ser leído mientras que el último dato en entrar será el primero en ser leído. Por eso se llama pila y su almacenamiento es de tipo LIFO (Last Input, First Output) • PUSH escribe datos en la pila. • POP lee datos de la pila Operaciones de entrada/salida: Son operaciones que mueven datos de un registro o desde la memoria hacia un puerto o viceversa. • INPUT Lectura desde un puerto de entrada • OUTPUT Escritura hacia un puerto de salida Operaciones para el control del flujo del programa: Saltos condicionales de acuerdo con el resultado de operaciones de comparación Saltos incondicionales Llamadas y retornos de interrupciones Llamadas y retornos de subrutinas Operaciones con números reales: La ALU de una CPU sólo puede sumar, aun así diferentes secuencias de instrucciones así como la utilización de diferentes códigos y bits de acarreo y signo permiten realizar las operaciones aritméticas básicas y otras más complejas. Una CPU puede tener operaciones de punto flotante con números reales a través de un coprocesador numérico. Operaciones matemáticas: Operaciones aritméticas. Suma, resta, multiplicación, división, cambio de signo, valor absoluto, parte entera Operaciones trigonométricas. Operaciones con logaritmos, potencias y raíces. Lenguaje máquina El lenguaje ensamblador utiliza mnemónicos para cada una de las instrucciones de la CPU. Aun así su programación no es sencilla pues es necesario conocer a fondo la arquitectura física del microprocesador para poder programarlo eficientemente. Por ejemplo, en un lenguaje una sentencia del tipo: MOVER RB, 45H Asigna el valor hexadecimal 45 (69 en decimal) al registro B. El programa ensamblador lee la sentencia de arriba y produce su equivalente binario en lenguaje de máquina, en este caso es una instrucción de dos palabras, la primera palabra estará codificada en el juego de instrucciones del microprocesador, se trata de una codificación arbitraria en la que la instrucción MOVER RB Hx puede estar codificada como 1F (por ejemplo) y la segunda palabra sería el valor propiamente dicho, en este caso el 45 de modo que tendríamos: Binario: 00011111 (1F) 010010101 (45) (hexadecimal: 1F 45) El mnemónico MOVER (MOV en Inglés) es un código de operación u opcode. Como acabo de indicar el opcode es seguido por la lista de argumentos o parámetros, (en este caso uno) completando la instrucción de ensamblador. En el ejemplo, RB es un registro de 8 bits del procesador, al cual le asignaremos el valor hexadecimal 45 tal y como se ha indicado. Por tanto el código de máquina que genera el ensamblador estará formado por 2 bytes. El primero contendrá la instrucción MOVER (codificada arbitrariamente) y el segundo contendrá el valor introducido 45. Dicha instrucción binaria 00011111 010010101 será interpretada directamente por el procesador el cual al final del ciclo habrá introducido el valor 01000101 en el registro RB. Macros Una macro en ensamblador es una secuencia de instrucciones. Una vez un macro ha sido definido, su nombre puede ser usado en lugar de un mnemónico. Cuando el ensamblador procesa la macro, reemplaza la sentencia por las líneas del texto asociadas a ese macro, entonces las procesa como si hubieran existido en el archivo del código fuente original. Es decir una macro en ensamblador es una subrutina, es decir un programa corto escrito previamente y almacenado en un lugar específico de la memoria el cual es llamado cada vez que se invoca la macro. Las macros suelen nombrarse con etiquetas cortas que las definen y hacen que los programas en lenguaje ensamblador parezcan mucho más cortos, requiriendo menos líneas de código fuente, igual que en los lenguajes de alto nivel. Aunque el lenguaje ensamblador es casi siempre manejado y generado por compiladores, todavía se utiliza manipular directamente el hardware, obtener acceso a instrucciones especializadas del procesador, o para resolver problemas de desempeño crítico. Uso actual La complejidad de los procesadores actuales hace la optimización cada vez más difícil para los compiladores, además las prestaciones cada vez mayores de los procesadores hacen que la mayoría de las CPU permanezcan desocupadas la mayor parte del tiempo. Esto hace que la velocidad de ejecución de código no sea ya un problema. El lenguaje ensamblador se utiliza principalmente para traducir lenguajes de alto nivel en código máquina, o para funciones críticas o en procesos industriales, sobre todo si es importante el tiempo real. También se utiliza si se necesita un ejecutable independiente (stand-alone) que deba ejecutarse sin recursos. Son programas empotrados que solo disponen de una pequeña cantidad de memoria y está dirigido para hacer tareas con propósito simple, por ejemplo en teléfonos, sistemas de ignición de combustible para automóviles, control de aire acondicionado, sensores y sistemas de seguridad. O cuando se necesitan utilizar instrucciones específicas del procesador no disponibles por el compilador. Un ejemplo es la instrucción de rotación de bits que se utiliza en algoritmos de cifrado. El lenguaje ensamblador es todavía enseñado en los programas de ciencias de la computación y en ingeniería electrónica. Aunque pocos programadores trabajan regularmente con el lenguaje directamente, este es muy útil para estudiar conceptos fundamentales, como aritmética binaria, asignación de memoria, procesamiento del stack, procesamiento de interrupciones, y diseño de compiladores. La mayoría de los computadores modernos tienen un conjunto de instrucciones similares. Con lo que estudiar un solo lenguaje ensamblador es suficiente para aprender. Lenguajes de nivel medio como C, proveen sintaxis especial para empotrar lenguaje ensamblador en la plataforma hardware. El lenguaje ensamblador también es valioso para hacer ingeniería inversa, pues muchos programas son distribuidos exclusivamente como código de máquina. El código de máquina es fácil de trasladar hacia lenguaje ensamblador para luego ser examinado en esta forma, aunque sigue siendo muy difícil trasladarlo a un lenguaje de alto nivel. También existen herramientas para hacer esto último de forma automática.

Juego Básico en Python

/*Este código no es de mi autoría, pertenece al blog hackmundy labs.*/ Estando estudiando python y practicando Hoy les presento mi primer juego basico espero que les guste... es para linux pero si desean en windows solo quitan la linea #!/usr/bin/env python y debes de "clear" le ponen "cls"... #!/usr/bin/env python #encoding: utf-8 import random import time import os class game: m_archivo=open("bienvenido.txt","r") a=m_archivo.readline() print a while a != "": a= m_archivo.readline() print a print "BIENVENIDOS A GAMES BY HACKMUNDY" def juego1(self,nombre): self.nombre=nombre print "Bienvenido al Juego 1" time.sleep(1) print "Suerte la Nesecitaras Xd...." time.sleep(2) print " " n_al=random.randrange(1,101) q="si" con=0 while (q == "Si") or (q=="si"): os.system("clear") print "ADIVINA QUE NUMERO PIENSO ES UN NUMERO ENTRE EL RANGO 1 AL 100..." print "" num=int(raw_input("Su Intento: ")) if num == n_al: print " " print "Enhorabuena Acertastes, Bien echo" print "Felicidades", self.nombre print "Numero de intentos: ",con print "" q=raw_input("Quieres continuar: ") if q=="no" or q=="No": print "" print "\a" print "Adios ",self.nombre,"Suerte para la proxima..." print "Numero de Intentos: ",con print "Saliendo del juego...." time.sleep(2) os.system("clear") self.__init__() else: print "" print "\a" print "Mala suerte perdistes, intentalo de nuevo.." print "Tranquilo en la proxima ganaras ",self.nombre if num > n_al: print "Escribe un numero mas chico ", self.nombre elif num < n_al: print "Escribe un numero mas Grande ",self.nombre print "" i=raw_input("") con=con+1 def juego2(self,nombre): self.nombre=nombre print " " print "Bienvenido al Juego 2" time.sleep(1) print "Suerte la Nesecitaras Xd...." time.sleep(2) print " " print "Elije tu favorito: " print "1.- Color en palabras" print "2.- Cero X" print " " hq="si" con=0 time.sleep(1) ele=int(raw_input("Elije cual quieres: ")) if ele == 1: #Comenzando el Juego 2 (color) print "Bienvenido Has elejido el Color en Palabras..." print "\a" print "" difi=3 con=0 while (hq=="si") or (hq=="Si"): tupla=("Rojo","Verde","Amarillo") seq=[] inte=[] for x in range(difi): r=random.randrange(3) seq.append(tupla[r]) os.system("clear") for s in seq: print s,"\a" time.sleep(1) os.system("clear") for e in range(difi): print "Introdusca..." print "1.- Rojo" print "2.- Verde" print "3.- Amarillo" print "" su=int(raw_input("?: ")) if su > 4: print "Elijistes un numero equivocado...." print "Reiniciando Juego" time.sleep(2) os.system("clear") self.juego2(self.nombre) inte.append(tupla[su-1]) os.system("clear") con=con+1 if seq==inte: print " " print "Enhorabuena Acertastes, Bien echo" print "Felicidades", self.nombre print "Numero de intentos: ",con print "Nivel de dificultad ", difi-2 print "" print "Aumentando Dificultad....." difi=difi+1 time.sleep(1) else: print "" print "\a" print "Mala suerte perdistes, intentalo de nuevo.." print "Tranquilo en la proxima ganaras ",self.nombre print "Nivel de dificultad " ,difi-2 print "" print "Disminuyendo Dificultad....." difi=difi-1 time.sleep(1) hq=raw_input("Quiere continuar: ") if hq=="no" or hq=="No": print "" print "\a" print "Adios ",self.nombre,"Suerte para la proxima..." print "Numero de Intentos: ",con print "Nivel de dificultad " ,difi-2 print "Saliendo del juego...." time.sleep(2) os.system("clear") self.__init__() elif ele==2:#Comenzando eleccion 2 di=3 while (hq=="si") or (hq=="Si"): tupla1=("x,0,0","0,x,0","0,0,x") seq1=[] inte1=[] for a in range(di): h=random.randrange(3) seq1.append(tupla1[h]) os.system("clear") for g in seq1: print g, "\a" time.sleep(1) os.system("clear") for pon in range(di): print "Introdusca...." print "1.- x,0,0" print "2.- 0,x,0" print "3.- 0,0,x" ten=int(raw_input("?: ")) if su > 4: print "Elijistes un numero equivocado...." print "Reiniciando Juego" time.sleep(2) os.system("cls") self.juego2(self.nombre) inte1.append(tupla1[ten-1]) os.system("clear") con=con+1 if seq1==inte1: print " " print "Enhorabuena Acertastes, Bien echo" print "Felicidades", self.nombre print "Numero de intentos: ",con print "Nivel de dificultad ", di - 2 print "" print "Aumentando Dificultad....." di=di+1 time.sleep(1) else: print "" print "\a" print "Mala suerte perdistes, intentalo de nuevo.." print "Tranquilo en la proxima ganaras ",self.nombre print "Nivel de dificultad ", di-2 print "" print "Disminuyendo Dificultad....." di=di+1 time.sleep(1) hq=raw_input("Quiere continuar: ") if hq=="no" or hq=="No": print "" print "\a" print "Adios ",self.nombre,"Suerte para la proxima..." print "Numero de Intentos: ",con print "Nivel de dificultad ",di-2 print "Saliendo del juego...." time.sleep(2) os.system("clear") self.__init__() else: print "\a \a \a" print "Has puesto un numero mal .... Elije otro" self.juego2(self.nombre) def __init__(self): print " " time.sleep(1) print "Elije tu juego...." print " " print "1.- Adivina el Numero" print "2.- Juego de Memoria" print "3.- Salir" print " " nom=raw_input("Cual es tu Nombre: ") cual=int(raw_input("Cual juego quiere jugar: ")) if cual == 1: print "\a" os.system("clear") self.juego1(nom) elif cual ==2: print "\a" os.system("clear") self.juego2(nom) elif cual == 3: print "\a" print "Gracias por Utilizar el Software...." print "Cualquier fallo, me podrias ayudr diciendomelo...." print "Hasta la proxima ",nom time.sleep(2) else: print "\a \a \a" print "Has puesto un numero mal .... Elije otro" self.__init__() game()

Notas musicales con "beep"

/*Este texto no es de mi autoria, pertenece al blog Code 0x66*/ ¡Hola de nuevo! Como ya hacía lo suyo que no sacaba nada, pues me dió por poner una función cortita, pero curiosa: Reproducir música con los "Beeps" de Windows. Pues venga, empiezo con una introducción: Seguro que habéis escuchado alguna vez un "Beep". Antes se escuchaban más, ahora ya no tanto, pero un Beep es ese sonido que solía escucharse cuando nos salía la ventanita de "StickyKeys", que saltaba al pulsar 5 veces Shift (creo). Esta función puede sacar el sonido por la placa de sonido, o por el altavoz (Windows 7 y superiores generalmente). Quien quiera tener más claro su funcionamiento, puede leer toda su inforación en la página de MSDN: MSDN - Beep. Ahora al tema. La función Beep() de la librería windows.h (no olvidéis el include), coge 2 parámetros: La frecuencia del sonido a reproducir, en hertzios, y la duración del sonido, en milisegundos. Quedaría así: Beep(unsigned int hz, unsigned int ms). Ahora, bien, dado que nosotros (al menos yo) solo conozco la frecuencia de la nota LA (440 Hz), si quiero componer una "cancioncilla" con esta función, me va a costar mucho. Para facilitar este proceso, dejo aquí uno de los snippets del día: enum notas{ DO=1, DO_S=2, RE, RE_S, MI, FA, FA_S, SOL, SOL_S, LA, LA_S, SI }; void note(int octava, int nota, int ms){ if(octava<=0 || nota<0 ||ms<=0) return; double oct = octava, no = nota; double n = 440.0 * exp(((oct-4)+(no-10)/12)*log(2)); if(n<37 || n>32767) return; Beep(n, ms); } Vamos a desglosar la función note(int octava, int nota, int ms). Esta función coge la nota y la octava (mirad en wikipedia por ejemplo para saber qué es), las transforma a una frecuencia, y se la pasa a Beep(). El primer "if", comprueba que ningún valor sea negativo ni 0. No tiene mucho más. Ahora, creamos 2 variables que lo único que harán será convertir int a double, ya que sinó las operaciones no guardarán decimales. La variable double n será el contenedor para nuestra ecuación. Esa ecuación la podéis encontrar por ahí. (Por si os lo preguntáis, yo no me la sé). El segundo "if" tiene una finalidad bastante concreta, y es la función Beep() debe recibir una frecuencia de entre 37 y 32767 hertzios. Y bueno, finalmente llamamos a la función, pasándole los hertzios que hemos obtenido, y los milisegundos. ¡No nos olvidemos de la parte más importante del código! Sin el enum sería algo complicado saber qué numero corresponde a cada nota. Para finalizar esta entrada, os paso una cancioncilla muy conocida que convertí a "Beep". Ciao y ¡nos vemos en otra entrada! void tetris(int velocity=200){ note(4, LA, velocity*2); note(4, MI, velocity*1); note(4, FA, velocity*1); note(4, SOL, velocity*2); note(4, FA, velocity*1); note(4, MI, velocity*1); note(4, RE, velocity*2); note(4, RE, velocity*1); note(4, FA, velocity*1); note(4, LA, velocity*2); note(4, SOL, velocity*1); note(4, FA, velocity*1); note(4, MI, velocity*2); note(4, MI, velocity*1); note(4, FA, velocity*1); note(4, SOL, velocity*2); note(4, LA, velocity*2); note(4, FA, velocity*2); note(4, RE, velocity*2); note(4, RE, velocity*4); thSleep(velocity); note(4, SOL, velocity*2); note(4, LA_S, velocity*1); /*****************************************************/ note(5, RE, velocity*1); note(5, RE, velocity*1); note(4, DO, velocity*1); note(4, LA_S, velocity*1); note(4, LA, velocity*3); note(4, FA, velocity*1); note(4, LA, velocity*1); note(4, LA, velocity*1); note(4, SOL, velocity*1); note(4, FA, velocity*1); note(4, MI, velocity*2); note(4, MI, velocity*1); note(4, FA, velocity*1); note(4, SOL, velocity*2); note(4, LA, velocity*2); note(4, FA, velocity*2); note(4, RE, velocity*2); note(4, RE, velocity*4); }

Contenedores(Map)

/*Este texto no es de mi autoría, pertenece al blog Code 0x66.*/ Hola. Ya hace tiempo desde la última entrada, así que aquí va esta, para continuar la serie. En la última entrada, hemos visto por encima el uso básico del vector, en este caso, veremos el map. Map Este contenedor, está incluído en la librería . Su uso es casi ta sencillo como el vector: El map guarda 2 datos: En primer lugar, guarda las llaves o keys. Las keys no se pueden repetir. Cada key tiene asignado un valor. Los valores sí se pueden repetir. Cuando buscamos un dato en un map, lo que vamos a buscar es el valor que tiene asignado una determinada key. Además, tanto la key como el valor pueden ser de cualquier tipo, salvo por 1 regla: la key, si es una clase, ha de tener la siguiente función declarada: "bool operator<(const asd a)const{/* */}". ¿Por qué ha de tener este operador, el operador menor que? El map tiene otra utilidad muy importante: ordena sus elementos según la key. Los ordena utilizando el operator<(). Para ver bien todos estos conceptos, veamos un ejemplo sencillo: #include #include using namespace std; /** Hagamos una especie de diccionario **/ int main(){ map m; //key:string, value:string m["enorme"] = "Que es muy grande"; m["enano"] = "Que es muy pequeño"; cout << "Definicion de 'enorme': " << m["enorme"]; } Como habéis visto, el operator[] nos permite acceder a su llave, o crearla si no ha sido creada aún. También podemos acceder a sus elementos ordenados haciendo uso de su iterator. for(auto it:m) cout << it.first << " significa " << it.second << endl; Nota: El iterator de map retorna los valores como pair. Un pair guarda 2 valores, que corresponden al first (key) y al second (value). Otra implementación importante de C++11, es el for( : ) y el auto. El auto asigna el tipo adecuado a una variable. Por ejemplo, si ponemos "auto a = 27;" estamos declarando 'a' como un entero (int). El for( type a : b ) nos reduce lo que tenemos que escribir. Es como poner "for(auto a=b.begin(); a!=b.end(); a++){}". Si probamos ese ejemplo, veremos que sale la salida ordenada. El map ordena su key, ya que guarda los datos como un árbol binario, hecho que le da mucha más velocidad al buscar keys. Así que ya sabéis, si queréis que un map os ordene los elementos, o queréis guardar muchos pares de datos, solo usad map. Si queréis guardar como key una clase vuestra, no olvidéis ponerle el operator, aunque es posible que el compilador ya os diga qué operator falta. Ahora solo, suerte!

Herencia (Exceptions)

/*Este texto no es de mi autoria, es del blog Code 0x66.*/ En esta entrada, veremos un ejemplo de herencia y de funciones virtuales, usando como base de la explicación la clase "std::exception" de la librería estandar. Para empezar: La clase exception es una clase utilizada en la librería estándar para unificar el manejo de excepciones. Las excepciones que puedes lanzar en C++ son de cualquier tipo, ya sean tipos básicos u objetos. Se capturan mediante el uso de las sentencias try{ /* ... */}catch( tipo variable ){ /* ... */}. Si queremos capturar una excepción de la librería estándar, basta poner "exception& e" en el catch. Ahora volviendo al tema: Si creamos una clase, y hacemos que herede de std::exception, podremos lanzar y capturar esa clase con el mismo catch. De hecho, al colocar "exception& e", estamos cogiendo la variable por referencia, y dado que nuestro objeto hereda de exception, podremos usar sus funciones virtuales. La función virtual principal de la clase exception es la función "what()", que retorna una cadena con el error ocurrido. Veamos un ejemplo: #include #include using namespace std; class exc:public exception{ /* */ }; int main(){} Importante incluir la librería exception para poder usar la clase exception. Una vez puesta la base, vamos a la función virtual más importante: virtual const char* what() const throw(){ return "Error"; } Hasta aquí lo más básico. Luego, como otra clase cualquiera, la podéis personalizar como queráis. Aquí pongo una clase que hice yo de este modo: class exc:public exception{ string _msg; public: exc(string msg="Error - Exception"):_msg(msg){} exc(int error_code){ _msg = "Error " + to_string(error_code); } exc(const exc& e):_msg(e.what()){} exc operator=(const exc& e){_msg = e.what();} exc operator=(string s){_msg = s;} exc operator=(int error_code){ _msg = "Error " + to_string(error_code); } virtual const char* what() const throw(){ return _msg.c_str(); } }; Prácticamente creé 3 constructores (y 3 operator= equivalentes), y guardo los datos en la string _msg. El primero de los constructores recoge una string, y directamente iguala el _msg con ella. El segundo de ellos, recoge un entero a modo de error, y genera un mensaje del tipo "Error " + código haciendo uso de to_string(), que transforma un número a una string. El tercero de ellos es el constructor de copia. La función virtual what(), lo único que hace es retornar el _msg. (Como la función es del tipo const char*, retorna _msg.c_str(), que retorna la cadena constante de char. Aunque realmente no es un código complejo, siempre puede ser útil generar excepciones propias. Esto es un código ya listo para quien quiera probar: #include #include using namespace std; class exc:public exception{ string _msg; public: exc(string msg="Error - Exception"):_msg(msg){} exc(int error_code){ _msg = "Error " + to_string(error_code); } exc(const exc& e):_msg(e.what()){} exc operator=(const exc& e){_msg = e.what();} exc operator=(string s){_msg = s;} exc operator=(int error_code){ _msg = "Error " + to_string(error_code); } virtual const char* what() const throw(){ return _msg.c_str(); } }; double div(double a, double b){ if(b==0) throw exc(666); return a/b; } int main(){ try{ cout << div(56.0 , 0.0) << endl; }catch(exception& e){ cout << e.what() << endl; } return 0; } Y hasta aquí esta entrada. Hacía ya un tiempo que no sacaba nada, así que se me ocurrió sacar algo del tema herencia. Y de paso, excepciones. Dos pájaros de un tiro. Suerte, y adiós ;D

Vectores C++/C++11

Hola de nuevo. Empezaré una serie de entradas donde se verán algunos aspectos de C++11, y otros temas de C++, tales como contenedores de datos, threads, etc. En este caso, veremos el vector. Vector Este contenedor, incluído en la librería , sirve para guardar ordenado cualquier tipo de dato. Para ello, se declara con un template. Al igual que la mayoría de contenedores de la STL, tiene las función .size(), para saber la cantidad de elementos que contiene, además de el operator[], para acceder a un determinado elemento, y varias formas de insertar datos, tales como insert() y push_back(). Esta última será la que use aquí. También tiene la función .erase(), a la que se le habrá de pasar un iterator del vector, que podemos conseguir con .begin() y .end(). Para aclarar todo esto, aquí va un ejemplo: #include #include using namespace std; int main(){ vector v; //Declaración de 'v' como vector de enteros (int) v.push_back(102); //Elemento 1 v.push_back(66); //Elemento 2 cout << v[0] << endl; //Mostramos el elemento 1 v.erase(v.begin()); //Borramos el elemento 1 cout << v[0] << endl; //Mostramos el elemento 2, //ya que hemos borrado el 1 cin.get(); //Pausa el programa return 0; } En el caso de que quisieramos borrar, por ejemplo, el elemento 5, pondríamos v.erase( v.begin() + 5 );. Con esto, le sumamos 5 al iterator, que es lo que devuelve v.begin(), dando como resultado el quinto elemento.