Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Manual de Cisco by Gerson
Manual de Cisco by Gerson
1 – By Gerson
0.1.2 ¿Qué es IDE?
IDE ( Integrated Development Environment ) es una
aplicación de software que generalmente consta de un editor de
código, un compilador, un depurador y un generador de interfaz
gráfica de usuario (GUI).
La programación con un IDE tiene muchas ventajas: obtienes un
kit de herramientas que contiene todo lo que puedas
necesitar. Los programadores reales también suelen usar un
IDE. Un IDE le brinda un cómodo escritorio equipado con todos los
medios, suministros y ayudas.
También hay algunas desventajas. Los escritorios cómodos
generalmente pesan mucho. También los IDEs. Es posible que
consuman muchos recursos y, francamente, probablemente no
necesite la mayoría de las funciones que pueden realizar.
El uso de herramientas en línea le permite escribir, almacenar y
ejecutar su código sin instalar nada. Imagínelo como un IDE
simplificado accesible de forma remota a través de Internet. Eso
significa que necesita dos cosas: un navegador de Internet y
acceso a Internet.
Si puede probar ambos enfoques, elija el que sea más conveniente
para usted. Si no puede, elija el que puede usar.
2 – By Gerson
0.1.3 Elija su IDE
descargas: https://www.visualstudio.com/products/free-
developer-offers-vs.aspx
descargas: https://www.eclipse.org/downloads
NetBeans
Entorno de desarrollo multiplataforma diseñado especialmente
para Java. Programación en C ++ posible sin configuración
adicional (versión de C ++ dedicada disponible para descargar).
descargas: https://netbeans.org/downloads/index.html
Código :: Bloques
Entorno de desarrollo multiplataforma diseñado para
programación C / C ++. El instalador predeterminado de Windows
no incluye el compilador de C ++; en su lugar, use el que contiene
"mingw-setup" dentro del nombre del archivo.
descargas: http://www.codeblocks.org/downloads/binaries
XCode
4 – By Gerson
Entorno de desarrollo de plataforma única diseñado especialmente
para crear aplicaciones para sistemas operativos diseñados por
Apple Inc. Programación en C ++ totalmente disponible.
descargas: https://developer.apple.com/xcode/download
5 – By Gerson
0.1.4 Herramientas en línea: ideone
#include <iostream>
usando el espacio de nombres estándar;
int main (void) {cout << "Está funcionando" << endl; }
Luego haga clic en el botón "Ideone it". El texto que dice "Está
funcionando" debería aparecer casi de inmediato en el campo
estándar; esto significa que su código fuente ha sido compilado y
ejecutado felizmente.
6 – By Gerson
Algo importante: si su programa lee cualquier dato de un usuario,
deberá preparar los datos dentro del campo estándar antes de
ejecutar el código (normalmente el proceso de lectura de entrada
es interactivo).
7 – By Gerson
1.1.1 Lenguaje natural vs. lenguaje de programación
9 – By Gerson
no está destinado a un ser humano, sino a una máquina.
Quizás se pregunte por qué necesitamos usar un lenguaje de
programación, y esa es una buena pregunta. Tratemos de
responderlo.
10 – By Gerson
informática, era el único método de programación disponible, y
rápidamente reveló sus serias fallas.
La programación en lenguaje de máquina requiere un
conocimiento completo del diseño de hardware de una
computadora y su estructura interna. Esto también significa que
reemplazar la computadora con una que difiera en diseño de su
predecesora puede hacer que todo el conocimiento del
programador sea inutilizable. Además, los viejos programas
podrían ser completamente inútiles si la nueva computadora usara
una IL diferente. Por lo tanto, un programa escrito para un tipo
específico de computadora podría ser completamente inútil para
otras computadoras y viceversa. En segundo lugar, los programas
escritos en lenguaje máquina son muy difíciles de entender
para los humanos , incluidos los programadores
experimentados. También es el caso de que desarrollar un
programa en lenguaje de máquina lleva mucho tiempo y es muy
costoso y engorroso.
Todas estas circunstancias conducen a la necesidad de algún tipo
de puente entre el lenguaje de las personas (lenguaje natural) y
el lenguaje de computadora (lenguaje de máquina). Ese puente
también es un lenguaje, un lenguaje común intermedio para
humanos y computadoras que trabajan juntos. Tal lenguaje a
menudo se llama lenguaje de programación de alto nivel .
Un lenguaje como este es al menos algo similar a un lenguaje
natural: utiliza símbolos, palabras y convenciones legibles para los
humanos. Este lenguaje permite a los humanos expresar
comandos complejos para computadoras.
Tal vez se pregunte cómo convencer a una computadora para que
comprenda los programas escritos de esta manera. Por más que
lo intente, alentar a la computadora no es suficiente, pero puede
traducir su programa al lenguaje de máquina. Además, la
traducción puede ser realizada por una computadora, haciendo
que todo el proceso sea rápido y eficiente.
¿Qué tan genial es eso? No necesita aprender muchos lenguajes
de máquina diferentes, solo necesita conocer un lenguaje de
programación de alto nivel. Si hay un traductor diseñado para una
computadora específica, puede ejecutar su programa sin ningún
problema. En otras palabras, los programas escritos en lenguajes
de alto nivel pueden traducirse a cualquier número de lenguajes
11 – By Gerson
de máquina diferentes y, por lo tanto, pueden usarse en muchas
computadoras diferentes. Esto se llama portabilidad .
13 – By Gerson
1.1.4 Lecturas adicionales
Inicio
1.2.1 Su primer programa (1)
15 – By Gerson
Eso es todo lo que queremos en este momento.
¿Qué pasos adicionales debe realizar nuestro primer
programa? Intentemos enumerarlos aquí:
1. para comenzar
2. para escribir el texto en la pantalla
3. para detener
Vamonos.
source_01_02_01_itsme.cpp
16 – By Gerson
1.2.2 Su primer programa (2)
Ya hemos dicho algo sobre los bloques. Ahora vamos un poco más
profundo. Uno de los tipos más comunes de bloques utilizados
para construir programas en C ++ son las funciones .
Si asocia una función con las matemáticas, está en el camino
correcto. Imagine una función como una caja negra, donde puede
insertar algo en ella (aunque esto no siempre es necesario) y sacar
algo nuevo de ella, como si fuera un sombrero mágico. Las cosas
que se deben poner en el cuadro se llaman argumentos de
función (o parámetros de función). Las cosas que se deben sacar
de la caja se denominan resultados de función . Además, una
función puede hacer algo más en el lateral.
Si esto suena bastante vago, no se preocupe, hablaremos de las
funciones muchas veces y con mucho más detalle más adelante.
20 – By Gerson
1.2.5 Su primer programa (5)
21 – By Gerson
"int main (nulo);"
cout
<<
" Soy yo, tu primer programa".
;
22 – By Gerson
1.2.6 Su primer programa (6)
devuelve 0;
Si fueras a escribir:
retorno 1;
23 – By Gerson
el programa finaliza inmediatamente después de la impresión,
lo que indica que se ha logrado todo lo que esperaba lograr.
24 – By Gerson
número que determina su tipo, rango y aplicación se
denomina tipo .
11,111,111
11.111.111
o incluso así:
11 111 111
25 – By Gerson
11111111
-11111111
+123
123
0123
0x123
26 – By Gerson
es un número hexadecimal con el valor (decimal) igual a 291 .
un nombre
un tipo
un valor
yo
t10
Tipo de cambio
mostrador
DaysToTheEndOfTheWorld
TheNameOfAVariableWhichIsSoLongThatYouWillNotBeAbleToW
riteItWithoutMistakes
_
28 – By Gerson
1.3.3 Una variable es variable (2)
29 – By Gerson
¿Qué declara el siguiente fragmento de un programa?
int variable1, balance_cuenta, facturas;
Declara tres variables de tipo int nombradas
(respectivamente) variable1 , balance_cuenta y facturas .
Recuerde que puede usar tantas declaraciones de variables
como sea necesario para lograr su objetivo.
Otro ejemplo →
30 – By Gerson
En este caso, el nuevo valor de la variable Resultado será el
resultado de sumar 100 a 200, pero probablemente ya lo haya
adivinado, ¿verdad?
32 – By Gerson
1.3.9 Comentarios sobre los comentarios (1)
// comentarios de línea
y
33 – By Gerson
/ * bloquear comentarios * /
/ *
y termina con un par de los siguientes caracteres
*/
34 – By Gerson
1.3.12 Comentarios sobre los comentarios (4)
Solo tenemos una cosa más que decir sobre los comentarios. Los
compiladores difieren en la evaluación de si se puede colocar otro
comentario dentro de un solo comentario. Considere el siguiente
programa →
35 – By Gerson
La pregunta es: ¿se le permite anidar un comentario de bloque
(como / * int j; * / ) dentro de otro comentario de bloque?
La respuesta es no.
No puede usar tal construcción en su código.
36 – By Gerson
1.4.3 Números de coma flotante (3)
4
4.0
37 – By Gerson
Puede pensar que son exactamente iguales, pero el compilador de
C ++ los ve de manera completamente diferente:
4 es un int .
4.0 es un flotador .
Cuando desee usar cualquier número que sea muy grande o muy
pequeño, puede usar la llamada notación científica . Tomemos,
por ejemplo, la velocidad de la luz expresada en metros por
segundo. Escrito directamente se vería así:
300000000
Para evitar el tedioso trabajo de escribir tantos ceros, los libros
de texto de física usan una forma abreviada, que probablemente
ya haya visto:
3 · 108
Significa: tres veces diez a la potencia de ocho
En el lenguaje C ++, el mismo efecto se logra en una forma
ligeramente diferente: eche un vistazo:
3E8
La letra E (también puede usar la letra minúscula e , proviene de
la palabra exponente ) es una representación concisa de la
frase multiplicada por diez por el poder de .
Nota:
38 – By Gerson
1.4.6 Números en coma flotante (6)
Veamos cómo se usa esta convención para registrar números
que son muy pequeños (en el sentido de su valor absoluto que
es cercano a cero).
Una constante física llamada constante de Planck (denotada como
h), según los libros de texto, tiene el valor de
6.62607 · 10-34
Si desea utilizarlo en un programa, lo escribiría de esta manera:
6.62607E-34
Y eso es. No es tan difícil, ¿verdad?
40 – By Gerson
1.4.10 Números de coma flotante (10)
41 – By Gerson
1.4.12 Operadores
1.4.13 Multiplicación
42 – By Gerson
1.4.14 División
1.4.17 Adición
44 – By Gerson
1.4.18 Resta
45 – By Gerson
Por esta razón, el operador de resta se considera uno de los
operadores binarios, al igual que los operadores de suma,
multiplicación y división. Pero el operador menos se puede usar
de una manera diferente: eche un vistazo al fragmento →
Como probablemente haya adivinado, a la variable j se le asignará
el valor de 100. Usamos el operador menos como operador
unario , ya que solo espera un argumento: el correcto.
1.4.21 Resto
46 – By Gerson
El operador restante es bastante peculiar, porque no tiene
equivalente entre los operadores aritméticos tradicionales.
Su representación gráfica en el lenguaje C ++ es el
carácter % (porcentaje), que puede parecer un poco confuso. Es
un operador binario (realiza la operación de módulo ) y ambos
argumentos no pueden ser flotantes (¡no lo olvides!).
Mira el ejemplo →
La variable k es 3 (porque 2 * 5 + 3 = 13).
Ah, y una cosa más que debes recordar: no puedes calcular el
resto con el argumento correcto igual a cero . ¿Puedes
adivinar por qué?
Probablemente recuerdes lo que dijimos antes sobre dividir entre
cero. Y debido a que la división por 0 invoca un comportamiento
indefinido, la operación de módulo, que se basa en la división,
también está indefinida.
Bueno, eso es lo que dice el estándar C ++. Tenemos que aceptar
eso.
1.4.22 Prioridades
1.4.23 Enlaces
48 – By Gerson
1.4.24 Lista de prioridades (1)
49 – By Gerson
1.4.26 Lista de prioridades (3)
50 – By Gerson
1.4.28 Paréntesis (2)
int SheepCounter;
SheepCounter = 0;
SheepCounter = SheepCounter + 1;
SheepCounter ++;
DaysUntilHoliday = DaysUntilHoliday - 1;
DaysUntilHoliday--;
++ SheepCounter;
--DíasUntilHoliday;
52 – By Gerson
Hay una diferencia bastante significativa, como se describe por los
nombres de estos operadores.
53 – By Gerson
1.4.33 Operadores anteriores y posteriores (2)
54 – By Gerson
1.4.35 Pre y post operadores (4)
55 – By Gerson
1.4.37 Operadores de acceso directo (1)
57 – By Gerson
1.5.2 Tipo de personaje (2)
58 – By Gerson
Los humanos no ven estos signos, pero pueden ver el efecto de su
aplicación donde se rompen las líneas.
Podemos crear prácticamente cualquier número de asignaciones
de caracteres, pero un mundo en el que cada tipo de computadora
utiliza una codificación de caracteres diferente sería un mundo
extremadamente inconveniente.
Las computadoras no podrían ponerse de acuerdo en nada y no
podrían hacer ningún trabajo, un poco como los políticos
elegidos. Esto ha llevado a la necesidad de un estándar universal
y ampliamente aceptado, implementado por (casi) todas las
computadoras y sistemas operativos en todo el mundo.
ASCII (abreviatura de American Standard Code for Information
Interchange) es el dispositivo más utilizado y casi todos los
dispositivos modernos (como computadoras, impresoras,
teléfonos móviles, tabletas, etc.) lo utilizan. El código permite 256
caracteres diferentes, pero solo nos interesan los primeros 128.
Si desea verificar cómo se construye el código, eche un vistazo a
la tabla →
Míralo con cuidado, porque hay algunas cosas interesantes
sucediendo aquí. Veamos uno en particular. Vea cuál es el código
para el carácter más común, el espacio. Sí, es 32. Ahora
compruebe cuál es el código para la letra minúscula "a". Es el 97,
¿verdad? Y ahora busquemos la mayúscula "A". Es 65. Ahora reste
el código de "a" de "A", y ¿qué obtienes? 32! Sí, ese es el código
para un espacio. Vamos a utilizar esta característica interesante
del código ASCII pronto.
También tenga en cuenta que las letras están ordenadas en el
mismo orden que en el alfabeto latino.
Por cierto, el código ASCII está siendo reemplazado (o más bien
extendido) por un nuevo estándar internacional llamado
UNICODE.
Afortunadamente, el conjunto ASCII es
un subconjunto UNICODE . UNICODE es capaz de representar
prácticamente todos los personajes utilizados en todo el
mundo. Pasaremos un poco más de tiempo más tarde en esto.
59 – By Gerson
1.5.4 Valores de tipo de caracteres (1)
60 – By Gerson
de la letra mayúscula "A" a una variable de algunas diapositivas
anteriores.
Así es como lo hacemos →
1.5.7 Literales
62 – By Gerson
1.5.8 Literales de caracteres (1)
63 – By Gerson
\ n : denota una transición a una nueva línea y, a veces, se
denomina LF (avance de línea), ya que las impresoras reaccionan
a este carácter moviendo el papel hacia adelante una línea de
texto.
1.5.11 Caracteres de escape (2)
64 – By Gerson
invertida es seguida por dos o tres dígitos octales (los dígitos del
rango de 0 a 7). El número codificado de esta manera se tratará
como un valor ASCII.
Y puede verse así →
47 octal es 39 decimal. Mire la tabla de códigos ASCII y verá que
es el código ASCII para un apóstrofe, por lo que esto es
equivalente a
'\''
(pero solo para computadoras que implementan el código ASCII).
65 – By Gerson
El valor del tipo char puede estar sujeto a los mismos
operadores que los datos del tipo int .
¡Bien hecho! Aquí están las respuestas: 97, 97, 97, 65, 65, 65
66 – By Gerson
1.6.1 Quien pregunta no se equivoca
= es un operador de asignación
== es la pregunta "¿son iguales estos valores?"
67 – By Gerson
1.6.4 Pregunta: ¿es x igual a y?
BlackSheepCounter == (2 * WhiteSheepCounter)
68 – By Gerson
1.6.7 Pregunta: ¿x no es igual a y?
70 – By Gerson
La segunda opción es más conveniente y mucho más común:
podemos usar la respuesta para tomar una decisión sobre el futuro
de nuestro programa. Utilizamos una instrucción especial para
este propósito y la abordaremos muy pronto.
Pero ahora necesitamos actualizar nuestra tabla de
prioridades. Ahora se ve así →
71 – By Gerson
La primera forma de una declaración condicional, que puede ver a
la derecha, está escrita de manera muy informal pero figurativa
→
Esta declaración condicional consta de los siguientes
elementos estrictamente necesarios en este orden (y solo este):
si palabra clave
paréntesis izquierdo (de apertura)
una expresión (una pregunta o una respuesta) cuyo valor se
interpretará únicamente en términos de "verdadero" (cuando
su valor sea distinto de cero) y "falso" (cuando sea igual a cero)
paréntesis derecho (de cierre)
una instrucción (solo una, pero aprenderemos cómo lidiar con
esa limitación)
72 – By Gerson
Sabiendo qué condiciones influyen en nuestro comportamiento y
asumiendo que tenemos funciones sin parámetros, GoForAWalk
() y HaveLunch () , podemos escribir el siguiente fragmento →
74 – By Gerson
1.7.1 Entrada y salida
Las capacidades
de corte reales son mucho
más impresionantes: es
capaz de escribir los datos de
prácticamente cualquier tipo
en la pantalla de una
computadora.
Entonces, ¿qué hacemos si
queremos generar el valor de
tipo int o float , o char , no solo una cadena simple?
75 – By Gerson
1.7.2 Salida (1)
76 – By Gerson
1.7.3 Salida (2)
En este ejemplo →
este fragmento de código da como resultado la cadena Sheep
contada hasta el momento: 123 impresos en la pantalla.
78 – By Gerson
1. FF como una representación hexadecimal de 255 (como efecto
del manipulador hexadecimal)
2. FF nuevamente (la activación hexadecimal anterior todavía
funciona aquí)
3. 255 (como resultado de la activación del manipulador dec)
80 – By Gerson
(newtype) expr
X 88 88 X
81 – By Gerson
1
2
3
2.5
2.5e-009
fijo,
científico.
82 – By Gerson
Tenga en cuenta que inicialmente las transmisiones no están
configuradas ni en el modo fijo ni en el científico, sino en el modo
predeterminado (automático).
El uso de cualquiera de los manipuladores anteriores cambia el
flujo al modo deseado; sin embargo, no puede volver al método
predeterminado de procesamiento de flotantes utilizando ninguno
de los manipuladores.
Debe usar una función especial (pero aquí no vamos a hablar de
esto intencionalmente).
El programa de la derecha → generará el siguiente texto:
2.500000 0.000000
2.500000e + 000 2.500000e-009
83 – By Gerson
Esta no es una solución particularmente conveniente . Es
mucho mejor obtener la información del usuario, transferirla al
programa y luego usarla para los cálculos. Entonces, ¿cómo un
programa de lenguaje C ++ obtiene datos de un humano y los
almacena en variables?
La forma más simple es invertir mentalmente la dirección de la
transferencia y reconocer eso para la entrada de datos:
84 – By Gerson
cout << 2 * i;
source_01_07_15_squareroots.cpp
86 – By Gerson
2.1.1 La declaración condicional (1)
La declaración condicional: más condicional que antes
Concluimos nuestra última discusión sobre declaraciones
condicionales con la promesa de que pronto presentaremos una
forma más compleja y flexible. Comenzamos con una frase simple
que decía: "Si hace buen tiempo, saldremos a caminar". Nota: no
dice nada sobre lo que sucederá si llueve gatos y perros. Solo
sabemos que no iremos afuera, pero lo que podríamos hacer en
cambio no se sabe. Es posible que también queramos planificar
algo en caso de mal tiempo.
En este caso, podemos decir, por ejemplo: "Si hace buen tiempo,
saldremos a caminar, de lo contrario iremos a un teatro". Esta
frase hace que nuestros planes sean más resistentes a los
caprichos del destino: sabemos lo que haremos si se cumplen las
condiciones y sabemos lo que haremos si no todo sigue nuestro
camino. En otras palabras, tenemos un plan "B" .
El lenguaje "C ++" nos permite expresar estos planes
alternativos. Lo hacemos con una segunda forma, un poco más
compleja, de la declaración condicional: aquí está →
87 – By Gerson
Así que ahora tenemos una nueva palabra: de lo contrario , esta
es una palabra clave (palabra reservada). La declaración que
comienza con "else" nos dice qué hacer si no se cumple la
condición especificada para if.
88 – By Gerson
2.1.3 La declaración condicional (3)
89 – By Gerson
el uso de la declaración if como esta se conoce
como anidamiento ; recuerde que todo lo demás se refiere al
primero más cercano si eso no coincide con ningún otro ; así es
como los if sy else s se emparejan;
mire cómo la sangría mejora la legibilidad y enfatiza el
anidamiento de las declaraciones condicionales
internas. Bonita, ¿no es así?
91 – By Gerson
de los seres humanos que viven en la Tierra; en este caso
necesitamos más de 32 bits para representar ese número,
solo necesitamos dos valores diferentes para representar los
estados de activación / desactivación o las condiciones de
verdadero / falso que en realidad no tienen una interpretación
numérica (aunque podemos hacer presunciones para ellos y
usar 1 como 'activado' y 0 como 'desactivado', por ejemplo)
el número de habitantes en la Tierra nunca será un número
negativo ; Parece un desperdicio real que nunca se use hasta
la mitad del rango permitido.
92 – By Gerson
largo : solía declarar que necesitamos un
rango de entradas más amplio que el estándar;
short : se utiliza para declarar que
necesitamos un rango de entradas más estrecho
que el estándar;
unsigned : se utiliza para declarar que una
variable se usará solo para números no negativos; esto puede
sorprenderlo, pero podemos usar este modificador junto con el
tipo char ; Lo explicaremos pronto.
Contador corto;
hormigas largas;
93 – By Gerson
2.2.6 No solo el int es un int (6)
11111110656.000000
95 – By Gerson
No podemos evitar estos efectos cuando sumamos / restamos los
números de tipo flotante (y también el doble , porque también
están afectados por este problema).
Este fenómeno es una de las llamadas anomalías numéricas .
96 – By Gerson
if (developer_is_hungry) {
HaveLunch ();
developer_is_hungry =! developer_is_hungry;
}
98 – By Gerson
2.3.3 Dos programas simples (3)
99 – By Gerson
Necesitarás cientos de declaraciones de variables de tipo int . Si
cree que puede hacer eso, intente imaginar escribir un programa
que encuentre el mayor de un millón de números.
100 – By Gerson
El truco se basa en la suposición de que cualquier parte del código
se puede realizar más de una vez, de hecho, tantas veces como
sea necesario.
Realizar una cierta parte del código más de una vez se
llama bucle . Probablemente ya sabes lo que es un bucle. Vea, los
pasos 2 a 5 hacen un bucle. ¿Podemos usar una estructura similar
en el programa escrito en el lenguaje "C ++"? Si podemos. Y les
contaremos a todos pronto.
101 – By Gerson
Así que ahora has aprendido uno de los bucles disponibles en el
lenguaje "C ++". En general, el bucle se ve así →
102 – By Gerson
2.3.8 El ciclo llamado "while" (4)
103 – By Gerson
2.3.11 El ciclo llamado "while" (7)
source_02_03_11_max_c.cpp
104 – By Gerson
Ciertos fragmentos se pueden simplificar sin cambiar el
comportamiento del programa. Echa un vistazo a la siguiente
diapositiva.
source_02_03_12_odds.cpp
105 – By Gerson
Intente recordar cómo el lenguaje "C ++" interpreta la verdad de
una condición y tenga en cuenta que estas dos formas son
equivalentes.
106 – By Gerson
2.3.16 El ciclo "while" en algunos ejemplos (5)
108 – By Gerson
usuario. Nuestro nuevo programa no se engañará al ingresar el
valor de -1 como primer número. Aquí está el programa →
Echar un vistazo. Utilizamos la variable de contador para contar
los números ingresados para poder indicarle al usuario que no
podemos buscar el mayor número si no se proporciona ningún
número.
Como tenemos que leer al menos un número , tiene sentido
usar el bucle do . Utilizamos este enfoque en el programa.
source_02_03_19_maxdo.cpp
109 – By Gerson
2.3.20 "para in ingles for " - el último bucle (1)
111 – By Gerson
bucle, pero en este caso estará disponible durante y solo
durante la ejecución del bucle.
Aquí hay un ejemplo:
112 – By Gerson
2.3.25 "para" - el último bucle (6)
source_02_03_26_maxbreak.cpp
114 – By Gerson
2.3.27 romper y continuar: las especias del bucle (2)
source_02_03_27_maxcontinue.cpp
115 – By Gerson
2.4.1 Las computadoras y su lógica
¿Has notado que las condiciones que hemos usado hasta ahora
son muy simples, bastante primitivas, de hecho? Las condiciones
que usamos en la vida real son mucho más complejas. Veamos la
siguiente oración:
Si tenemos algo de tiempo libre y el clima es bueno, saldremos a
caminar.
Hemos utilizado la conjunción " y ", lo que significa que salir a
caminar depende del cumplimiento simultáneo de las dos
condiciones .
116 – By Gerson
En el lenguaje de la lógica, las condiciones de conexión como esta
se llaman conjunciones. Y ahora otro ejemplo:
Si usted está en el centro comercial o yo en el centro comercial,
uno de nosotros comprará un regalo para mamá.
La aparición de la palabra " o " significa que la compra depende
de al menos una de estas condiciones . En lógica, un
compuesto como este se llama disyunción .
118 – By Gerson
2.4.5 Ser || ! ser - estar
120 – By Gerson
2.4.7 Algunas expresiones lógicas (2)
! ( p && q ) ==! p || ! q
! ( p || q ) ==! p &&! q
121 – By Gerson
Los operadores lógicos toman sus argumentos como un todo,
independientemente de cuántos bits
contengan. Los operadores solo conocen
los valores 0 o falso (cuando se
restablecen todos los bits), lo que
significa "falso", o no 0 o verdadero
(cuando se establece al menos un bit), lo
que significa "verdadero". El resultado de
sus operaciones es el valor 0 (falso) o 1
(verdadero) .
Esto significa que el fragmento de la derecha asignará el valor
verdadero a la variable j si i no es falso. De lo contrario, será falso
(¿por qué?).
122 – By Gerson
Mencionemos algo importante aquí: los argumentos de estos
operadores deben ser enteros ( int , así
como long , short o char ); No podemos usar carrozas aquí.
La diferencia en la operación de los operadores lógicos y de bits
es importante: los operadores lógicos no penetran en el nivel de
bits de su argumento. Solo les interesa el valor entero final.
Los operadores bit a bit son más estrictos: se ocupan de cada bit
por separado. Si suponemos que la variable int ocupa 32 bits,
puede imaginar la operación bit a bit como una evaluación de 32
veces del operador lógico para cada par de bits de los
argumentos. Esta analogía es obviamente imperfecta, ya que en
el mundo real todas estas 32 operaciones se realizan al mismo
tiempo.
123 – By Gerson
2.4.10 Cómo lidiar con bits individuales (3)
124 – By Gerson
Estos bits corresponden al valor entero de 6.
125 – By Gerson
2.4.15 Cómo lidiar con bits individuales (8)
126 – By Gerson
Puede enfrentar las siguientes tareas:
#1
verifique el estado de su bit; desea averiguar el valor de su
bit; comparar toda la variable con cero no hará nada porque los
bits restantes pueden tener valores completamente
impredecibles, pero podemos usar la siguiente propiedad de
conjunción:
x&1=x
x&0=0
00000000000000000000000000001000
00000000000000000000000000001000
si su bit se estableció en "1",
00000000000000000000000000000000
si su bit se restableció a "0"
127 – By Gerson
int TheMask = 8;
#2
Restablezca su bit: asigna un cero al bit mientras todos los demás
bits permanecen sin cambios; usaremos la misma propiedad de la
conjunción que antes, pero usaremos una máscara ligeramente
diferente, así:
1111111111111111111111111111110111
128 – By Gerson
2.4.19 Cómo lidiar con bits individuales (12)
#3
Establezca su bit: asigna un "uno" a su bit mientras que todos los
demás bits permanecen sin cambios; utilizaremos la siguiente
propiedad de disyunción:
x|1=1
x|0=x
Ahora estamos listos para configurar su bit con una de las
siguientes instrucciones →
#4
para negar su bit, reemplace "uno" con "cero" y "cero" con
"uno". Usemos una propiedad interesante del operador xor :
x ^ 1 =! x
x^0=x
y niega tu bit con las siguientes instrucciones →
129 – By Gerson
2.4.21 Cómo lidiar con bits individuales (14)
El lenguaje "C ++" nos ofrece otra operación relacionada con bits
individuales: desplazamiento . Se aplica solo a valores enteros
y no se puede usar con flotantes como argumentos.
Usas esta operación inconscientemente todo el tiempo. ¿Cómo
multiplicas cualquier número por 10? Echar un vistazo:
12345 ∙ 10 = 123450
Como puede ver, multiplicar por diez es solo un caso de
desplazamiento de todos los dígitos a la izquierda y agregar un "0"
a la derecha. ¿Cómo se divide por 10? Miremos:
12340 ÷ 10 = 1234
Todo lo que haces es mover los dígitos a la derecha.
131 – By Gerson
2.4.23 Cómo lidiar con bits individuales (16)
2.5.1 Caso y cambio vs. if (1) Case and switch vs. if (1)
2.5.2 Caso y cambio vs. if (2) Case and switch vs. if (2)
133 – By Gerson
2.5.3 Caso y cambio vs. if (3) Case and switch vs. if (3)
2.5.4 Caso y cambio vs. if (4) Case and switch vs. if (4)
También podemos suponer que nuestro programa no tiene una
opinión sobre dónde los valores de i son distintos a los
especificados hasta ahora, y queremos que el programa lo exprese
claramente. ¿Hemos hecho un millón de casos nuevos que cubren
todo el rango del tipo int ?
No. Podemos usar un caso generalizado que cubra todos los
eventos que no se mencionan en los casos anteriores. Así es como
se ve →
134 – By Gerson
Tenga en cuenta que el valor predeterminado también es una
palabra clave.
136 – By Gerson
llama vector en términos matemáticos, también diremos que esta
declaración declara un vector int de tamaño igual a 5.
Todos los elementos de una matriz tienen el mismo tipo.
139 – By Gerson
2.6.10 Matrices: ¿cómo? (10) Arrays – how? (10)
No sabemos lo que piensas, pero definitivamente no nos gusta
cómo se hace. Todavía es aceptable con una matriz de 5
elementos, pero con 99 elementos ciertamente no lo sería.
140 – By Gerson
2.7.1 Inicialización de matriz (1) Array initialization (1)
141 – By Gerson
2.7.4 Inicialización de matriz (4) Array initialization (4)
142 – By Gerson
Prácticamente cada pieza de datos se puede agregar en una
matriz. Incluso una matriz. Te lo mostraremos pronto.
143 – By Gerson
2.9.2 No solo vectores (2) Not only vectors (2)
int fila1 [8], fila2 [8], fila3 [8], fila4 [8], fila5 [8], fila6 [8], fila7 [8], fila8
[8];
144 – By Gerson
Mira nuestro hermoso tablero de ajedrez. Cada campo contiene un
par de índices que deben darse para acceder al contenido del
campo.
Mirando la figura aquí → podemos colocar algunas piezas de
ajedrez en nuestro tablero. Primero, agreguemos todas las torres:
tablero de ajedrez [0] [0] = ROOK;
tablero de ajedrez [0] [7] = ROOK;
tablero de ajedrez [7] [0] = ROOK;
tablero de ajedrez [7] [7] = ROOK;
145 – By Gerson
Intentemos diseñar una matriz capaz de almacenar todos estos
resultados. Primero, tenemos que decidir qué tipo de datos sería
mejor para esta aplicación. Creemos que un flotador sería lo
mejor, ya que nuestro termómetro puede medir la temperatura
con una precisión de 0.1 grados centígrados.
A continuación, decidimos arbitrariamente que las filas registrarán
las lecturas cada hora en punto (por lo que la fila tendrá 24
elementos) y cada una de las filas se asignará a un día del mes
(por lo que necesitamos 31 filas). Aquí está nuestra declaración →
146 – By Gerson
2.9.6 No solo vectores (6) Not only vectors (6)
Ahora queremos contar los días en que la temperatura al
mediodía era de al menos 20 grados centígrados.
147 – By Gerson
Paso uno: el tipo de elemento de la matriz. Creemos que
el int sería una buena opción, aunque también debería estar sin
firmar, ya que no hay un número negativo de invitados.
Paso dos: analice con calma la situación. Resuma la información
disponible: 3 torres, 15 pisos, 20 habitaciones.
Ahora podemos escribir la declaración →
148 – By Gerson
2.10.1 Estructuras: ¿por qué las necesitamos? (1)
Structures – why do we need them? (1)
149 – By Gerson
2.10.2 Estructuras: ¿por qué las necesitamos? (2)
Structures – why do we need them? (2)
151 – By Gerson
2.10.4 Estructuras: ¿por qué las necesitamos? (4)
Structures – why do we need them? (4)
152 – By Gerson
El resultado de este operador es el campo seleccionado de la
estructura y, por lo tanto, la expresión que contiene este operador
a veces se denomina selector .
Esto significa que el selector aquí → da como resultado la selección
de un campo llamado tiempo . El tipo de esta expresión es el tipo
del campo seleccionado y es un valor l.
En consecuencia, podemos usar estos dos selectores:
stdnt.time = 1.5;
y
flotador t;
t = stdnt.time;
153 – By Gerson
stdnts [3] .time
Ahora recopilamos todas estas tareas que se realizan para las tres
matrices separadas. Míralos cuidadosamente:
stndts [0] .name = "Bond";
stndts [0] .time = 3.5;
stdnts [0] .recent_chapter = 4;
154 – By Gerson
DateOfBirth.year = 1980;
DateOfBirth.month = 7;
DateOfBirth.day = 31;
También podemos usar la etiqueta de estructura para declarar
una matriz de estructuras:
FECHA Visitas [100];
Acceder a una única estructura almacenada en la matriz es
fácil. Si queremos modificar los datos de la primera visita,
hacemos esto:
155 – By Gerson
2.10.8 Estructuras: ¿por qué las necesitamos? (7)
Structures – why do we need them? (7)
156 – By Gerson
Prueba sorpresa: ¿cuándo nos visitó Harry por última vez?
fecha.año = 2012;
date.month = 12;
date.day = 21;
he.name = "Bond";
he.time = 3.5;
he.recent_chapter = 4;
he.last_visit.year = 2012
he.last_visit.month = 12;
he.last_visit.day = 21;
Debido a la integridad del inicializador interno, podemos escribir
la siguiente forma simplificada:
ESTUDIANTE he = {"Bond", 3.5, 4, 2012, 12, 21};
159 – By Gerson
Esta simplificación (omitiendo las llaves internas) no se puede
aplicar en el siguiente caso:
ESTUDIANTE ella = {"Mata Hari", 12., 12, {2012}};
El iniciador interno, que se refiere al campo last_visit , no cubre
todos los campos. Esto significa que será equivalente a la
siguiente secuencia de tareas:
she.name = "Mata Hari";
she.time = 12 .;
she.recent_chapter = 12;
she.last_visit.year = 2012
she.last_visit.month = 0;
she.last_visit.day = 0;
160 – By Gerson
Los punteros también son valores , pero diferentes de los
que hemos estado usando hasta ahora. Los tipos que hemos
estado utilizando están estrechamente relacionados con el
procesamiento de datos informáticos, pero reflejan plenamente
nuestras ideas e intuición.
Todos usamos números enteros en la vida cotidiana para
contar. Usamos flotadores cuando pagamos algo e ints cuando
contamos algo. Los punteros no tienen una analogía simple y
obvia con nuestra vida cotidiana y sus valores son ilegibles para
los humanos y completamente inútiles.
Sin embargo, las computadoras pueden hacer un gran uso de los
punteros, brindando a los desarrolladores opciones poderosas al
diseñar algoritmos y estructuras de datos.
Ahora, prepárate para el hecho de que no todo será
inmediatamente obvio para ti. Esto es normal: tomará algún
tiempo antes de que pueda comprender los punteros mismos y
sus rasgos específicos.
161 – By Gerson
vivimos en ciertas direcciones al igual que cada variable "vive" en
su dirección, también.
Intenta obtener esta importante diferencia:
162 – By Gerson
El lenguaje "C ++" también puede usar los llamados punteros
amorfos , que pueden usarse para señalar cualquier tipo de
datos, pero vamos a discutirlos al final de nuestra historia.
163 – By Gerson
Hay una excepción distintiva. Puede asignar cero a la variable
del puntero . Hacer esto no molesta al compilador.
164 – By Gerson
3.1.7 Cómo asignar un valor (4)
How to assign a value (4)
165 – By Gerson
3.1.10 Cómo obtener un valor (1)
How to get a value (1)
¿Cómo obtenemos un valor señalado por el puntero?
¿Qué podemos hacer con un puntero que no es nulo y apunta a
un valor? Podemos desreferenciarlo .
La desreferenciación es una operación en la que la variable
de puntero (como veremos más adelante, no es solo una
variable, sino también una expresión que produce un puntero)
se convierte en sinónimo del valor al que apunta .
Observe cómo podemos declarar una variable de tipo int ( ivar ) y
una variable de tipo int * ( ptr ). Podemos hacerlo dentro de una
sola declaración →
166 – By Gerson
3.1.13 Cómo obtener el valor (4)
How to get the value (4)
167 – By Gerson
3.1.16 Cómo obtener un valor (6)
How to get a value (6)
168 – By Gerson
Este nuevo operador espera que su argumento sea literal o
variable o una expresión entre paréntesis o el nombre del tipo
(este es el único operador "C" que permite que su argumento sea
un tipo).
171 – By Gerson
3.2.1 Punteros frente a matrices (1)
Pointers vs. arrays (1)
172 – By Gerson
3.2.2 Punteros frente a matrices (2)
Pointers vs. arrays (2)
173 – By Gerson
restando un puntero de un puntero que da un número
entero ( ptr - ptr → int )
comparar los dos punteros para igualdad o desigualdad (tal
comparación da un valor de tipo int que representa verdadero
o falso) ( ptr == ptr → int ; ptr ! = ptr → int )
174 – By Gerson
3.2.6 La aritmética de los punteros (4)
The pointers' arithmetic (4)
La comparación:
ptr1 == ptr2
176 – By Gerson
3.2.8 La aritmética de los punteros (6)
The pointers' arithmetic (6)
177 – By Gerson
3.2.11 La aritmética de los punteros (9)
The pointers' arithmetic (9)
nombre
parámetros
tipo de resultado
181 – By Gerson
La parte del código que especifica todos estos elementos se
conoce como la declaración de función . El compilador debe
conocer la declaración de la función para permitirle interpretar
correctamente las invocaciones de la función. La declaración de
función a veces se denomina prototipo de función .
Una declaración de función no dice nada sobre lo que la función
hace exactamente. Esa información es proporcionada por el
cuerpo de la función, que es una parte separada del código, entre
paréntesis.
Una declaración de función enriquecida con un cuerpo de función
forma la denominada definición de función .
182 – By Gerson
Si queremos aprovechar esta función, necesitamos entregar su
definición . Puedes verlo a la derecha →
Nota: la transformación de una declaración en una definición
requiere que agreguemos un cuerpo, pero el cuerpo también
reemplaza el punto y coma que termina la declaración (ver
diapositiva anterior). El cuerpo de la función no termina con un
punto y coma.
El cuerpo contiene:
183 – By Gerson
Los parámetros definidos dentro de la función se
denominan parámetros formales . Los valores realmente
transferidos a la función (por lo tanto, existentes fuera de la
función) se denominan parámetros reales .
La invocación de la función es solo el nombre de la función que se
invoca junto con los valores transferidos (pasados) a la función
como parámetros reales.
Como puede ver, hemos declarado una variable llamada arg y
le hemos asignado el valor de 2.0. A continuación, hemos
invocado la función cuadrada , entregando la variable arg como
argumento (el parámetro real).
El resultado de la función se envía a la pantalla y se muestra como
parte del mensaje que dice " La segunda potencia de 2 es 4 ".
source_03_03_05_square.cpp
184 – By Gerson
3.3.6 Primera función (3)
First function (3)
¿Es posible colocar la función cuadrada después
de la función principal y no antes ? Sí, lo es, pero no olvide que
el compilador debe conocer todos los rasgos de la función
invocada.
Por lo tanto, debe colocar la declaración de función antes de la
primera invocación de función.
Echa un vistazo al código modificado aquí →
185 – By Gerson
3.4.1 Declarar funciones
Declaring functions
186 – By Gerson
retorno y el tipo de los parámetros (si los hay) . Una forma
general de declaración de función (o prototipo de función -
podemos usar estos términos indistintamente) está aquí a la
derecha →
190 – By Gerson
Mire cómo enviamos el valor del parámetro real a la función
invocada. Intente imaginar cómo el parámetro real reemplaza un
parámetro formal dentro de una función.
El usuario recibe un saludo por kilómetro y un saludo adicional
(para aquellos sin ego).
source_03_04_04_ave.cpp
#include <iostream>
include <iostream>
void Greet(void)
{
cout << "Ave user!" << endl;
}
int main(void)
{
int sizeofego;
192 – By Gerson
cout << "How big is your ego? [km]" << endl;
cin >> sizeofego;
GreetManyTimes(1 + sizeofego);
return 0;
}
193 – By Gerson
3.4.7 La sintaxis de invocación - suplemento
The invocation syntax - supplement
VoidFunction (2);
la función NonVoid se puede invocar de las dos formas siguientes:
194 – By Gerson
valor = NonVoidFunction (2);
Función No Vacío (2);
Significa que el resultado de cualquier función no nula puede
ser aceptado por el invocador (el primero) y asignado a una
variable, o utilizado de cualquier otra manera, o puede
ser ignorado por el invocador (el último) y simplemente olvidado
inmediatamente después de la devolución de la función
195 – By Gerson
Las variables globales permiten obtener funciones y
proporcionar datos de cualquier tipo . Si una función modifica
cualquier variable global que no utiliza ningún otro mecanismo de
transferencia de datos, decimos que esta función tiene un efecto
secundario .
Los efectos secundarios, aunque a veces son útiles, no se
recomiendan y se consideran un signo de mal estilo de
programación porque hacen que el código sea difícil de entender.
Echa un vistazo al código de la derecha →
El globvar es una variable global. Su declaración no está
contenida en ninguna función. La función func incrementa
el globvar en cada invocación. Podemos decir que globvar se usa
para contar las ejecuciones de func .
Tenga en cuenta que la función principal también utiliza esta
variable, aunque no modifica el valor de la variable. Por esta
razón, suponemos que la función principal no causa efectos
secundarios.
Evitaremos el uso de efectos secundarios en futuros
ejemplos. Trátelos solo como una posibilidad, no como una rutina.
source_03_05_01_enjoy.cpp
196 – By Gerson
3.5.2 Pasando parámetros por valor
Passing parameters by value
Hasta ahora, hemos estado asumiendo que los valores del
parámetro real se envían a la función y no hemos dicho una
palabra sobre el camino de regreso. Nuestros parámetros viajan
al cuerpo de la función y no esperamos que regresen de allí.
Hagamos un experimento simple que muestre si una función
puede cambiar el valor de su parámetro.
Ahora eche un vistazo al código de la derecha →
Como puede ver,
la función AmIAbleToChangeMyParameter incrementa el valor de
su parámetro. También lo informa al usuario. La pregunta es: ¿el
valor modificado es visible fuera de la función? En otras
palabras: ¿el cambio del parámetro formal refleja el valor
real del parámetro?
197 – By Gerson
Vamos a compilar el código y ejecutarlo. Debe producir el
siguiente resultado:
var = 1
----------
Tengo: 1
Estoy a punto de devolver: 2
----------
var = 1
Analice el ejemplo cuidadosamente y haga el experimento usted
mismo.
Como puede ver, el valor del parámetro formal no reemplaza
el valor del parámetro real al regresar de la
función . Podemos decir que el parámetro real tiene un boleto
unidireccional: transporta un valor a la función y no lo lleva al
invocador.
No te olvides de eso. Esta forma de comunicación se basa en
transferir un valor del invocador a la función. Y es por eso que este
método se llama pasar parámetros por valor .
source_03_05_02_not_able.cpp
198 – By Gerson
3.5.3 Pasando parámetros por referencia (1)
Passing parameters by reference (1)
199 – By Gerson
var = 1
----------
Tengo: 1
Estoy a punto de devolver: 2
----------
var = 2
source_03_05_03_able.cpp
200 – By Gerson
Vea el ejemplo a la derecha →
La función MixedStyles asigna su segundo parámetro con un valor
incrementado de su primer parámetro. Esto significa que el primer
parámetro se pasa por valor, mientras que el último se pasa por
referencia.
El programa produce el siguiente resultado:
var1 = 1, var2 = 2
source_03_05_04_mixed.cpp
201 – By Gerson
podemos usar no solo una variable sino también un resultado
literal, o incluso una invocación de función.
Decimos que esta limitación es "obvia" porque la función no puede
colocar un valor en algo que no sea una variable. No puede asignar
un nuevo valor a un literal ni forzar a una expresión a cambiar su
resultado. Ver el fragmento a la derecha →
Se permiten todas las invocaciones siguientes:
ByVal (i);
ByVal (i + 2);
ByVal (intfun (0));
203 – By Gerson
3.6.1 Parámetros - cont.
Parameters – cont.
Ahora vamos a reescribir nuestra función Greet para que sea más
flexible. Queremos que:
204 – By Gerson
guardar el saludo
205 – By Gerson
Es posible que solo queramos omitir el "1", con la esperanza de
que la función sea lo suficientemente inteligente como para
adivinar lo que vamos a hacer.
¿Es razonable esperar que cualquier función pueda comportarse
de una manera tan conveniente?
La respuesta es sí, pero ... Pero primero debemos informarle que
algunas de las invocaciones no especificarán todos los parámetros
esperados, e indicarán qué valores deben usarse en lugar de los
ausentes. Este mecanismo se llama " parámetros
predeterminados " y presentaremos sus reglas modificando
ligeramente nuestra función anterior.
Podemos modificar la declaración del segundo parámetro formal
usando una frase:
= valor
para indicar que queremos que el compilador asuma el valor
predeterminado para el parámetro cuando lo omitimos durante la
invocación. Si declaramos la función de la siguiente manera:
NewGreet (string greet, int repeats = 1)
el compilador tratará las invocaciones de un parámetro como
esta:
NewGreet ("Hola");
como si estuvieran (explícitamente) escritos de la siguiente
manera:
NewGreet ("Hola", 1);
Ahora mire cuidadosamente el ejemplo a la derecha →
Tenga en cuenta las diferentes formas de invocación. El programa
producirá el siguiente resultado:
Hola
hola
buenos dias
hola
Como puede ver, el valor del parámetro especificado
explícitamente invalida el valor predeterminado.
source_03_06_02_newgreet.cpp
206 – By Gerson
3.6.3 Parámetros predeterminados: un ejemplo más
complejo
Default parameters – a more complex example
Es posible que desee preguntar ahora si es posible tener más de
un parámetro predeterminado en una función, es decir, si
podemos elegir el valor predeterminado no solo para el parámetro
de repeticiones sino también para el saludo .
Si es posible. Aquí hay un ejemplo de cómo hacerlo a la derecha
→
Este mecanismo es útil, pero para aprovecharlo al máximo no
debe olvidarse de las siguientes limitaciones:
207 – By Gerson
mismo orden en que se enumeran en la declaración de
función; Esto significa que no puede usar el valor
predeterminado para el primer parámetro y especificar un valor
explícito para el segundo
source_03_06_03_newgreet2.cpp
209 – By Gerson
memoria independientemente de cuántas veces se invoque la
función. Significa que invocarlo de esta manera ahorra memoria y
hace que su programa sea más compacto.
Pero...
Una de las paradojas más interesantes de la programación de
computadoras dice que cuando un código es compacto, no
puede ser rápido al mismo tiempo; y viceversa, cuando el
código es rápido, no puede ser compacto. Por supuesto, es más
una broma que una ley científica, pero en este caso la regla
funciona muy bien.
Trate de imaginar que nuestro programa invocará la función
muchas veces (por ejemplo, cientos o miles de veces). Puede
significar que tendrá que pagar un alto precio (en el sentido del
tiempo) por todas esas transferencias de control y ejecuciones de
prólogo / epílogo. El precio es más alto cuando la función es corta
(es decir, más corta que el prólogo y el epílogo).
Este ejemplo muestra que a veces, en casos bien definidos, sería
mejor evitar la cadena prólogo-función-epílogo e insertar el
código de la función directamente en el código del
invocador .
211 – By Gerson
no importa si la palabra clave en línea se coloca antes o
después del nombre del tipo; ambas líneas son sintácticamente
correctas:
212 – By Gerson
una función del mismo nombre. Es hora de preguntar si podemos
tener más de una función del mismo nombre.
Si podemos. Es natural que deseemos tener diferentes
herramientas del mismo nombre para diferentes
propósitos . Por ejemplo, necesitamos una función para
encontrar el mayor de dos números flotantes. No parece difícil,
¿verdad?
Bueno, hemos escrito esta función para ti. Echa un vistazo al
fragmento de la derecha →
Podría argumentar que podríamos haber escrito la función de una
manera más compacta. Estamos de acuerdo contigo Es
demasiado detallado. Siéntase libre de reescribirlo de una manera
más inteligente.
213 – By Gerson
¿Qué, no te gusta? A nosotros tampoco nos gusta. No es
agradable ni efectivo. Sería mejor olvidar nuestra antigua función
y escribir una nueva y elegante que se adaptara mucho más a lo
que queremos.
También sería una buena idea nombrarlo como el
anterior: max . Este nombre ilustra perfectamente el rol y el
propósito de la función.
Echa un vistazo al fragmento de la derecha →
214 – By Gerson
Nuestros ejemplos no dejan dudas. La elección es simple: si la
invocación contiene tres parámetros reales, se elige la segunda
variante. Si hay dos parámetros, el compilador usa la primera
variante. Cualquier otra variante de la invocación se considera un
error.
¿Qué circunstancias tiene en cuenta el compilador al elegir la
función de destino (una de las pocas disponibles)?
void fnc(int a) {
}
215 – By Gerson
3.8.4 ¿Cómo encontrar al mejor candidato? (1)
216 – By Gerson
El literal 1.0 no es de tipo flotante . Es de tipo doble (¡en
serio!). El compilador del lenguaje C ++ intenta promover los
tipos si no hay un ajuste exacto (como en nuestro ejemplo:
obviamente, un flotante no es un doble ).
PlayWithNumber (1.0f);
217 – By Gerson
calcula el valor de la expresión1
i = i> 0? 1: 0;
si (i> 0)
i = 1;
más
i=0
218 – By Gerson
3.8.8 Un nuevo operador: un ejemplo (2)
219 – By Gerson
En las siguientes secciones, clasificaremos la matriz en orden
creciente para que los números se ordenen de menor a
mayor. Aquí está nuestra matriz →
220 – By Gerson
3.9.4 Ordenar una matriz (4)
221 – By Gerson
el segundo paso a través de la matriz. Observamos el primer y el
segundo elemento: ¡oh, es necesario un intercambio!
222 – By Gerson
Ahora 6 necesita encontrar su lugar. Lo ayudaremos e
intercambiaremos el segundo y el tercer elemento.
¡Ay! ¡Mira! ¡La matriz ya está ordenada! ¡No tenemos nada más
que hacer! ¡Esto es exactamente lo que queríamos!
Como puede ver, la esencia de este algoritmo es simple:
comparamos los elementos adyacentes y al intercambiar algunos
de ellos logramos nuestro objetivo.
Intentaremos codificar en el lenguaje "C ++" todas las acciones
realizadas durante una sola pasada a través de la matriz, y luego
pensaremos en cuántas pasadas realmente necesitamos. No
hemos analizado esto hasta ahora, y lo discutiremos más
adelante.
223 – By Gerson
3.9.13 Ordenar una matriz (13)
224 – By Gerson
225 – By Gerson
3.9.14 Ordenar una matriz (14)
source_03_09_14_bsort.cpp
226 – By Gerson
3.10.1 nulo - el tipo muy excepcional (1)
void – the very exceptional type (1)
nada en absoluto();
* ptr = 1;
227 – By Gerson
Sin embargo, los punteros de tipo void * son muy útiles cuando
necesita tener un puntero, pero no sabe para qué se puede usar
en el futuro.
Tan pronto como quede claro, el puntero se puede convertir
fácilmente en otro puntero del tipo deseado (por supuesto, un tipo
de puntero) que siempre es posible y no causa ninguna pérdida
de precisión.
228 – By Gerson
necesita especificaciones precisas con respecto a la entidad que
se está creando; debe expresarse como una descripción de tipo
y si la entidad creada es una matriz, también se debe dar el
tamaño de la matriz (como en el primer ejemplo)
229 – By Gerson
Ahora le mostraremos un programa completo, aunque no muy útil,
que demuestra el uso de ambas palabras clave.
source_03_10_06.newdel.cpp
230 – By Gerson
3.10.7 Memoria bajo demanda (5)
231 – By Gerson
3.10.8 Memory on demand (6)
source_03_10_08_newbsort.cpp
232 – By Gerson
No hay nada que impida que los elementos de la matriz sean
punteros. Imagina que necesitamos una matriz dinámica. La
matriz es bidimensional y no podemos predecir cuántas filas
tendrá o cuántas columnas.
Solo sabemos que el número de columnas se almacena en
la variable cols y el número de filas en la variable de filas .
Ni siquiera vamos a intentar asignar la matriz de la siguiente
manera:
es posible?
233 – By Gerson
4.1.2 Arreglos de punteros (2)
Sí, es posible.
Así es como lo hacemos:
234 – By Gerson
Esto significa que el tipo de ptrarr es " un puntero a un puntero
a int ", que denotamos como " int ** ". Ahora podemos escribir
una declaración completa →
235 – By Gerson
4.1.7 Arreglos de punteros (7)
¿Como funciona?
* (* (ptrarr + r) + c)
236 – By Gerson
4.1.8 Triangular matrices (1)
La ventaja de este tipo de matrices es que, a diferencia de las
matrices comunes, cada fila puede tener una longitud
diferente . Esto es útil para los algoritmos que no necesitan una
matriz completa para ejecutarse, sino solo una porción de
ella. Se refiere específicamente a las llamadas matrices
triangulares .
Podemos asignar este tipo de matriz así →
source_04_01_09_triangle.cpp
237 – By Gerson
4.2.1 ¿Qué es una conversión?
238 – By Gerson
Puede evitar la conversión codificando el literal de una manera
más clara, por ejemplo, así:
El sufijo ' L ' (o ' l ' - son intercambiables) dice que el literal se
define explícitamente como largo .
239 – By Gerson
Como ya sabe, las conversiones implícitas pueden ocurrir sin
su entrada . El compilador decide dónde se deben realizar. Por
supuesto, debemos ser conscientes de esto, y debemos poder
encontrar todas las circunstancias que pueden hacer que el
compilador convierta nuestros datos.
Podemos decir que las conversiones implícitas afectan los datos
de los tipos fundamentales (básicos) y con mayor frecuencia se
asocian con un cambio de la representación interna .
Este tipo de conversión ocurre cuando asigna, por
ejemplo, int a float o float a long o double a int . Hay muchas
otras combinaciones posibles.
Hagamos una lista de algunos de los contextos donde las
conversiones implícitas juegan un papel importante (aunque casi
invisible):
240 – By Gerson
4.2.3 Conversiones explícitas
Conversiones explícitas: ¿cómo podemos iniciarlas?
En general, el lenguaje C ++ nos brinda dos formas de especificar
conversiones explícitas:
241 – By Gerson
una sintaxis de ese tipo); en este caso, especificamos la
conversión de la siguiente forma:
(new_type_name) expression_of_old_type
new_type_name (expression_of_old_type)
source_04_02_03_conv1.cpp
242 – By Gerson
4.2.4 Conversiones: ganancias y pérdidas (1)
243 – By Gerson
4.2.5 Conversiones: ganancias y pérdidas (2)
244 – By Gerson
4.2.6 Conversiones: ganancias y pérdidas (3)
source_04_02_07_conv5.cpp
246 – By Gerson
Intente compilar y ejecutar el programa de ejemplo usted
mismo. Los resultados te sorprenderán, te lo prometemos.
source_04_02_08_conv6.cpp
4.2.9 Promociones
247 – By Gerson
Formalmente, todas las promociones se llevan a cabo de acuerdo
con el siguiente conjunto de reglas (las reglas se aplican en el
siguiente orden hasta que todos los datos utilizados en una
expresión particular tengan el mismo tipo: ¡esta condición es muy
importante!):
los datos de tipo char o short int se convertirán a tipo int (esto
se llama una promoción de enteros );
249 – By Gerson
para qué podemos usarlo si tenemos un tipo de datos
como char . Buena pregunta.
Las variables char son útiles (y generalmente todo lo que
necesitamos) cuando queremos procesar caracteres individuales,
pero son extremadamente difíciles cuando tenemos que lidiar con
datos que contienen todo tipo de nombres (por ejemplo, apellidos,
nombres de ciudades, nombres de calles, etc.) o simplemente
texto (por ejemplo, acuerdos, declaraciones o simplemente libros
o correos electrónicos). Procesar ese tipo de datos como un
conjunto de caracteres se asemeja a la ortografía: es tedioso y
lento. Es mucho más fácil tratar a todos los personajes como un
todo, almacenados, asignados y procesados al mismo tiempo.
En nuestro nivel actual de conocimiento, podemos suponer que
string es un tipo como int o float . No es del todo cierto, pero
podemos descuidar todos los detalles aburridos y comenzar desde
este punto. A su debido tiempo, le mostraremos por qué la cadena
es algo diferente a un tipo de datos ordinario. También será una
buena oportunidad para mostrarle algunos rasgos interesantes de
la programación de objetos .
250 – By Gerson
4.3.2 Inicializando una cadena (1)
251 – By Gerson
si se invoca una función real llamada PetName . La respuesta es
sí y no". Sí, porque hay una función especializada responsable de
crear cadenas y la función se invoca cada vez que desea crear una
nueva cadena. No, porque no puedes invocar directamente la
función como cualquier otra función regular.
Ambas formas de inicialización son iguales y sus resultados son
exactamente los mismos.
source_04_03_05_concat.cpp
252 – By Gerson
4.3.6 Operadores de cadena: + (2)
253 – By Gerson
4.3.7 Operadores de cadena: + =
source_04_03_07_tobe.cpp
254 – By Gerson
4.3.8 Cadenas de entrada (1)
Ser o no ser
source_04_03_08_cincout.cpp
255 – By Gerson
4.3.9 Cadenas de entrada (2)
source_04_03_09_getline.cpp
256 – By Gerson
4.3.10 Comparación de cadenas (1)
source_04_03_10_passwd.cpp
257 – By Gerson
4.3.11 Comparación de cadenas (2)
source_04_03_11_compare.cpp
258 – By Gerson
4.3.12 Comparación de cadenas: el enfoque objetivo
función (datos);
object.member_function ();
secret.compare (contraseña)
contraseña.compare (secreto)
source_04_03_12_passwd2.cpp
source_04_03_13_compare2.cpp
4.4.1 Subcadenas
262 – By Gerson
Sí, es BEFABCDEF .
Y ahora preste atención, porque esto es muy importante: obtener
una subcadena requiere que sea preciso . No debe definir una
subcadena que no se ajuste totalmente dentro de la cadena
original (por ejemplo, comienza al lado del final de la cadena
original). Hacer esto hará que su instrucción sea rechazada, y es
lo que llamamos una excepción .
Discutiremos las excepciones en la siguiente sección: estad
atentos.
source_04_04_01_substr.cpp
263 – By Gerson
4.4.2 La longitud de una cuerda
Cada cuerda tiene una longitud. Incluso una cadena vacía (que no
contiene caracteres) tiene una longitud de cero. Es obvio que en
algún momento podemos querer saber cuánto dura una cadena
en particular.
Esta información es proporcionada por dos funciones de miembros
gemelos. Sus nombres son diferentes, pero sus comportamientos
son idénticos. Podemos decir que estas funciones
son sinónimos .
Sus prototipos informales se ven así:
int pos = 1;
cambiado a:
264 – By Gerson
int pos = 2;
source_04_04_02_substr2.cpp
265 – By Gerson
4.4.3 Comparación de cadenas más detallada
cadena S = "ABC";
cout << S.compare (1,1, "B");
cadena S = "ABC";
266 – By Gerson
cout << S.compare (1,1, "ABC", 1,1);
source_04_04_03_compare.cpp
267 – By Gerson
4.4.4 Encontrar cadenas dentro de cadenas
source_04_04_04_find.cpp
268 – By Gerson
269 – By Gerson
4.4.5 ¿Qué tan grande es realmente la cuerda?
Nota: este valor es común para todas las cadenas que usa en su
programa. Obviamente, el valor anterior puede ser diferente para
cada instancia de la cadena.
El programa de la derecha demuestra la coexistencia de estos tres
valores. Compílelo y ejecútelo usted mismo, y también cambie los
valores de la variable y pruebe su comportamiento.
No intente aumentar el límite superior del ciclo for en una cantidad
significativa. Puede bloquear su sistema. ¿Qué, no nos
crees? Pues bien, pruébalo!
source_04_04_05_length.cpp
271 – By Gerson
4.4.6 ¿Cómo podemos controlar el tamaño de la cadena?
source_04_04_06_capacity.cpp
273 – By Gerson
4.4.7 Cómo controlar el contenido de la cadena (1)
274 – By Gerson
El nombre de la función está vacío , no requiere parámetros y
devuelve un valor de tipo bool , determinando la verdad de la
siguiente oración: esta cadena está vacía ahora .
source_04_04_07_resize.cpp
275 – By Gerson
puede usar una máscara y mostrarse como una matriz ordinaria
(bueno, casi ordinaria). Nos permite leer y escribir cada
carácter por separado .
El programa de la derecha hace uso de esta valiosa propiedad de
cadena. Convierte todos sus caracteres en mayúsculas. Lo
sentimos: el algoritmo es demasiado simple para funcionar en
todas partes y siempre. No lo use para aplicaciones serias. Eso
definitivamente sería una mala idea. Una buena idea es explicar
cómo funciona realmente y de dónde proviene su debilidad. Le
instamos a que intente hacerlo usted mismo.
Hasta ahora, no hemos dicho una palabra sobre cómo es posible
que una cadena haga algo como esto. Bueno, se debe a un
mecanismo llamado "sobrecarga del operador". Le contaremos
más al respecto cuando lleguemos a construir nuestros propios
objetos. Una vez más, lo sentimos: en este momento, debe
limitarse a la función de usuario de ese mecanismo. Cambiaremos
esto pronto, lo prometemos.
source_04_04_08_index.cpp
276 – By Gerson
Al final de esta sección, le diremos con precisión qué aspectos de
las cadenas hemos omitido y por qué. Pero hasta entonces,
intenta adivinar.
277 – By Gerson
por ejemplo, creando una cadena de invocaciones
de anexos posteriores .
source_04_05_01_append.cpp
278 – By Gerson
source_04_05_02_pushback.cpp
a la pantalla.
source_04_05_03_append.cpp
280 – By Gerson
4.5.4 Asignación de una (sub) cadena o un carácter
source_04_05_04_assign.cpp
281 – By Gerson
4.5.5 Sustitución de una (sub) cadena
El código saldrá
a la pantalla.
source_04_05_05_replace.cpp
282 – By Gerson
4.5.6 Borrar una (sub) cadena
TheString.erase ();
source_04_05_06_erase.cpp
284 – By Gerson
4.5.7 Intercambiando el contenido de dos cadenas
AGlass = Glass1;
Glass1 = Glass2;
Glass2 = AGlass;
source_04_05_07_swap.cpp
¿Hay algún método para hacer que su nombre de pila sea más
explícito? Sí, por supuesto. Su nombre tiene que
ser calificado con otro nombre con la esperanza de que este
nuevo grupo verbal no sea ambiguo en el nuevo espacio más
amplio.
Probablemente ya hayas notado que ya tienes algo como esto. Es
tu apellido, ¿no?
Por supuesto, es muy posible que este tipo de calificación no
sea suficiente . Puede haber otra persona con el mismo nombre
de pila y apellidos que el suyo, incluso cuando no tiene ninguna
relación. Esto significa que se debe usar otro nivel de calificación
y, como probablemente ya sepa, diferentes culturas han creado
sus propias formas de manejar tales problemas, por ejemplo,
usando el nombre de uno de sus padres, o su lugar de nacimiento,
o su fecha de nacimiento, y así en.
288 – By Gerson
una sintaxis especial para este propósito. Se ve así (escrito de
manera muy informal):
home_name_space :: entity_name
source_04_06_03_error.cpp
¿Sabes qué es un troll? Pues claro que sí. Un troll es una criatura
muy desagradable conocida por todos. Los trolls llegan a nuestro
mundo desde muchos lugares diferentes, por ejemplo, desde las
mazmorras de Hogwarts o desde las profundidades oscuras de
Mordor, o incluso desde muchos foros de Internet donde realizan
sus actividades destructivas. Incluso nos han dado el verbo "troll".
¡Recuerde, no alimente a los trolls!
290 – By Gerson
Imagine que queremos usar trolls (dos, para ser precisos) en
nuestro software. Vamos a tomar uno de Hogwarts y uno de
Mordor. ¿Podemos cooperar con ellos simultáneamente sin correr
el riesgo de confundir uno con el otro?
Tenemos que crear dos espacios de nombres diferentes y vincular
a los trolls a sus orígenes. La definición de un espacio de nombres
se ve así:
source_04_06_05_trolls.cpp
291 – By Gerson
4.6.6 Usar un espacio de nombre (1)
292 – By Gerson
espacio de nombres ( puede haber más de un espacio de nombres
de este tipo).
El acto de usar un espacio de nombres seleccionado se lleva
a cabo mediante la instrucción de uso del espacio de nombres . Si
la declaración se coloca fuera de cualquier bloque (una parte de
un código encerrado entre { y } corchetes), afecta el código
después de la declaración hasta el final del archivo fuente.
source_04_06_06_trolls2.cpp
293 – By Gerson
4.6.7 Usar un espacio de nombre (2)
source_04_06_07_trolls3.cpp
294 – By Gerson
4.6.8 Expandir un espacio de nombres
source_04_06_08_trolls4.cpp
source_04_06_09_trolls5.cpp
source_04_06_10_trolls6.cpp
296 – By Gerson
Mira el ejemplo →
Muestra cómo un nombre largo y retorcido podría tener un alias
para facilitar un poco la vida del desarrollador.
Dejemos solo el espacio de nombre "C ++" por ahora. El mundo
real está esperando.
source_04_06_11_trolls7.cpp
298 – By Gerson
El enfoque del objeto sugiere una forma de pensar completamente
diferente. Los datos y el código están encerrados juntos en el
mismo mundo, divididos en clases. Cada clase es como una receta
que se puede usar cuando se desea crear un objeto útil (sí, de
aquí proviene el nombre del enfoque). Puede producir tantos
objetos como necesite para resolver su problema. Cada objeto
tiene un conjunto de rasgos (se llaman propiedades) y puede
realizar un conjunto de actividades (que se llaman métodos).
Las recetas pueden modificarse si son inadecuadas para fines
específicos y, en efecto, pueden crearse nuevas clases. Las nuevas
clases heredan propiedades y métodos de los originales y
generalmente agregan algunos nuevos, creando herramientas
nuevas y más específicas.
Los objetos son encarnaciones de ideas expresadas en clases, al
igual que un trozo de tarta de queso en su plato es una
encarnación de una idea expresada en la receta impresa en un
viejo libro de cocina. Los objetos interactúan entre sí,
intercambian datos o activan sus métodos. Una clase construida
correctamente (y, por lo tanto, los objetos) puede proteger los
datos sensibles y ocultarlos de modificaciones no autorizadas. No
existe un límite claro entre los datos y el código: viven como uno
solo en los objetos.
Queremos mostrarle que todos estos conceptos no son tan
abstractos como puede sospechar a primera vista. Por el
contrario, todos están tomados de experiencias de la vida real y,
por lo tanto, son realmente útiles en la programación de
computadoras: no crean una vida artificial: reflejan hechos,
relaciones y circunstancias reales.
299 – By Gerson
5.1.3 Clase: ¿qué es? (1)
vehículos terrestres
vehículos acuáticos
vehículos aéreos
vehículos espaciales
vehículos de ruedas
vehículos rastreados
aerodeslizador
301 – By Gerson
La jerarquía que hemos creado se ilustra en la figura de la derecha
→
Tenga en cuenta la dirección de las flechas: siempre apuntan a la
superclase. La clase de nivel superior es una excepción: no tiene
su propia superclase. No olvides esto.
302 – By Gerson
Podemos decir que todos los animales (nuestra clase de nivel
superior) se pueden dividir (por laicos como nosotros) en cinco
subclases:
mamíferos
reptiles
aves
pescado
anfibios
mamíferos salvajes
mamíferos domesticados
5.1.6 Herencia
304 – By Gerson
Ahora estamos listos para definir uno de los conceptos
fundamentales de la programación de objetos, llamado
"herencia". Cualquier objeto vinculado a un nivel específico de una
jerarquía de clases hereda todos los rasgos (así como los
requisitos y cualidades) definidos dentro de cualquiera de las
superclases. La clase de inicio del objeto puede definir nuevos
rasgos (así como requisitos y cualidades), que serán heredados
por cualquiera de sus subclases.
No debería tener ningún problema para hacer coincidir esta regla
con ejemplos específicos, ya sea que se aplique a animales o
vehículos.
305 – By Gerson
Aquí hay dos frases de muestra que son buenos ejemplos:
307 – By Gerson
5.2.1 Pila aka LIFO (1)
308 – By Gerson
5.2.2 Pila aka LIFO (2)
Primero, tenemos que decidir cómo almacenar los valores int que
llegarán a nuestra pila. Sugerimos usar el método más simple y
usar un vector para este trabajo. Suponemos (de forma algo
temeraria) que no habrá más de 100 valores en la pila al mismo
tiempo. También suponemos que el elemento en el índice 0 está
en la parte inferior de la pila.
La pila en sí ya está declarada a la derecha →
5.2.4 Empujar
309 – By Gerson
la función no devuelve nada (se explica por sí mismo,
¿verdad?)
5.2.5 Pop
310 – By Gerson
5.2.6 La pila en acción
311 – By Gerson
5.2.7 Pros y contras
SP = 100;
El funcionamiento de la pila estará completamente desorganizado.
hemos usado la pila int hasta ahora, pero es posible que desee
usar las pilas definidas para otros tipos: flotantes, cadenas o
incluso matrices y estructuras; ¿Qué pasará entonces?
312 – By Gerson
la capacidad de ocultar (proteger) los valores seleccionados
contra el acceso no autorizado se
denomina encapsulación ; no se puede acceder ni modificar
los valores encapsulados si desea utilizarlos exclusivamente
313 – By Gerson
5.2.9 Pila desde cero (2)
314 – By Gerson
Depende de usted cuál de los dos elige. Queremos mostrarles a
ambos y hemos decidido implementar la función pop dentro del
cuerpo de la clase, mientras que hemos implementado
la función push fuera de la clase.
Queremos invocar estas funciones para insertar y reventar
valores. Esto significa que ambos deben ser accesibles para el
usuario de cada clase (en contraste con las variables previamente
declaradas que están ocultas para los usuarios de una clase
ordinaria). Este tipo de componente se llama " público " y
tenemos que usar una palabra clave para enfatizar este hecho.
Las declaraciones en sí no deberían sorprenderte. Echa un vistazo
→
315 – By Gerson
Las funciones que implementan las actividades de la clase y se
ubican fuera del cuerpo de la clase deben describirse de una
manera muy específica. Sus nombres
deben calificarse utilizando el nombre de la clase de inicio y
el operador " :: ".
No debes olvidar eso. Si omite el prefijo de calificación, la función
no se considerará parte de la clase. Será una función ordinaria en
su lugar.
316 – By Gerson
5.2.12 Pila desde cero (5)
317 – By Gerson
5.2.13 Pila desde cero (6)
little_stack.SP ++;
source_05_02_13.stack2.cpp
Ahora vamos a hacer algo más. Queremos una nueva clase para
manejar las pilas. Queremos que la nueva clase pueda evaluar una
suma de todos los elementos almacenados actualmente en la
pila. Raro, verdad?
318 – By Gerson
No queremos modificar la pila previamente definida. Es lo
suficientemente bueno como es, y no queremos cambiarlo de
ninguna manera. Queremos una nueva pila con nuevas
capacidades .
En otras palabras, queremos construir una subclase de
la clase Stack .
El primer paso no será asombroso. Simplemente definiremos una
nueva subclase señalando la clase que se utilizará como
superclase.
Así es como se ve →
319 – By Gerson
Primero, agregamos una nueva variable a la clase. Será una
variable privada, como todas las variables anteriores. No
queremos que nadie manipule el valor de la suma .
En segundo lugar, agregamos dos funciones ... Detener, ¿es
realmente "agregar"? ¡Ya tenemos funciones en la
superclase! ¿Podemos hacer algo así?
Si podemos. Significa que vamos a cambiar la funcionalidad de las
funciones, no sus nombres. Podemos decir con mayor precisión
que la interfaz de la clase sigue siendo la misma cuando
cambiamos la implementación al mismo tiempo.
321 – By Gerson
5.2.19 Pila desde cero (12)
Tenga en cuenta la frase ": Pila ()". Es una solicitud para invocar
al constructor de la superclase antes de que el constructor
actual comience su trabajo.
Echemos un vistazo a un código completo de la nueva clase ahora.
Aquí está →
Podemos verificar su funcionamiento ahora. Lo haremos con la
ayuda de una función principal muy simple. Lo encontrará en la
próxima diapositiva.
322 – By Gerson
5.2.21 Pila desde cero (14)
45
0
source_05_02_21.stack3.cpp
323 – By Gerson
5.3.1 Componentes de clase
clase A {
Tipo Var;
324 – By Gerson
};
clase A {
privado:
Tipo Var;
};
325 – By Gerson
5.3.3 Crear un objeto
the_object.setVal (0);
the_object.value = 0;
326 – By Gerson
valor = valor;
su nombre es este
327 – By Gerson
La regla general dice que:
329 – By Gerson
5.3.8 Constructores
Objeto de clase ;
330 – By Gerson
invoca implícitamente al constructor . Puede asegurarse de
que el constructor haga su trabajo empleando las siguientes
instrucciones:
object.Class ()
o esto
331 – By Gerson
5.3.9 Sobrecarga de nombres de constructor (1)
-1
100
333 – By Gerson
Si una clase tiene un constructor (o más precisamente, al menos
un constructor), se debe elegir uno de ellos durante la creación
del objeto, es decir, no se le permite escribir una declaración que
no especifique un constructor de destino.
La clase de la derecha tiene un constructor de un parámetro. Esto
significa que la única forma permitida de creación de objetos de
esa clase debe ser similar a la siguiente:
La siguiente forma
Objeto de clase;
No se permite. No lo hagas
334 – By Gerson
Hay un tipo especial de constructor destinado a copiar un objeto
en otro . Los constructores de este tipo tienen un parámetro
referenciado a un objeto de la misma clase y se usan para copiar
todos los datos importantes del objeto fuente al objeto recién
creado (o más precisamente, al objeto que se está creando
actualmente ).
Se los conoce como constructores de copia y se invocan
implícitamente cuando un iniciador sigue una declaración de un
objeto. También se puede invocar si la declaración especifica un
constructor adecuado para la declaración.
source_5_03_11_copying.cpp
335 – By Gerson
5.3.12 Pérdidas de memoria
336 – By Gerson
Podemos esperar que un retorno de las funciones MakeALeak
() provoque la siguiente acción:
5.3.13 Destructores
337 – By Gerson
Podemos protegernos de este peligro definiendo una función
especial llamada destructor . Los destructores tienen las
siguientes restricciones:
source_5_03_13_memleak.cpp
La palabra clave " auto " vino del antepasado de "C ++", el
lenguaje de programación "C". La palabra ha conservado su
significado original, pero "C ++" le ha agregado un nuevo
338 – By Gerson
sabor. Comencemos con las características originales de la palabra
y el efecto que la palabra tiene en su programa.
Todas las variables en su código pertenecen a una de dos
categorías. Son:
var = 100
var = 100
var = 100
339 – By Gerson
var = 100
var = 100
source_05_04_01_auto.cpp
var = 100
var = 101
var = 102
var = 103
var = 104
source_05_04_02_static.cpp
340 – By Gerson
Anteriormente hemos dicho que definir la clase en sí no tiene
efectos directos. La clase es como un muñeco cobrado vida cuando
se crea su encarnación (en este caso, su objeto).
Cada objeto creado a partir de una clase particular se
denomina instancia de una clase . Desde este punto de vista,
cada instancia de la clase es un universo separado y no tiene
nada que ver con ninguna de las instancias restantes.
Todos los componentes del objeto (campos y funciones) están
encerrados dentro de la instancia. Podemos decir (aunque esto no
es estrictamente cierto a nivel de código de máquina) que cada
instancia de una clase es un espécimen separado de las especies
definidas por la clase.
También podemos decir que ninguno de estos componentes
realmente existe hasta que se crea la primera instancia. En
consecuencia, no debemos usar ninguno de los componentes de
la clase hasta que hayamos creado un objeto de esa clase.
341 – By Gerson
5.4.3 Instancias de la clase
342 – By Gerson
Podemos decir que todas las instancias comparten los mismos
componentes estáticos.
El programa de la derecha introduce una clase con dos campos del
mismo tipo: uno estático y otro no estático (tenga en cuenta que
no podemos usar el término "auto" en este caso, ya que "C ++"
crea un contexto completamente diferente) .
Estático = 1, no estático = 10
Estático = 2, no estático = 20
source_05_04_04_static2.cpp
343 – By Gerson
5.4.5 Variables de clase estática (1)
344 – By Gerson
2 instancias hasta ahora
4 instancias
¡Adiós!
source_05_04_05_counter.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
static int Counter ;
Clase ( nula ) { ++ Contador; } ;
~ Clase ( nula ) {
--Contador ;
if ( Contador == 0 ) cout << "¡Adiós, adiós!" << endl ;
};
void HowMany ( void ) { cout << Contador << "instancias" << endl ;}
};
int Clase :: Contador = 0 ;
int main ( void ) {
Clase a ;
Clase b ;
cout << Class :: Counter << "instancias hasta ahora" << endl ;
Clase c ;
Clase d ;
re. HowMany () ;
devuelve 0 ;
345 – By Gerson
}
Clase :: Contador = 1;
346 – By Gerson
5.4.7 Variables de clase estática (3)
Cuántos();
b.HowMany ();
0 instancias
2 instancias
4 instancias
¡Adiós!
source_05_04_07_counter3.cpp
348 – By Gerson
4. un no estático componente accede a un no
estático componente
349 – By Gerson
El primer programa de prueba (que se muestra aquí →) muestra
un caso en el que una función estática llamada funS2 intenta
invocar otra función estática llamada funS1 .
Un caso como este siempre es posible , ya que ambas funciones
están disponibles durante toda la vida del programa. Se puede
acceder con éxito desde dentro de un objeto y desde dentro de la
clase.
Este programa puede compilarse con éxito y produce el siguiente
resultado:
estático
estático
source_05_04_09_static_static.cpp
350 – By Gerson
5.4.11 Interacción estática → no estática
source_05_04_11_static_nonstatic.cpp
351 – By Gerson
5.4.13 Interacción no estática → estática
estático
source_05_04_13_nonstatic_static.cpp
352 – By Gerson
5.4.15 Componentes estáticos versus no estáticos
353 – By Gerson
Los objetos también pueden existir como entidades
dinámicamente creadas y destruidas. En otras palabras,
los objetos pueden aparecer a pedido , cuando se necesitan,
y desaparecer de la misma manera.
Comencemos con el siguiente programa simple →
Hemos definido una clase (o más bien un esqueleto para una clase
futura) y la llamamos Clase . La clase no tiene campos ni
funciones miembro. Solo hay un constructor y un destructor
dentro de esta clase. Ambos no hacen nada; su única actividad es
anunciar que han sido invocados.
La función principal declara la variable ptr , que es un puntero a
los objetos de la clase Class . A continuación, hemos creado un
objeto de esa clase utilizando la nueva palabra clave. Tenga en
cuenta que podemos omitir los paréntesis vacíos después
del nombre de la Clase ; en cualquier caso, se activará el
constructor sin parámetros.
Objeto construido!
Objeto destruido!
source_05_05_01_dynaobj.cpp
5.5.2 Punteros a campos
Objeto construido!
1
Objeto destruido!
source_05_05_02_dynaobj2.cpp
355 – By Gerson
5.5.3. Punteros a funciones
Objeto construido!
valor = 2
Objeto destruido!
source_05_05_03_dynaobj3.cpp
356 – By Gerson
Objeto construido (# 1)
Objeto construido (# 2)
valor = 2
valor = 3
Objeto destruido! val = 3
Objeto destruido! val = 2
source_05_05_04_dynaobj4.cpp
source_05_05_05_arr.cpp
source_05_05_06_arr2.cpp
358 – By Gerson
Un objeto de cualquier clase puede ser el campo de un
objeto de cualquier otra clase . Todas las reglas relativas al
acceso a los componentes de la clase también se cumplen en este
caso.
Hemos preparado un ejemplo simple para ilustrar el problema:
puede encontrarlo a la derecha →
Hay una clase muy simple llamada Element . Está destinado a
almacenar un valor int . Míralo, es muy simple, ¿no?
La segunda clase que se muestra en el ejemplo también es simple,
pero hay algo interesante al respecto: hay dos campos de
la clase Elemento .
Como puede ver, podemos manipularlos sin gran dificultad. Se
comportan como cualquier otro componente de clase.
Elemento # 1 = 2
Elemento # 2 = 3
source_05_05_07_objinside.cpp
359 – By Gerson
Aquí va el código modificado → Hemos limpiado la función
principal de todo lo que realmente no es necesario para rastrear
la actividad de los constructores.
Compilamos y ejecutamos el programa. Esto es lo que vemos en
la pantalla:
Elemento construido!
Elemento construido!
Colección construida!
360 – By Gerson
El constructor invocado implícitamente (a veces llamado
el constructor predeterminado ) es el que no tiene
parámetros. No hemos entregado tal constructor. Tampoco
hemos entregado el constructor de copia. El único constructor
disponible no es compatible ni con el predeterminado ni con el
constructor de copia, y esto hace que nuestro programa sea
incorrecto.
¿Cómo podemos lidiar con esto? ¿Hay algún truco para decirle al
compilador que queremos que use el otro constructor en lugar del
predeterminado?
Sí hay. El lenguaje "C ++" nos ofrece una sintaxis especial para
esta y otras situaciones similares.
source_05_05_09_objinside3.cpp
361 – By Gerson
El programa se puede compilar correctamente y cuando se ejecuta
produce el siguiente resultado:
clase X {
público:
X (int x) {};
};
clase Y {
X x;
público:
Y(int x);
};
Y::Y(int x) : x(1) { };
source_05_05_10_objinside4.cpp
6.1.1 Definición de una subclase simple (1)
362 – By Gerson
Podemos usar cada clase como base (o base) para definir o
construir otra clase ( una subclase ). También es posible
usar más de una clase para definir una subclase . Puede ver
ambos casos a la derecha →
Tenga en cuenta que las flechas siempre apuntan a la (s)
superclase (s) .
363 – By Gerson
6.1.2 Definición de una subclase simple (2)
101
source_06_01_02_inher.cpp
clase A: X, Y, Z {...};
364 – By Gerson
6.1.4 Definición de una subclase simple (4)
365 – By Gerson
clase Sub: Super {
};
int main (nulo) {
Subobjeto;
object.put (100);
object.put (object.get () + 1);
cout << object.get () << endl;
devuelve 0;
}
Los objetos de la clase Sub pueden hacer casi las mismas cosas
que sus hermanos mayores creados a partir de
la clase Super . Usamos la palabra 'casi' porque ser una subclase
también significa que la clase ha perdido el acceso a los
componentes privados de la superclase . No podemos escribir
una función miembro de la clase Sub que pueda manipular
directamente la variable de almacenamiento .
Esta es una restricción muy seria. ¿Hay algún trabajo alrededor?
Si.
366 – By Gerson
La palabra clave protegida significa que cualquier componente
marcado con él se comporta como un componente público
cuando lo utiliza cualquiera de las subclases y se ve como
un componente privado para el resto del mundo .
Deberíamos agregar que esto es cierto solo para las clases
heredadas públicamente (como la clase Super en nuestro ejemplo
aquí →)
Hagamos uso de la palabra clave ahora mismo.
source_06_01_05_inher2.cpp
#include <iostream>
clase Super {
privado :
almacenamiento int ;
public :
void put ( int val ) { almacenamiento = val ; }
int get ( void ) { devolver almacenamiento ; }
};
367 – By Gerson
cout << objeto. get () << endl;
devuelve 0 ;
}
object.storage = 0;
almacenamiento = 101
source_06_01_06_inher3.cpp
#include <iostream>
368 – By Gerson
clase Super {
protegido :
almacenamiento int ;
public :
void put ( int val ) { almacenamiento = val ; }
int get ( void ) { devolver almacenamiento ; }
};
público
privado
369 – By Gerson
protegido
370 – By Gerson
6.1.8 Definición de una subclase simple (8)
almacenamiento = 3
seguro = 5
source_06_01_08_multiinher
371 – By Gerson
6.2.1 Compatibilidad de tipos: el caso más simple
a_dog = a_cat;
a_cat = a_dog;
372 – By Gerson
¡Maullar! ¡Maullar!
¡Guau! ¡Guau!
source_06_02_01_compat.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Cat {
public :
void MakeSound ( void ) { cout << "¡Miau! ¡Miau!" << endl
};
class Dog {
public :
void MakeSound ( void ) { cout << "¡Guau! ¡Guau!" << endl
};
int main ( void ) {
Cat * a_cat = ne w Cat () ;
Perro * a_dog = ne w Perro () ;
a_cat -> MakeSound () ;
a_dog -> MakeSound () ;
devuelve 0 ;
}
Y entonces:
375 – By Gerson
Tom: estoy corriendo
Tom: Miau! ¡Maullar!
source_06_02_02_compat2.cpp
#include <iostream>
#include <cadena>
usando el espacio de nombres estándar ;
clase Pet {
protegida :
cadena Nombre ;
public :
Pet ( string n ) { Name = n ; }
void Run ( void ) { cout << Nombre << ": estoy corriendo" << endl ; }
};
clase Perro : mascota pública {
público :
perro ( cadena n ) : mascota ( n ) {};
vacío MakeSound ( vacío ) { cout << Nombre << ": ¡Guau! ¡Guau!" << endl ; }
};
clase Cat : public Pet {
public :
Cat ( string n ) : Pet ( n ) {} ;
vacío MakeSound ( vacío ) { cout << Nombre << ": ¡Miau! ¡Miau!" << endl ; }
};
int main ( nulo ) {
Pet a_pet ( "mascota" ) ;
Cat a_cat ( "Tom" ) ;
376 – By Gerson
Perro a_dog ( "Spike" ) ;
una mascota. Ejecutar () ;
un perro. Ejecutar () ; un perro. MakeSound () ;
un gato. Ejecutar () ; un gato. MakeSound () ;
devuelve 0 ;
}
source_06_02_03_compat3.cpp
#include <iostream>
#include <cadena>
usando el espacio de nombres estándar ;
clase Pet {
protegida :
377 – By Gerson
cadena Nombre ;
public :
Pet ( string n ) { Name = n ; }
void Run ( void ) { cout << Nombre << ": estoy corriendo" << endl ; }
};
class Perro : public Pet {
public :
Dog ( string n ) : Pet ( n) {} ;
vacío MakeSound ( vacío ) { cout << Nombre << ": ¡Guau! ¡Guau!" << endl ; }
};
clase Cat : public Pet {
public :
Cat ( string n ) : Pet ( n ) {} ;
vacío MakeSound ( vacío ) { cout << Nombre << ": ¡Miau! ¡Miau!" << endl ; }
};
int main ( void ) {
Pet * a_pet1 = new Cat ("Tom") ;
Pet * a_pet2 = nuevo perro ("Spike") ;
devuelve 0 ;
}
378 – By Gerson
6.2.4 Compatibilidad de tipos: cómo recuperar lo perdido
El resultado se ve así:
source_06_02_05_compat4.cpp
380 – By Gerson
6.2.6 Compatibilidad de tipos: abuso del poder del
propietario
381 – By Gerson
especialmente para este caso. Su nombre es algo
sugerente: dynamic_cast .
El nombre dice que la conversión se lleva a cabo dinámicamente
con respecto al estado actual de todos los objetos creados. Esto
significa que la conversión puede (o no) ser exitosa, haciendo que
nuestro programa se detenga si quiere que un perro
maulle. Volveremos a este problema pronto.
source_06_02_06_compat5.cpp
382 – By Gerson
El programa emite el siguiente texto:
source_06_02_07_compat6.cpp
source_06_03_01_override.cpp
384 – By Gerson
6.3.2 Reemplazar un método en la subclase (2)
source_06_03_02_override2.cpp
386 – By Gerson
Queremos pedirle ahora toda su atención, ya que vamos a
presentar una de las nociones objetivas más importantes:
el polimorfismo . Este es un método para redefinir el
comportamiento de una superclase (¡pero solo el que acepta
explícitamente ser tratado de esta manera!) Sin tocar su
implementación .
No vaya más allá hasta que esté familiarizado con los dos últimos
ejemplos del código. También lo alentamos a que haga algunos
experimentos por su cuenta, para que realmente pueda
familiarizarse con él.
source_06_03_03_poly.cpp
388 – By Gerson
Invocamos el método MakeSound como parte
del constructor Pet . Ya sabemos que el método
se reemplaza polimórficamente por las nuevas
implementaciones presentadas por
las subclases Cat y Dog . Todavía no sabemos cuándo ocurre el
reemplazo.
El programa generará las siguientes líneas:
source_06_03_04_poly2.cpp
6.3.5 Reemplazar un método en la subclase (5)
389 – By Gerson
Kitty the Cat dice: ¡Miau! ¡Maullar!
Doggie the Dog dice: ¡Guau! ¡Guau!
source_06_03_05_poly3.cpp
6.4.1 Pasar un objeto como parámetro de función
source_06_04_01_param.cpp
¿Se pueden pasar los objetos por valor como valores ordinarios
de tipos integrados básicos como int o float ?
Sí, por supuesto, pero debe tener en cuenta que cualquier
modificación realizada a estos parámetros no abandonará la
función: los efectos de cualquier operación que afecte al objeto
ocurrirán en la copia del objeto, no en el objeto en sí.
El ejemplo aquí → ilustra las tres variantes posibles para hacer uso
de un objeto dentro de una función. El nombre de la función
individual muestra la forma en que la función recibió su
parámetro. Las tres funciones intentan nombrar su parámetro (es
decir, invocar su método llamado NameMe ).
Inmediatamente después de que se completa la invocación
de la función , se activa el método MakeSound para verificar si el
nombramiento ha sido exitoso y si puede observarse fuera de la
función.
El programa produce el siguiente resultado:
Esto significa que nombrar un objeto " Alfa " ha afectado una copia
del objeto mascota , no el objeto en sí.
También hay otro inconveniente grave que aparece cuando pasa
por valor un objeto de una subclase de una clase especificada
como un tipo de parámetro. Puede provocar la "desaparición" de
parte del objeto. Entonces, pasar un objeto por valor
391 – By Gerson
generalmente no es una buena idea. Volveremos a este problema
pronto, mostrándole un aspecto diferente del problema.
source_06_04_02_param2.cpp
392 – By Gerson
Podemos ilustrar su estructura usando el siguiente diagrama:
393 – By Gerson
No, no lo estamos.
source_06_04_03_param3.cpp
source_06_04_04_param4.cpp
#include <iostream>
#include <cadena>
usando el espacio de nombres estándar ;
clase Pet {
394 – By Gerson
protegido : nombre de cadena ;
public : Pet ( string name ) { this -> name = name ; }
void MakeSound ( void ) { cout << nombre << "es silencioso :(" << endl ; }
};
clase Perro : público Mascota {
público : Perro ( nombre de cadena ) : Mascota ( nombre ) {}
void MakeSound ( vacío ) { cout << nombre << "dice: ¡Guau!" << endl ; }
};
clase GermanShepherd : public Dog {
public : GermanShepherd ( string name ) : Dog ( name ) {}
void MakeSound ( nulo ) { cout << nombre << "dice: ¡Wuff!" << endl ; }
};
clase MastinEspanol : public Dog {
public : MastinEspanol ( string name ) : Dog ( name ) {}
void MakeSound ( void ) { cout << name << "dice: Guau!" << endl ; }
};
nulo PlayWithPet ( Pet * pet ) {
mascota -> MakeSound () ;
}
int main ( void ) {
Pet * pet = new Pet ( "criatura" ) ;
Perro * perro = Perro nuevo ( "Perro" ) ;
GermanShepherd * gs = new GermanShepherd ( "Hund" ) ;
MastinEspanol * mes = nuevo MastinEspanol ( "Perro" ) ;
PlayWithPet ( mascota ) ;
PlayWithPet ( perro ) ;
PlayWithPet ( gs ) ;
PlayWithPet ( mes ) ;
395 – By Gerson
devuelve 0 ;
}
<cadena>
397 – By Gerson
Perro says: Guau!
Perro runs (mes)!
source_06_04_05_param5.cpp
#include <iostream>
#include <cadena>
usando el espacio de nombres estándar ;
clase Pet {
protegido : nombre de cadena ;
public : Pet ( string name ) : name ( name ) {}
virtual void MakeSound ( void ) { cout << name << "is silent :(" << endl ; }
};
class Dog : public Pet {
public : Dog ( nombre de cadena ) : Pet ( nombre ) {}
void MakeSound ( void ) { cout << name << "dice: ¡Guau!" << endl ; }
};
clase GermanShepherd : public Dog {
public : GermanShepherd ( string name ) : Dog ( name ) {}
void MakeSound ( void ) { cout << name << "dice: Wuff!" << endl ; }
vacío Laufen( nulo ) { cout << nombre << "ejecuta (gs)!" << endl ; }
};
clase MastinEspanol : public Dog {
398 – By Gerson
public : MastinEspanol ( string name ) : Dog ( name ) {}
void MakeSound ( void ) { cout << name << "dice: Guau!" << endl ; }
vacío Ejecutar ( vacío ) { cout << nombre << "<< endl ; }
};
nulo PlayWithPet ( Pet * pet ) {
GermanShepherd * gs ;
MastinEspanol * mes ;
mascota -> MakeSound () ;
if ( gs = dynamic_cast <GermanShepherd *> ( pet ))
gs -> Laufen () ;
if ( mes = dynamic_cast <MastinEspanol *> ( mascota ))
mes -> Ejecutar () ;
}
int main ( nulo ) {
Pet * pet =nueva mascota ( "criatura" ) ;
Perro * perro = Perro nuevo ( "Perro" ) ;
GermanShepherd * gs = new GermanShepherd ( "Hund" ) ;
MastinEspanol * mes = nuevo MastinEspanol ( "Perro" ) ;
PlayWithPet ( mascota ) ;
PlayWithPet ( perro ) ;
PlayWithPet ( gs ) ;
PlayWithPet ( mes ) ;
regreso0 ;
}
399 – By Gerson
El operador dynamic_cast aplicado a una referencia
400 – By Gerson
la criatura está en silencio :(
terminar llamado después de lanzar una instancia de 'std :: bad_cast'
what (): std :: bad_cast
source_06_04_06_param6.cpp
401 – By Gerson
#include <iostream>
#include <cadena>
usando el espacio de nombres estándar ;
clase Pet {
protegido : nombre de cadena ;
public : Pet ( string name ) : name ( name ) {}
virtual void MakeSound ( void ) { cout << name << "is silent :(" <<
};
clase Perro: público Mascota {
público : Perro ( nombre de cadena ) : Mascota ( nombre ) {}
void MakeSound ( vacío ) { cout << nombre << "dice: ¡Guau!" << en
};
clase GermanShepherd : public Dog {
public : GermanShepherd ( string name ) : Dog ( name ) {}
void MakeSound ( void ) { cout << name << "dice: Wuff!" << endl ;
void Laufen ( void ) { cout << nombre << "ejecuta (gs)!" << endl ; }
};
clase MastinEspanol : public Dog {
public : MastinEspanol ( string name ) : Dog ( name ) {}
void MakeSound ( void ) { cout << name << "dice: Guau!" << endl ;
Void Ejecutar ( void ) { cout << << nombre de "carreras (MES)!" <<
};
nulo PlayWithPet ( Pet & pet ) {
402 – By Gerson
pet. MakeSound () ;
Dynamic_cast <GermanShepherd &> ( mascota ) . Laufen () ;
dynamic_cast <MastinEspanol &> ( mascota ) . Ejecutar () ;
}
int main ( void ) {
Pet pet ( "criatura" ) ;
Perro perro ( "Perro" ) ;
GermanShepherd gs ( "Hund" );
MastinEspanol mes ( "Perro" ) ;
PlayWithPet ( mascota ) ;
PlayWithPet ( perro ) ;
PlayWithPet ( gs ) ;
PlayWithPet ( mes ) ;
devuelve 0 ;
}
tratar {
403 – By Gerson
thing_we_want_to_try_although_we_are_not_quite_sure_if_it_is_reason
able;
} captura(…) {}
source_06_04_07_param7.cpp
#include <iostream>
#include <cadena>
usando el espacio de nombres estándar ;
clase Pet {
protegido : nombre de cadena ;
public : Pet ( string name ) : name ( name ) {}
virtual void MakeSound ( void ) { cout << name << "is silent :(" << endl ; }
404 – By Gerson
};
clase Perro : público Mascota {
público : Perro ( nombre de cadena ) : Mascota ( nombre ) {}
void MakeSound ( vacío ) { cout << nombre << "dice: ¡Guau!" << endl ; }
};
clase GermanShepherd : public Dog {
public : GermanShepherd ( string name ) : Dog ( name ) {}
void MakeSound ( nulo ) { cout << nombre << "dice: ¡Wuff!" << endl ; }
void Laufen ( void ) { cout << nombre << "ejecuta (gs)!" << endl ; }
};
clase MastinEspanol : public Dog {
public : MastinEspanol ( string name ) : Dog ( name ) {}
void MakeSound ( void ) { cout << name << "dice: Guau!" << endl ; }
Void Ejecutar ( void ) { cout << << nombre de "carreras (MES)!" << endl ; }
};
nulo PlayWithPet ( Pet & pet ) {
mascota. MakeSound () ;
pruebe {
dynamic_cast <GermanShepherd &> ( mascota ) . Laufen () ;
} catch ( ... ) {}
try {
dynamic_cast <MastinEspanol &> ( pet ) . Ejecutar () ;
} captura ( ... ) {}
}
int main ( void ) {
Pet pet ( "criatura" ) ;
Perro perro ( "Perro" ) ;
GermanShepherd gs ( "Hund" ) ;
MastinEspanol mes ( "Perro" ) ;
PlayWithPet ( mascota ) ;
PlayWithPet ( perro ) ;
405 – By Gerson
PlayWithPet ( gs ) ;
PlayWithPet ( mes ) ;
devuelve 0 ;
}
A (A y)
406 – By Gerson
el operador = en la notación de asignación clásica y usando
la notación funcional .
Los objetos o2 y o3 se crearán como copias gemelas de los
objetos o1 y o2 respectivamente, pero debemos enfatizar que
estos tres objetos no tienen nada en común .
En particular, cada uno de ellos tiene su propio campo
de datos . Los tres objetos viven sus propias vidas, separados de
sus hermanos. Como puede predecir, el incremento aplicado
al objeto o1 no afecta ni al objeto o2 ni al objeto o3 . En efecto, el
código producirá el siguiente resultado:
124
123
123
source_06_05_01_cc.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
datos int ;
pública :
Clase ( int valor ) : los datos ( valor ) {}
vacío de la subasta ( void ) { datos ++ ; }
valor int ( void ) { datos de retorno ; }
};
int main ( void ) {
Clase o1 ( 123 ) ;
Clase o2 = o1 ;
Clase o3 ( o2 ) ;
407 – By Gerson
o1. incremento () ;
cout << o1. valor () << endl ;
cout << o2. valor () << endl ;
cout << o3. valor () << endl ;
devuelve 0 ;
}
124
124
124
source_06_05_02_ccptr.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Class {
int * data ;
public :
Class ( int value ) {
data = new int ;
* datos = valor ;
}
incremento nulo ( nulo ) {( * datos ) ++ ; }
valor int ( void ) { retorno * datos ; }
};
int main ( void ) {
Clase o1 ( 123 ) ;
Clase o2 = o1 ;
409 – By Gerson
Clase o3 ( o2 ) ;
o1. incremento () ;
cout << o1. valor () << endl ;
cout << o2. valor () << endl ;
cout << o3. valor () << endl ;
devuelve 0 ;
}
124
123
123
410 – By Gerson
source_06_05_03_ccptr2.cpp
incluir <iostream>
usando el espacio de nombres estándar ;
clase Class {
int * data ;
public :
Class ( int value ) {
data = new int ;
* datos = valor ;
}
incremento nulo ( nulo ) {( * datos ) ++ ; }
valor int ( void ) { retorno * datos ; }
};
124
123
123
source_06_05_04_excc.cpp
#include <iostream>
usando el espacio de nombres estándar ;
412 – By Gerson
clase Class {
int * data ;
public :
Class ( int value ) {
data = new int ;
* datos = valor ;
}
Clase ( Clase y fuente ) {
data = new int ;
* datos = fuente. valor () ;
}
incremento nulo ( nulo ) {( * datos ) ++ ; }
valor int (nulo ) { retorno * datos ; }
};
int main ( void ) {
Clase o1 ( 123 ) ;
Clase o2 = o1 ;
Clase o3 ( o2 ) ;
o1. incremento () ;
cout << o1. valor () << endl ;
cout << o2. valor () << endl ;
cout << o3. valor () << endl ;
devuelve 0 ;
}
413 – By Gerson
6.5.5 Más sobre copiar constructores (5)
source_06_05_05_ccbyvalue.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Dummy {
public :
414 – By Gerson
Dummy ( int value ) {}
Dummy ( Dummy & source ) {
cout << "¡Hola del constructor de copias!" << endl ;
}
};
anular DoSomething ( Dummy ob ) {
cout << "Estoy aquí!" << endl ;
}
int main ( void ) {
Dummy o1 ( 123 ) ;
DoSomething ( o1 ) ;
devuelve 0 ;
}
6.5.6 Más información sobre la copia de constructores (6)
source_06_05_06_nocc.cpp
#include <iostream>
415 – By Gerson
usando el espacio de nombres estándar ;
clase Dummy {
private :
Dummy ( Dummy & source ) {}
public :
Dummy ( int value ) {}
};
anular DoSomething ( Dummy ob ) {
cout << "Estoy aquí!" << endl ;
}
int main ( void ) {
Dummy o1 ( 123 ) ;
Maniquí o2 = o1 ;
DoSomething ( o1 ) ;
devuelve 0 ;
}
i = 2147344384, f = 1.54143e-044
i = 5641768, f = 7.89812e-039
source_06_05_07_nocons.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase NoConstructorsAtAll {
public :
int i ;
flotador f ;
Pantalla vacía ( vacío ) { cout << "i =" << i << ", f =" << f << e
};
int main ( void ) {
NoConstructorsAtAll o1 ;
NoConstructorsAtAll * o2 ;
o2 = nuevo NoConstructorsAtAll ;
o1. Mostrar () ;
o2 -> Pantalla () ;
devuelve 0 ;
417 – By Gerson
}
418 – By Gerson
source_06_05_08_withcons.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase WithConstructor {
public :
int i ;
flotador f ;
WithConstructor ( int a, float b ) : i ( a ) , f ( b ) {}
void Display ( void ) { cout << "i =" << i << ", f =" << f << endl ; }
};
int main ( void ) {
WithConstructor o1 ;
Con Constructor * o2 ;
o2 = nuevo WithConstructor ;
o1. Mostrar () ;
o2 -> Pantalla () ;
devuelve 0 ;
}
419 – By Gerson
Con Constructor ()
i = 0, f = 0
i = 0, f = 0
source_06_05_09_withcons2.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase WithConstructor {
public :
int i ;
flotador f ;
WithConstructor ( int a = 0 , float b = 0 ) : i ( a ) , f ( b ) {}
void Display ( void ) { cout << "i =" << i << ", f =" << f << endl ; }
420 – By Gerson
};
int main ( void ) {
WithConstructor o1 ;
Con Constructor * o2 ;
o2 = nuevo WithConstructor ;
o1. Mostrar () ;
o2 -> Pantalla () ;
devuelve 0 ;
}
source_06_05_10_compo.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase A {
public :
void Do ( void ) { cout << "A está haciendo algo" << endl ; }
};
clase B {
public :
void Do ( void ) { cout << "B está haciendo algo" << endl ; }
};
clase Compo {
público :
A f1 ;
B f2 ;
};
int main ( void ) {
422 – By Gerson
Compo co ;
co. f1 . Do () ;
co. f2 . Do () ;
devuelve 0 ;
}
copiando A ...
copiando B ...
A está haciendo algo
B está haciendo algo
source_06_05_11_compo2.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase A {
public :
A ( A & src ) { cout << "copiando A ..." << endl ; }
A ( vacío ) {}
vacío Hacer ( vacío ) { cout << "A está haciendo algo" << endl ; }
};
clase B {
público :
B ( B & src ) { cout << "copiando B ..." << endl ; }
B ( vacío ) {}
vacío Do ( vacío ) { cout << "B está haciendo algo" << endl ; }
};
clase Compo {
public :
Compo ( void ) {} ;
A f1 ;
B f2 ;
};
424 – By Gerson
int main ( void ) {
Compo co1 ;
Compo co2 = co1 ;
co2. f1 . Do () ;
co2. f2 . Do () ;
devuelve 0 ;
}
Compo (Compo & src): f1 (src.f1), f2 (src.f2) {cout << "Copiando Compo
..." << endl; }
en lugar de
425 – By Gerson
Compo (Compo & src) {cout << "Copiando Compo ..." << endl; }
copiando A ...
copiando B ...
Copiando Compo ...
A está haciendo algo
B está haciendo algo
source_06_05_12_compo3.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase A {
public :
A ( A & src ) { cout << "copiando A ..." << endl ; }
A ( vacío ) {}
vacío Hacer ( vacío ) { cout << "A está haciendo algo" << en
};
clase B {
public :
B ( B & src ) { cout << "copiando B ..." << endl ; }
B ( vacío ) {}
426 – By Gerson
vacío Do ( vacío ) { cout << "B está haciendo algo" << endl ;
};
class Compo {
public :
Compo ( Compo & src ) { cout << "Copiando Compo ..." << e
Compo ( nulo ) {} ;
A f1 ;
B f2 ;
};
int main ( void ) {
Compo co1 ;
Compo co2 = co1 ;
co2. f1 . Do () ;
co2. f2 . Do () ;
volver 0;
}
tamaño1 ++;
tamaño2 = tamaño1;
428 – By Gerson
Este fragmento será inválido si elimina la
palabra const ( algunos compiladores permiten la compilación
de este ejemplo , porque
tienen implementada una extensión especial ) .
- puntos [2];
data.key = 0;
429 – By Gerson
Además, al contrario de los ejemplos anteriores, no puede tratar
estos símbolos como literales. Algunos de los compiladores "C ++"
pueden considerar la siguiente línea como incorrecta:
--iptr;
++ cptr;
* iptr = 0;
* cptr = 'T';
430 – By Gerson
int arr [ 5 ] = { 1 , 2 , 4 , 8 , 16 } ;
int * const iptr = arr + 2 ;
char * const cptr = "¿Por qué?" ;
--iptr;
++ cptr;
* iptr = 0;
* cptr = 'T';
431 – By Gerson
int arr [ 5 ] = { 1 , 2 , 4 , 8 , 16 } ;
const int * iptr = arr + 2 ;
const char * cptr = "¿Por qué?" ;
--iptr;
++ cptr;
* iptr = 0;
* cptr = 'T';
int arr [ 5 ] = { 1 , 2 , 4 , 8 , 16 } ;
const int * const iptr = arr + 2 ;
const char * const cptr = "¿Por qué?" ;
432 – By Gerson
Parámetros de función constante (pasados por valor)
433 – By Gerson
El fragmento es incorrecto, ya que la función intenta romper la
promesa. El compilador no se comprometerá en esto.
Hay muchas razones para esta advertencia. Una de las más obvias
es que el valor devuelto se encuentra en la memoria de solo
lectura.
Los literales de cadena de estilo C se almacenan comúnmente en
la parte de la memoria en la que no se puede escribir.
Por ejemplo, el siguiente programa (muy probablemente) causará
un desastre menor:
434 – By Gerson
Pregunta: ¿cuál de las siguientes funciones puede obtener
la variable str como parámetro y garantizar que el desastre no
ocurra?
435 – By Gerson
6.6.10 Variables de clase constante
clase Clase {
privado :
campo int const ;
public :
436 – By Gerson
Class ( int n ) : field ( n ) {} ;
Clase ( Clase & c ) : campo ( 0 ) {} ;
Clase ( nula ) : campo ( 1 ) {} ;
};
Estamos muy cerca del final de nuestro viaje por la Tierra de las
Constantes. Se paciente. Constantemente.
Un objeto de cualquier clase puede declararse
como constante .
Esto significa que el objeto no debe modificarse durante su
vida . El compilador protegerá el objeto de cualquier intento de
intentar cambiar su estado. Entonces:
Clase o1 (1);
437 – By Gerson
const clase o2 (2);
que i;
o2.field = 3;
o2.set (1);
i = o2.get ();
clase Clase {
public :
int field ;
Clase ( int n ) : campo ( n ) {} ;
Clase ( Clase & c ) : campo ( 0 ) {} ;
Clase ( nula ) : campo ( 1 ) {} ;
conjunto vacío ( int n ) { campo = n ; }
int get ( nulo ) { campo de retorno ; }
};
438 – By Gerson
6.6.12 Funciones miembro constantes
i = o2.get ();
clase Clase {
public :
int field ;
Clase ( int n ) : campo ( n ) {} ;
Clase ( Clase & c ) : campo ( 0 ) {} ;
439 – By Gerson
Clase ( nula ) : campo ( 1 ) {} ;
conjunto vacío ( int n ) { campo = n ; }
int get ( nulo ) const { campo de retorno ; }
};
440 – By Gerson
Si hay dos clases llamadas, por ejemplo, A y B , y si A quiere
que B pueda acceder a sus posesiones privadas, tiene que
anunciar que B es su amigo. El anuncio funciona solo en una
dirección. La clase B no puede decir simplemente: " Soy el amigo
de A ", no funcionará.
Tenga en cuenta que es como en la palabra real. Nuestros amigos
son aquellos a quienes nos referimos como amigos. Las personas
que afirman que son nuestros amigos pueden ser mentirosas.
source_06_07_02_friendclass.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
441 – By Gerson
amigo clase Amigo ;
privado :
campo int ;
void print ( void ) { cout << "Es un secreto, ese campo =" << campo << endl ;
};
class Friend {
public :
void DoIt ( Class & c ) { c. campo = 100 ; C. print () ; }
};
int main ( void ) {
Clase o ;
Amigo f ;
f. DoIt ( o ) ;
devuelve 0 ;
}
source_06_07_03_friendclass2.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase A {
amigo clase B ;
amigo clase C ;
privado :
campo int ;
protegido :
vacío de impresión ( vacío ) { cout << "Es un secreto, ese campo =" << campo
};
clase C {
public :
void DoIt ( A & a ) { a. print () ; }
};
clase B {
public :
void DoIt ( A y a, C y c ) { a. campo = 111 ; C. DoIt ( a ) ; }
};
int main ( nulo ) {
Aa;Bb;Cc;
443 – By Gerson
si. DoIt ( a, c ) ;
devuelve 0 ;
}
1. la clase B
444 – By Gerson
clase A;
source_06_07_04_friendfunc.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase A ;
clase C {
public :
void dec ( A & a ) ;
};
clase A {
amigo clase B ;
amigo vacío C :: dec ( A & ) ;
amigo vacío DoIt ( A & ) ;
privado :
campo int ;
445 – By Gerson
protegida :
vacío de impresión ( void ) { cout << "Es un secreto, ese campo =" << campo
};
nulo C :: dec ( A y a ) { a. campo - ; }
clase B {
public :
void DoIt ( A & a ) { a. print () ; }
};
nulo DoIt ( A y a ) {
a. campo = 99 ;
}
int main ( void ) {
Aa;Bb;Cc;
DoIt ( a ) ;
b. DoIt ( a ) ;
devuelve 0 ;
}
source_07_01_01_division.cpp
#include <iostream>
447 – By Gerson
usando el espacio de nombres estándar ;
source_07_01_02_divisionloop.cpp
449 – By Gerson
#include <iostream>
450 – By Gerson
¿Salvamos al mundo? Realmente no. Trate de imaginar que
tenemos que evaluar fórmulas más complejas que una sola
división.
Por ejemplo, queremos construir un código con docenas de
expresiones que incluyan no solo divisiones, sino también
invocaciones de funciones sensibles al punto de un dominio de los
argumentos, como sqrt () , que no le gustan los negativos, o tan
() , que es impotente contra argumentos que son múltiplos de 90
grados.
source_07_01_03_safedivloop.cpp
#include <iostream>
451 – By Gerson
más
cout << "¿Me estás tomando el pelo?" << endl ;
}
devuelve 0 ;
}
452 – By Gerson
Bien, perdón por esta breve digresión. Es hora de volver a nuestro
código. La función tiene tres parámetros: el primero se utiliza para
devolver el resultado de la función, mientras que los otros
transmiten valores de argumento a la función. Claro, simple y
elegante.
De Verdad?
source_07_01_04_safedivfun.cpp
#include <iostream>
usando el espacio de nombres estándar ;
bool div ( float & res, float arg1, float arg2 ) {
if ( arg2 == 0.0 )
return false ;
res = arg1 / arg2 ;
volver verdadero ;
}
int main ( void ) {
float r, a, b ;
mientras que ( cin >> a ) {
cin >> b ;
if ( div ( r, a, b ))
cout<< r << endl ;
más
cout << "¿Me estás tomando el pelo?" << endl ;
}
devuelve 0 ;
453 – By Gerson
}
456 – By Gerson
Si no hay nadie que quiera atrapar la excepción , continúa
volando al nivel más alto de la cadena de funciones con la
esperanza de que haya alguien allí que quiera atraparla.
Si la excepción no se detecta en el nivel superior (en la función
principal), hará que el programa se detenga y emita un mensaje
de diagnóstico apropiado. Este es el escenario "diabólico".
Hemos dicho que la excepción son los datos. El lenguaje "C ++"
proporciona algunas clases especializadas reunidas en una
estructura jerárquica que refleja las diferentes naturalezas de las
diferentes excepciones. Estas estructuras incluyen todas las
excepciones estándar generadas por funciones reunidas en
bibliotecas estándar.
457 – By Gerson
Esto no significa que tenga que usar solo objetos de estas clases:
puede usar los datos que desee, pero si va a preparar su código
para que funcione con alguna función estándar, debe conocer y
comprender La estructura de la jerarquía.
Los elementos más importantes de la jerarquía están aquí →
#include <excepción>
458 – By Gerson
7.1.8 Anatomía de un objeto de excepción
459 – By Gerson
Si desea detectar excepciones, debe marcar la parte del código en
la que pueden ocurrir las excepciones. Para ello, utilice la
instrucción "probar". De hecho, la declaración "probar" realmente
no hace nada, en particular, no cambia la ejecución de su
bloque. Solo activa un observador de excepciones de vuelo
(estamos bromeando, por supuesto).
Como puede ver, el nombre de la declaración es muy ilustrativo:
se lee: intente ejecutar esto y veremos qué sucede.
Una cosa importante: en el lenguaje "C ++" (a diferencia de otros
lenguajes de programación más nuevos), la división por cero no
arroja una excepción . Esto significa que tendremos que tirarlo
por nuestra cuenta.
No hay problema. Podemos hacerlo.
intente {
:
:
:
}
Esta forma:
atrapar ( qué ) {
:
:
:
}
lanzar 997;
461 – By Gerson
tirar una cuerda ("¡Adiós mundo!");
462 – By Gerson
Y aquí va el programa completo →
Ahora, preste atención al cuerpo del bucle while. Observe cómo se
intenta la división y cómo se detecta la excepción.
Compile el programa y ejecútelo. Probar su comportamiento en
diferentes casos.
source_07_01_13_except.cpp
#include <iostream>
usando el espacio de nombres estándar ;
float div ( float a, float b ) {
if ( b == 0.0 )
throw string ( "division by zero :(" ) ;
return a / b ;
}
int main ( void ) {
float a, b ;
while ( cin > > a ) {
try {
cin >> b ;
cout << div ( a, b )<< endl ;
} catch ( string & problem ) {
cout << "¡Mira lo que hiciste, mal usuario!" << endl ;
cout << problema << endl ;
}
}
463 – By Gerson
devuelve 0 ;
}
source_07_01_13_notcaught.cpp
#include <iostream>
usando el espacio de nombres estándar ;
float div ( float a, float b ) {
if ( b == 0.0 )
throw string ( "division by zero :(" ) ;
return a / b ;
}
int main ( void ) {
float a, b ;
while ( cin > > a ) {
464 – By Gerson
try {
cin >> b ;
cout << div ( a, b )<< endl ;
} catch ( int problem ) {
cout << "¡Mira lo que hiciste, mal usuario!" << endl ;
cout << problema << endl ;
}
}
devuelve 0 ;
}
465 – By Gerson
excepción. La excepción está "empaquetada" en un cuadro de
tipo cadena y lleva un mensaje simple que describe el problema.
También hay una rama de captura diseñada para detectar la
excepción y proporcionar un manejo muy simple (y, para ser
honesto, muy ingenuo).
466 – By Gerson
Deberías poder explicar esto fácilmente.
source_07_02_01_trycatchtogether.cpp
#include <iostream>
usando el espacio de nombres estándar ;
flotador DoCalculations ( flotar a, float b, flotador c, flotador d ) {
try {
float x ;
if ( a == 0.0 )
arrojar cadena ( "Arg incorrecto" ) ;
x=1/a;
if ( b == 0.0 )
arrojar cadena ( "Arg incorrecto b" ) ;
x/=b;
Si( c == 0.0 )
lanzar cadena ( "Arg incorrecta c" ) ;
x/=c;
if ( d == 0.0 )
arroja una cadena ( "Bad arg d" ) ;
retorno x / d ;
} catch ( string & exc ) {
cout << "Algo malo sucedió:" << exc << endl ;
devuelve 0 ;
467 – By Gerson
}
}
int main ( void ) {
DoCalculations ( 1 , 2 , 3 , 0 ) ;
devuelve 0 ;
}
source_07_02_02_trycatchseparated.cpp
#include <iostream>
usando el espacio de nombres estándar ;
468 – By Gerson
flotador DoCalculations ( flotar a, float b, flotador c, flo
float x ;
if ( a == 0.0 )
arrojar cadena ( "Arg incorrecto" ) ;
x=1/a;
if ( b == 0.0 )
arrojar cadena ( "Arg incorrecto b" ) ;
x/=b;
si ( c ==0.0 )
lanzar cadena ( "Arg incorrecta c" ) ;
x/=c;
if ( d == 0.0 )
arroja una cadena ( "Bad arg d" ) ;
retorno x / d ;
}
int main ( void ) {
try {
DoCalculations ( 1 , 2 , 3 , 0 ) ;
} catch ( string & exc ) {
cout << "Algo malo sucedió:"<< exc << endl ;
469 – By Gerson
}
devuelve 0 ;
}
Objeto construido
El objeto dice: hola
Objeto destruido
source_07_02_03_prologueepilogue.cpp
#include <iostream>
usando el espacio de nombres estándar ;
class Class {
public :
Class ( void ) { cout << "Objeto construido" << endl ; }
~ Class ( void ) { cout << "Objeto destruido" << endl ; }
void Hello ( void ) { cout << "El objeto dice: hola" << endl ; }
};
471 – By Gerson
int main ( void ) {
DoCalculations () ;
devuelve 0 ;
}
-------
fatal 1
-------
Objeto construido
Objeto destruido
fatal 2
-------
Objeto construido
El objeto dice: hola
Objeto destruido
472 – By Gerson
fatal 3
source_07_02_04_prologueepiloguethrow.cpp
incluir <iostream>
usando el espacio de nombres estándar ;
class Class {
public :
Class ( void ) { cout << "Objeto construido" << endl ; }
~ Class ( void ) { cout << "Objeto destruido" << endl ; }
void Hello ( void ) { cout << "El objeto dice: hola" << endl ; }
};
){
if ( i == 0 )
arrojar cadena ( "fatal 1" ) ;
Objeto de clase ;
if ( i == 1 )
arrojar cadena ( "fatal 2" ) ;
objeto. Hola () ;
if ( i == 2 )
arrojar cadena ( "fatal 3" ) ;
}
473 – By Gerson
int main ( void ) {
for ( int i = 0 ;i < 3 ; i ++ ) {
try {
cout << "-------" << endl ;
DoCalculations ( i ) ;
} catch ( string & exc ) {
cout << exc << endl ;
}
}
devuelve 0 ;
}
-------
Objeto [excepción 1] construido
Atrapado!
excepción 1
Objeto [excepción 1] destruido
-------
Objeto [objeto] construido
Objeto [excepción 2] construido
Objeto [objeto] destruido
Atrapado!
excepción 2
Objeto [excepción 2] destruido
-------
Objeto [objeto] construido
Objeto [objeto] dice: hola
Objeto [excepción 3] construido
Objeto [objeto] destruido
Atrapado!
475 – By Gerson
excepción 3
Objeto [excepción 3] destruido
source_07_02_05_throwobj.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) { cout << "Objeto [" << msg << "] construido" <<
~ Class ( void ) { cout << "Objeto [" << msg << "] destruido" << endl ;
"Object [" << msg << "] dice: hola" << endl ; }
};
anular DoCalculations ( int i ) {
if ( i == 0 )
throw Class ( "excepción 1" ) ;
Objeto de clase ( "objeto" ) ;
if ( i == 1 )
arrojar clase ( "excepción 2" ) ;
objeto. Hola () ;
if ( i == 2 )
arrojar clase ( "excepción 3" ) ;
}
int main ( void ) {
476 – By Gerson
for ( int i = 0 ; i < 3 ; i ++ ) {
try {
cout << "-------" << endl ;
DoCalculations ( i ) ;
} catch ( Class & exc ) {
cout << "¡Atrapado!" << endl ;
cout << exc. msg << endl ;
}
}
devuelve 0 ;
}
477 – By Gerson
source_07_02_06_nothrowspec.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) {}
};
función vacía ( int i ) {
throw Class ( "objeto" ) ;
}
int main ( void ) {
try {
function ( 1 ) ;
} catch ( Class & exc ) {
cout << "¡Atrapado!" << endl ;
}
devuelve 0 ;
}
478 – By Gerson
7.2.7 Lanzamiento y su especificación (1)
tirar (x)
lanzar()
Mira el ejemplo →
Hemos agregado la especificación de lanzamiento a nuestra
función.
But, apart from providing information. what does the specification
actually change? It’s a kind of promise. The program declares that
the function won’t throw objects of types other than those
specified. What’ll happen when the programmer doesn’t keep the
promise?
We’ll answer that question soon, but now we should also add that
the lack of specification means nothing. A function without the
specification may throw something or nothing at all.
Now we want to draw your attention to an additional interesting
aspect: note that the throw keyword has two different meanings.
Be aware!
source_07_02_07_throwspec.cpp
#include <iostream>
480 – By Gerson
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) {}
};
función vacía ( vacío ) throw ( Class ) {
throw Class ( "objeto" ) ;
}
int main ( void ) {
try {
function () ;
} catch (Class & exc ) {
cout << "¡Atrapado!" << endl ;
}
devuelve 0 ;
}
481 – By Gerson
¿Compilacion? Va bien : sin problemas, sin errores, sin
advertencias.
¿Ejecución? Houston, tenemos un problema: el programa ha
sido interrumpido y ha aparecido un mensaje. Dice que
hubo una excepción no detectada del tipo ' std :: string ' .
Oh sí, está claro. No hay rama de captura para este tipo de
excepción. ¡Tenemos que reparar nuestro código!
source_07_02_08_badthrowspec.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) {}
};
función vacía ( vacío ) throw ( Class ) {
throw string ( "object" ) ;
}
int main ( void ) {
try {
function () ;
} catch ( Class & exc ) {
cout << "¡Atrapado!" << endl ;
}
devuelve 0 ;
}
source_07_02_09_badthrowspec2.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) {}
};
función vacía ( vacío ) throw ( Class ) {
throw string ( "object" ) ;
}
int main ( void ) {
try {
function () ;
} catch ( string & exc ) {
483 – By Gerson
cout << "¡Atrapado!" << endl ;
}
devuelve 0 ;
}
source_07_02_10_goodthrowspec.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) {}
};
función vacía ( vacío ) throw ( string ) {
throw string ( "objeto" ) ;
}
int main ( void ) {
484 – By Gerson
try {
function () ;
} catch ( string & exc ) {
cout << "¡Atrapado!" << endl ;
}
devuelve 0 ;
}
source_07_02_11_emptythrowspec.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) {}
};
485 – By Gerson
función vacía ( vacío ) throw () {
throw string ( "objeto" ) ;
}
int main ( void ) {
try {
function () ;
} catch ( string & exc ) {
cout << "¡Atrapado!" << endl ;
}
devuelve 0 ;
}
source_07_02_12_doubledthrowspec.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Clase {
public :
string msg ;
Clase ( string txt ) : msg ( txt ) {}
};
función vacía ( int i ) throw ( string, Class ) {
switch ( i ) {
case 0 : throw string ( "string" ) ;
caso 1 : clase de lanzamiento ( "objeto" ) ;
predeterminado : cout << "OK" << endl ;
}
}
nivel vacío ( int i ) throw ( Class ) {
try {
function ( i ) ;
} catch ( string & exc ) {
487 – By Gerson
cout << "String [" << exc << "] atrapado en el nivel ()" << endl ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 2 ; i ++ ) {
cout << "-------" << endl ;
pruebe {
nivel ( i ) ;
} catch ( Class & exc ) {
cout << "Object [" << exc. msg << "] capturado en main ()" << endl ;
}
}
devuelve 0 ;
}
Sí, es obligatorio
¿Por qué? Porque las excepciones de tipo Class en realidad se
lanzan desde la función de nivel . No importa que sean arrojados
desde el cuerpo de otra función. La especificación debe contener
todas las excepciones que abandonan la función ,
independientemente de su procedencia.
488 – By Gerson
que finaliza el programa y emite el mensaje de diagnóstico
que ya hemos leído algunas veces. Su nombre es inesperado () .
No puede modificar la función (es parte del entorno estándar),
pero puede especificar su propia función si desea realizar algunas
limpiezas adicionales antes de que el programa termine su vida
útil.
Su función se invocará al comienzo de la ejecución inesperada de
la función () .
Recuerde: no puede "guardar" su programa de esta manera: su
destino está sellado y el programa finalizará de todos modos.
489 – By Gerson
Este mecanismo puede ser muy útil, pero no intente usarlo si no
está seguro de lo que está haciendo. Puede lograr el mismo
objetivo de una manera más simple (muy probablemente).
source_07_02_13_unexpect.cpp
#include <iostream>
#include <string>
490 – By Gerson
7.3.1 Jerarquía de clases de excepción
491 – By Gerson
7.3.2 La palabra clave 'explícita'
A a = 1;
B b = 1;
será considerado OK
492 – By Gerson
A a (1);
class A {
public :
explícito A ( int ) {}
};
clase B {
public :
B ( int ) {}
};
int main ( void ) {
A a = 1 ; // ¡error de compilación!
493 – By Gerson
Bb=1;
devuelve 0 ;
}
source_07_03_03_exception.cpp
#include <iostream>
#include <excepción>
usando el espacio de nombres estándar ;
494 – By Gerson
clase A {
public :
virtual void f ( void ) {}
};
clase AA : public A {
public :
void aa ( void ) {} ;
};
excepción ← error_lógico
495 – By Gerson
algoritmo / programa . Se puede (pero no siempre) hacen que
las excepciones de este tipo son evitables , es decir, que no
sucederá si todos los datos procesados son válidos. También
significa que este tipo de excepción puede predecirse
estáticamente analizando la estructura del código fuente.
#include <stdexcept>
497 – By Gerson
La clase length_error se deriva de la clase logic_error . Está
diseñado para representar todas las excepciones causadas por
el uso de valores ilegales para especificar el tamaño /
longitud de los agregados de datos .
Puede esperar este tipo de excepción cuando intenta extender una
cadena a una longitud inaceptable.
499 – By Gerson
};
500 – By Gerson
7.3.13 ¿Qué sigue?
7.3.14 bad_alloc
source_07_03_15_badexc.cpp
#include <iostream>
#include <excepción>
usando el espacio de nombres estándar ;
función vacía ( vacío ) throw ( int ) {
throw 3.14 ;
}
int main ( void ) {
try {
function () ;
} catch ( double f ) {
cout << "Got double" << endl ;
} catch ( bad_exception bad ) {
cout << "Es tan malo ..." << endl ;
}
cout << "Listo" << endl ;
devuelve 0 ;
}
source_07_03_16_badexc2.cpp
#include <iostream>
#include <excepción>
usando el espacio de nombres estándar ;
void unexp ( void ) {
cout << "¡Llegó una excepción inesperada!" << endl ;
tirar ;
}
función void ( void ) throw ( int , bad_exception ) {
503 – By Gerson
throw 3.14 ;
}
int main ( void ) {
set_unexpected ( unexp ) ;
intente {
function () ;
} captura( doble f ) {
cout << "Tiene doble" << endl ;
} catch ( bad_exception bad ) {
cout << "Es tan malo ..." << endl ;
}
cout << "Listo" << endl ;
devuelve 0 ;
}
Excepción atrapada!
Excepción atrapada!
Excepción atrapada!
source_07_04_01_ellipsis.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función nula ( int i ) {
switch ( i ) {
505 – By Gerson
case 0 : throw out_of_range ( "0" ) ;
caso 1 : lanzar overflow_error ( "1" ) ;
caso 2 : arrojar domain_error ( "2" ) ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 3 ; i ++ ) {
try {
function ( i ) ;
}
catch ( ... ) {
cout << "¡Excepción capturada!" << endl ;
}
}
devuelve 0 ;
}
506 – By Gerson
lanzadas por una función se derivan de la clase de excepción y,
por lo tanto, son de tipo compatible.
Tenga en cuenta que ahora podemos identificar un objeto,
nombrarlo localmente (como ex ) y hacer uso de sus propiedades
y / o funciones. Invocamos la función qué para averiguar qué
quiere decir el objeto sobre sí mismo.
Excepción capturada: 0
Excepción capturada: 1
Excepción capturada: 2
Excepción detectada: excepción desconocida
fuente_07_04_02_clase
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
507 – By Gerson
función nula ( int i ) {
switch ( i ) {
case 0 : throw out_of_range ( "0" ) ;
caso 1 : lanzar overflow_error ( "1" ) ;
caso 2 : arrojar domain_error ( "2" ) ;
caso 3 : lanzar excepción () ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 4 ; i ++ ) {
try {
function ( i ) ;
}
catch (except & ex) {
cout<<"Excepción capturada:"<< ej. what()<< endl;
}
}
devuelve 0 ;
}
508 – By Gerson
la función arroja cuatro excepciones diferentes y podemos hacer
cuatro ramas de captura : una rama por tipo de excepción.
El programa modificado está aquí →
Actualmente, cada una de las excepciones se maneja por
separado.
El programa genera el siguiente texto:
Fuera de rango: 0
Desbordamiento: 1
Dominio: 2
Excepción: excepción desconocida
source_07_04_03_branches.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función nula ( int i ) {
switch ( i ) {
case 0 : throw out_of_range ( "0" ) ;
caso 1 : lanzar overflow_error ( "1" ) ;
caso 2 : arrojar domain_error ( "2" ) ;
caso 3 : lanzar excepción () ;
}
}
509 – By Gerson
int main ( void ) {
f or ( int i = 0 ; i < 4 ; i ++ ) {
try {
function ( i ) ;
}
catch ( out_of_range & ofr ) {
cout << "Fuera de rango:" << ofr. what () << endl ;
}
catch ( overflow_error & ovf ) {
cout << "Desbordamiento:" << ovf. que ()<< endl ;
}
catch ( domain_error & dmn ) {
cout << "Dominio:" << dmn. what () << endl ;
}
catch ( excepción y ex ) {
cout << "Excepción:" << ex. what () << endl ;
}
}
devuelve 0 ;
}
Fuera de rango: 0
Desbordamiento: 1
Dominio: 2
Excepción: excepción desconocida
Algo malo sucedio
source_07_04_04_brancheselli.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función nula ( int i ) {
switch ( i ) {
case 0 : throw out_of_range ( "0" ) ;
caso 1 : lanzar overflow_error ( "1" ) ;
caso 2 : arrojar domain_error ( "2" ) ;
caso 3 : lanzar excepción () ;
caso 4: tirar "tan mal" ;
}
}
int main ( void ) {
511 – By Gerson
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
function ( i ) ;
}
catch ( out_of_range & ofr ) {
cout << "Fuera de rango:" << ofr. what () << endl ;
}
catch ( overflow_error & ovf ) {
cout << "Desbordamiento:" << ovf. que () <<;
}
catch ( domain_error & dmn ) {
cout << "Dominio:" << dmn. what () << endl ;
}
catch ( excepción y ex ) {
cout << "Excepción:" << ex. what () << endl ;
}
catch ( ... ) {
cout << "Algo malo sucedió" << endl ;
}
}
devuelve 0 ;
}
Fuera de rango: 0
Desbordamiento: 1
Dominio: 2
Excepción: excepción desconocida
Algo malo sucedio
source_07_04_05_swap1.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función nula ( int i ) {
switch ( i ) {
case 0 : throw out_of_range ( "0" ) ;
caso 1 : lanzar overflow_error ( "1" ) ;
caso 2 : arrojar domain_error ( "2" ) ;
caso 3 : lanzar excepción () ;
caso 4: tirar "tan mal" ;
}
513 – By Gerson
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
function ( i ) ;
}
catch (overflow_error & ovf) {
cout<<"Desbordamiento:"<< ovf. what()<< endl;
}
catch (out_of_range & ofr) {
cout<<"Fuera de rango:"<< ofr. what()<< endl;
}
catch (domain_error & dmn) {
cout<<"Dominio:"<< dmn. what()<< endl;
}
captura (excepción y
"Excepción:" << ej. what () << endl ;
}
catch ( ... ) {
cout << "Algo malo sucedió" << endl ;
}
}
devuelve 0 ;
}
514 – By Gerson
Es hora del próximo cambio. Ahora hemos intercambiado las
ramas de captura primera y cuarta.
¿Cambia el comportamiento del programa?
Si, lo hace!
Excepción: 0
Excepción: 1
Excepción: 2
Excepción: excepción desconocida
Algo malo sucedio
source_07_04_06_swap2.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función nula ( int i ) {
switch ( i ) {
case 0 : throw out_of_range ( "0" ) ;
515 – By Gerson
caso 1 : lanzar overflow_error ( "1" ) ;
caso 2 : arrojar domain_error ( "2" ) ;
caso 3 : lanzar excepción () ;
caso 4: tirar "tan mal" ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
function ( i ) ;
}
catch (excepción y ex) {
cout<<"Excepción:"<< ex. what()<< endl;
}
catch (out_of_range & ofr) {
cout<<"Fuera de rango:"<< ofr. what()<< endl;
}
catch (overflow_error & ovf) {
cout<<"Desbordamiento:"<< ovf. what()<< endl;
}
catch (domain_error &
"Dominio:" << dmn. what () << endl ;
}
catch ( ... ) {
cout << "Algo malo sucedió" << endl ;
}
}
devuelve 0 ;
}
516 – By Gerson
Cuando la excepción llega a un conjunto de ramas de captura , se elige
de destino.
Esto significa que cuando se coloca un tipo / clase más general an
rama no recibirá ninguna excepción .
Es por eso que el compilador le advierte que el orden de las ramas d
permanentemente en el proceso de selección del controlador de excepc
Esta es también la razón por la cual la rama con la clase de excepció
la clase de excepción .
Excepción: 0
Excepción: 1
Excepción: excepción desconocida
Excepción: 2
Debe esperar este tipo de comportamiento cada vez que una excepción
source_07_04_07_hierarchy.cpp
#include <iostream>
517 – By Gerson
#include <excepción>
# include <stdexcept>
using namespace std ;
función vacía ( int i ) {
switch ( i ) {
case 0 : throw domain_error ( "0" ) ;
caso 1 : throw logic_error ( "1" ) ;
caso 2 : lanzar excepción () ;
caso 3 : arrojar range_error ( "2" ) ;
caso 4 : tirar "tan mal" ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
function ( i ) ;
}
catch ( excepción y ex ) {
cout << "Excepción:" << ex. what () << endl ;
}
}
devuelve 0 ;
}
518 – By Gerson
Podemos reparar nuestro programa de una manera muy simple:
todo lo que tenemos que hacer aquí es agregar una rama de
puntos suspensivos, que será responsable de encargarse de todas
las excepciones huérfanas. Por supuesto, no es un remedio para
todos sus problemas con excepciones no controladas. La vida real
crea circunstancias más complicadas.
Nuestro programa reparado produce el siguiente resultado:
Excepción: 0
Excepción: 1
Excepción: excepción desconocida
Excepción: 2
Algo malo sucedio
source_07_04_08_hierarchy2.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función vacía ( int i ) {
switch ( i ) {
case 0 : throw domain_error ( "0" ) ;
caso 1 : throw logic_error ( "1" ) ;
519 – By Gerson
caso 2 : lanzar excepción () ;
caso 3 : arrojar range_error ( "2" ) ;
caso 4 : tirar "tan mal" ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
function ( i ) ;
}
catch (excepción y ex) {
cout<<"Excepción:"<< ex. what()<< endl;
}
catch (...) {
cout<<"Algo malo sucedió"<< endl;
}
}
devuelve 0 ;
}
source_07_04_09_hierarchy3.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función vacía ( int i ) {
switch ( i ) {
case 0 : throw domain_error ( "0" ) ;
caso 1 : throw logic_error ( "1" ) ;
caso 2 : lanzar excepción () ;
caso 3 : arrojar range_error ( "2" ) ;
caso 4 : tirar "tan mal" ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
function ( i ) ;
}
catch (logic_error & le) {
521 – By Gerson
cout<<"Error lógico:"<< le. what()<< endl;
}
catch (excepción y ex) {
cout<<"Excepción:"<< ex. what()<< endl;
}
catch (...) {
cout<<"Algo malo sucedió"<< endl;
}
}
devuelve 0 ;
}
Error lógico: 0
Error lógico: 1
Excepción: excepción desconocida
Excepción: 2
Algo malo sucedio
source_07_04_10_hierarchy4.cpp
522 – By Gerson
#include <iostream>
#include <excepción>
# include <stdexcept>
utilizando espacio de nombres std ;
función vacía ( int i ) {
switch ( i ) {
case 0 : throw domain_error ( "0" ) ;
caso 1 : throw logic_error ( "1" ) ;
caso 2 : lanzar excepción () ;
caso 3 : arrojar range_error ( "2" ) ;
caso 4: tirar "tan mal" ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
function ( i ) ;
}
catch (logic_error & le) {
cout<<"Error lógico:"<< le. what()<< endl;
}
catch (runtime_error & re) {
cout<<"Error de tiempo de ejecución:"<< re. what()<< endl;
}
catch (excepción y ex) {
cout<<"Excepción:"<< ex. what()<< endl;
}
captura (...
"Algo malo sucedió" << endl ;
}
}
devuelve 0 ;
}
523 – By Gerson
7.4.11 Compartir la responsabilidad (1)
La respuesta es:
Error lógico: 0
Error lógico: 1
Excepción: excepción desconocida
Error de tiempo de ejecución: 2
Algo malo sucedio
Broker - excepción: 0
Broker - excepción: 1
Broker - excepción: excepción desconocida
Broker - excepción: 2
Algo malo sucedio
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función vacía ( int i ) {
switch ( i ) {
case 0 : throw domain_error ( "0" ) ;
caso 1 : throw logic_error ( "1" ) ;
caso 2 : lanzar excepción () ;
caso 3 : arrojar range_error ( "2" ) ;
caso 4 : tirar "tan mal" ;
}
}
corredor vacío ( int i ) {
try { function ( i ) ; }
catch ( excepción ex ) { cout << "Broker - excepción:" << ex. what () << endl ;
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
broker ( i ) ;
}
catch (logic_error & le) {
cout<<"Error lógico:"<< le. what()<< endl;
525 – By Gerson
}
catch (runtime_error & re) {
cout<<"Error de tiempo de ejecución:"<< re. what()<< endl;
}
catch (excepción y ex) {
cout<<"Excepción:"<< ex. what()<< endl;
}
captura (...
"Algo malo sucedió" << endl ;
}
}
devuelve 0 ;
}
source_07_04_12_broker2.cpp
526 – By Gerson
#include <stdexcept>
#include <excepción>
#include <iostream>
switch ( i ) {
try { function ( i ) ; }
catch ( logic_error & le ) { cout << "Broker - logic_error:" << le. what () << endl ; }
try {
broker ( i ) ;
catch ( excepción y ex ) {
catch ( ... ) {
devuelve 0 ;
527 – By Gerson
}
source_07_04_13_broker3.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función vacía ( int i ) {
switch ( i ) {
case 0 : throw domain_error ( "0" ) ;
caso 1 : throw logic_error ( "1" ) ;
caso 2 : lanzar excepción () ;
caso 3 : arrojar range_error ( "2" ) ;
528 – By Gerson
caso 4 :tirar "tan mal" ;
}
}
corredor vacío ( int i ) {
try {
function ( i ) ;
}
catch (...) {
cout<<"El corredor barrió los problemas debajo de la alfombra"<< endl;
}
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
broker ( i ) ;
}
catch (logic_error & le) {
cout<<"Error lógico:"<< le. what()<< endl;
}
catch (runtime_error & re) {
cout<<"Error de tiempo de ejecución:"<< re. what()<< endl;
}
catch (excepción y ex) {
cout<<"Excepción:"<< ex. what()<< endl;
}
captura (...
"Algo malo sucedió" << endl ;
}
}
devuelve 0 ;
}
529 – By Gerson
7.4.14 Compartir la responsabilidad (4)
source_07_04_14_broker4.cpp
#include <iostream>
#include <excepción>
# include <stdexcept>
using namespace std ;
función vacía ( int i ) {
switch ( i ) {
531 – By Gerson
case 0 : throw domain_error ( "0" ) ;
caso 1 : throw logic_error ( "1" ) ;
caso 2 : lanzar excepción () ;
caso 3 : arrojar range_error ( "2" ) ;
caso 4 : tirar "tan mal" ;
}
}
corredor vacío ( int i ) {
try {
function ( i ) ;
}
catch ( ... ) {
cout << "El corredor barrió los problemas debajo de la alfombra" << endl ;
tirar ;
}
}
int main ( void ) {
for ( int i = 0 ; i < 5 ; i ++ ) {
try {
broker ( i ) ;
}
catch ( logic_error & le ) {
cout << "Error lógico:" << le. what () << endl ;
}
catch ( runtime_error & re ) {
cout << "Error de tiempo de ejecución:" << re. what () << endl ;
}
catch ( excepción y ex ) {
cout << "Excepción:" << ex. what () << endl ;
}
captura ( ...
"Algo malo sucedió" << endl ;
}
532 – By Gerson
}
devuelve 0 ;
}
533 – By Gerson
Las mejoras son muy necesarias. Pongámonos a trabajar.
source_07_05_01_stack.cpp
class Stack {
private :
int * stackstore ;
int stacksize ;
int SP ;
public :
Stack ( int tamaño = 100 ) ;
~ Pila () ;
vacío push ( valor int ) ;
int pop ( nulo ) ;
};
Pila :: Pila ( tamaño int ) {
stackstore = new int [ tamaño] ;
stacksize = tamaño ;
SP = 0 ;
}
Pila :: ~ Pila ( nula ) {
eliminar [] stackstore ;
}
pila vacía :: push ( valor int ) {
stackstore [ SP ++ ] = value ;
}
int Stack :: pop ( void ) {
return stackstore [ --SP ] ;
}
534 – By Gerson
#include <iostream>
usando el espacio de nombres estándar ;
int main ( void ) {
Stack stk ;
stk. empujar ( 1 ) ;
cout << stk. pop () << endl ;
devuelve 0 ;
Intentemos identificar todas las sorpresas "malas" que nuestra pila pue
enfrentar en su vida. Podemos ver cuatro de ellos aquí:
Puede que no esté de acuerdo, pero creemos que los mejores nombres
para estos son los que están aquí →
Por supuesto, la convención de nomenclatura es solo cuestión de gusto
Puedes nombrarlos de manera diferente ... si crees que tenemos mal g
1. stack_size_error
535 – By Gerson
2. stack_bad_alloc
3. stack_overflow
4. stack_empty
source_07_05_03_newexceptions
#include <iostream>
#include <excepción>
#include <stdexcept>
536 – By Gerson
public :
explícito stack_size_error ( const std :: string & msg ) ;
};
clase stack_bad_alloc : public std :: bad_alloc {
público :
explícito stack_bad_alloc ( void ) ;
};
clase stack_overflow : public std :: logic_error {
public :
explicitstack_overflow ( const std :: string & msg ) ;
};
clase stack_empty : public std :: logic_error {
public :
explicit stack_empty ( const std :: string & msg ) ;
};
stack_size_error :: stack_size_error ( const std :: string & msg ) : std :: length_error ( msg ) {
};
stack_bad_alloc :: stack_bad_alloc ( vacío ) : std :: bad_alloc () {
};
537 – By Gerson
stack_overflow :: stack_overflow ( const std :: string & msg ) : std :: logic_error ( msg ) {
};
stack_empty :: stack_empty (const std :: string & msg ) : std :: logic_error ( msg ) {
};
source_07_05_05_newthrows
538 – By Gerson
class Stack {
private :
int * stackstore ;
int stacksize ;
int SP ;
public :
Stack ( int size = 100 ) throw ( stack_size_error, stack_bad_alloc ) ;
~ Pila () ;
vacío push ( valor int ) throw ( stack_overflow ) ;
int pop ( void ) throw ( stack_empty );
};
source_07_05_06_construct
539 – By Gerson
pruebe {
stackstore = new int [ tamaño ] ;
} catch ( std :: bad_alloc ba ) {
throw stack_bad_alloc () ;
}
stacksize = tamaño ;
SP = 0 ;
}
7.5.7. Apilar de nuevo - nuevo empuje
source_07_05_07_push
540 – By Gerson
source_07_05_08_pop
541 – By Gerson
nombre único para el proyecto específico. Por lo general, el nombre de
del nombre del encabezado en sí, y hemos seguido esa convención aqu
Si el símbolo no está definido ( ndef ), el preprocesador analizará el re
del archivo o lo omitirá. Tenga en cuenta que no omite todo el conten
del archivo, sino solo la parte anidada en
las directivas #ifndef y #endif .
mystack.h
#ifndef __MYSTACK__
#define __MYSTACK__
#include <iostream>
#include <excepción>
#include <stdexcept>
542 – By Gerson
};
class Stack {
private :
int * stackstore ;
int stacksize ;
int SP ;
public :
Stack ( int size = 100 ) throw ( stack_size_error, stack_bad_alloc ) ;
~ Pila () ;
vacío push ( valor int ) throw ( stack_overflow ) ;
int pop ( void ) throw ( stack_empty );
};
543 – By Gerson
#endif
mystack.cpp
#incluye "mystack.h"
stack_overflow :: stack_overflow ( const std :: string & msg ) : std :: logic_error ( msg ) {
};
stack_empty :: stack_empty ( const std :: string & msg ) : std :: logic_error ( msg ) {
};
544 – By Gerson
if ( size <= 0 )
throw stack_size_error ( "el tamaño debe ser> = 0" ) ;
pruebe {
stackstore = new int [ tamaño ] ;
} catch ( std :: bad_alloc ba ) {
throw stack_bad_alloc () ;
}
stacksize = tamaño ;
SP = 0 ;
}
545 – By Gerson
7.5.11 Pila de nuevo - función principal
algunos compiladores pueden usar " mystack.o ", otros " mystack.ob
no se sorprenda).
¿Terminamos?
No, no lo estamos. Definitivamente necesitamos hacer algunas pruebas
para demostrar (incluso de forma limitada) que nuestra pila funciona d
manera confiable.
main.cpp
546 – By Gerson
#incluye "mystack.h"
#include <iostream>
usando el espacio de nombres estándar ;
int main ( void ) {
Stack stk ;
stk. empujar ( 1 ) ;
cout << stk. pop () << endl ;
devuelve 0 ;
}
7.5.12 Volver a apilar: nueva y mejor función principal
Aquí están las prendas nuevas del emperador, lo siento, las principales
nuevas →
Ahora estamos preparados para todas las circunstancias
(al menos eso creemos). Todas las operaciones de pila están cubiertas
el bloque try , y tenemos un conjunto completo de capturas listo para
diagnosticar todos los problemas. Hagamos algunas pruebas de choqu
source_07_05_12_main2.cpp
#incluye "mystack.h"
#include <iostream>
547 – By Gerson
stk. empujar ( 1 ) ;
cout << stk. pop () << endl ;
}
catch ( stack_bad_alloc sba ) {
cout << "No hay espacio para la pila, ¡lo siento!" << endl ;
}
catch ( stack_size_error sse ) {
cout << "Las pilas de ese tamaño no existen, ¡lo siento!" << endl ;
}
catch ( stack_overflow se) {
cout << "La pila es demasiado pequeña para tantos empujes, ¡lo sien
}
catch ( stack_empty su ) {
cout << "La pila está vacía, ¡lo siento!" << endl ;
}
devuelve 0 ;
}
source_07_05_13_main3.cpp
548 – By Gerson
#incluye "mystack.h"
#include <iostream>
549 – By Gerson
7.5.14 Pila de nuevo - pruebas de choque (2)
source_07_05_14_main4.cpp
#incluye "mystack.h"
#include <iostream>
550 – By Gerson
cout<<"La pila es demasiado pequeña para tantos empujes, ¡lo siento!" << endl;
}
catch (stack_empty su) {
cout<<"La pila está vacía, ¡lo siento!" << endl;
}
devuelve 0 ;
}
source_07_05_15_main5.cpp
#incluye "mystack.h"
#include <iostream>
551 – By Gerson
try {
Stack stk ( 1 ) ;
stk. empujar ( 1 ) ;
stk. empujar ( 2 ) ;
cout << stk. pop () << endl ;
}
catch ( stack_bad_alloc sba ) {
cout << "No hay espacio para la pila, ¡lo siento!" << endl ;
}
catch ( stack_size_error sse ) {
cout <<"No existen pilas de ese tamaño, ¡lo siento!" << endl ;
}
catch ( stack_overflow se ) {
cout << "La pila es demasiado pequeña para tantos empujes, ¡lo siento!" << endl ;
}
catch ( stack_empty su ) {
cout << "La pila está vacía, ¡lo siento!" << endl ;
}
devuelve 0 ;
}
source_07_05_16_main6.cpp
#incluye "mystack.h"
#include <iostream>
553 – By Gerson
8.1.1 Operadores: una mirada al pasado (1)
operadores unarios
operadores binarios
554 – By Gerson
8.1.2 Operadores: una mirada al pasado (2)
operador >>
556 – By Gerson
Una función de operador puede implementarse de dos maneras:
Nota:
557 – By Gerson
expresión, p. ej. stack << 2 * VAR;
etc
mystack_01.h
558 – By Gerson
.1.5 Implementación del operador << (2)
Implementing the << operator (2)
La definición correspondiente de la función del operador está aquí
→
Como hemos dicho anteriormente, el objeto de la clase es el
primero de los argumentos del operador (el izquierdo, para
ser precisos), por lo que no tenemos nada más que hacer, excepto
invocar el método push con un valor del segundo operador
(derecho) argumento.
La nueva función principal que hace uso del nuevo operador está
aquí →
El nuevo operador funciona igualmente bien con literales,
expresiones y variables. Compruébalo tú mismo. No confíes en
nuestra palabra .
main_01.cpp
559 – By Gerson
560 – By Gerson
8.1.7 Implementación del operador >> (1)
Implementing the >> operator (1)
En segundo lugar, definiremos el operador para la función de
miembro pop . Tenga en cuenta que hay una diferencia
importante entre el operador anterior y el actual.
No se nos permite (por razones obvias) almacenar un valor
extraído de la pila dentro de un literal o una
expresión . Tenemos que ponerlo en una variable (o para ser
más precisos, en un valor l ).
Por otro lado, un parámetro pasado por valor no puede transferir
datos en ninguna otra dirección que no sea desde el exterior a la
función. Esto no es lo que necesitamos.
Pero es por eso que declaramos el único argumento de la función
como aprobado por referencia.
La declaración completa está aquí →
mystack_02.h
561 – By Gerson
8.1.9 Implementando el >> operador (3)
Implementing the >> operator (3)
563 – By Gerson
8.1.12 Mejora del operador << (3)
Improving the << operator (3)
Es hora de algunas pruebas: la nueva función principal está aquí
→
¡Pruébalo!
main_03.cpp
564 – By Gerson
8.1.14 Mejora del operador << (5)
Improving the << operator (5)
Y la nueva definición →
mystack_04.cpp
565 – By Gerson
8.1.16 Los mismos efectos de una manera diferente
The same effects in a different way
Implementar operadores sobrecargados como funciones miembro
es fácil cuando eres el "propietario" de la clase y puedes modificar
su código fuente de cualquier manera. Puede ser imposible cuando
el código fuente no está disponible. Por supuesto, en muchos
casos puede ser posible escribir su propia subclase que contenga
todos los operadores deseados, pero esto puede ser inconveniente
en algunos casos.
Afortunadamente, se le permite escribir funciones de
operador fuera de cualquier clase : usar ambos tipos de
operadores es lo mismo, y cuando usa un operador sobrecargado
sin conocer su implementación, no puede adivinar cuál de los
métodos se ha utilizado.
En nuestro caso, una función de operador independiente debe
tener dos argumentos y el orden de los argumentos refleja el
orden de los argumentos del operador.
Tenga cuidado: no todos los operadores pueden estar
sobrecargados de esta manera.
Discutiremos ambos aspectos pronto.
566 – By Gerson
8.1.17 Un operador de indexación para la pila (1)
An indexing operator for the stack (1)
Para mostrarle el poder de la sobrecarga del operador, le
mostraremos un ejemplo de implementación de un operador algo
sorprendente. Redefiniremos el significado del operador de
indexación .
Sí, sabemos que está diseñado para matrices o colecciones tipo
matriz y parece que la pila no tiene nada que ver con eso. Pero,
desde cierto punto de vista, una pila es una matriz, una muy
específica, pero sigue siendo una matriz.
Será una indexación muy poco ortodoxa. Estamos de acuerdo: su
usabilidad es muy discutible, pero en nuestra opinión funcionará
perfectamente como conejillo de indias en el laboratorio de
nuestro operador.
Queremos que la indexación funcione de esta extraña manera:
Pila [0] devuelve una referencia al elemento que se encuentra en
la parte superior de la pila
567 – By Gerson
Pila [-1] devuelve una referencia al elemento que se encuentra
debajo de la parte superior de la pila
, etc., etc.
Tenga en cuenta que esta es una referencia , no un valor , ya
que queremos usar el operador dentro de las expresiones de valor
l , por ejemplo, como un argumento izquierdo del operador de
asignación.
Un intento de alcanzar un elemento de pila inexistente provocará
una excepción. Parece que std :: range_error es el mejor
candidato para este propósito.
OKAY. Escribamos una declaración →
Nota:
mystack_06.h
568 – By Gerson
8.1.19 Un operador de indexación para la pila (3)
An indexing operator for the stack (3)
La versión más nueva de la función principal está aquí →
El programa produce el siguiente resultado:
4
1
0
0
Consulte el código fuente y responda la pregunta: ¿es esto lo que
esperábamos? ¿Es la prueba que estamos buscando de que
nuestro operador funciona correctamente?
Tenemos curiosidad por saber lo que piensas. Si tan solo
pudiéramos.
main_06.cpp
569 – By Gerson
8.2.1 Tipos enumerados: ¿por qué los necesitamos? (1)
Enumerated types – why do we need them? (1)
570 – By Gerson
8.2.2 Tipos enumerados: ¿por qué los necesitamos? (2)
Enumerated types – why do we need them? (2)
dónde:
571 – By Gerson
la cadena es solo una serie de caracteres
572 – By Gerson
8.2.3 Tipos enumerados: ¿por qué los necesitamos? (3)
Enumerated types – why do we need them? (3)
573 – By Gerson
8.2.4 Tipos enumerados: ¿cómo los definimos?
Enumerated types– how do we define them?
575 – By Gerson
8.2.7 Tipos enumerados: ¿cómo los usamos? (3)
Enumerated types – how do we use them? (3)
576 – By Gerson
8.2.10 Tipos enumerados: ¿cómo los usamos? (6)
Enumerated types – how do we use them? (6)
577 – By Gerson
8.2.12 Tipos enumerados: ¿cómo los usamos? (8)
Enumerated types – how do we use them? (8)
579 – By Gerson
8.3.1 ¡Advertencia!
Warning!
el operador sobrecarga
581 – By Gerson
8.3.3 Lo que no debes hacer
What you mustn’t do
582 – By Gerson
8.3.4 Operadores aritméticos
Arithmetic operators
Operadores +-*/%
Dependiendo del
Tipo de valor de retorno
contexto
583 – By Gerson
8.3.5 Operadores bit a bit
Bitwise operators
Dependiendo del
Tipo de valor de retorno
contexto
584 – By Gerson
Todos los operadores anteriores, excepto el ~ , son binarios .
Resista la tentación de sobrecargar el operador ^ para una
exponenciación, como en los lenguajes de programación FORTRAN
o PERL y en algunas hojas de cálculo.
La exponenciación real tiene una prioridad muy alta (más alta que
el operador * ), mientras que ^ tiene una prioridad más baja que
otros operadores aritméticos. Puede traer algunos efectos
secundarios inesperados y no deseados.
Hemos reconstruido nuestro ejemplo anterior, puedes encontrarlo
aquí →
Ahora la clase V es capaz de desplazar a la derecha bit a bit cada
uno de sus elementos y evaluar su producto (es un uso bastante
inusual del operador ~ , sí, lo sabemos).
El programa produce el siguiente resultado:
(7, 3)
21
source_08_03_05_bitwise.cpp
585 – By Gerson
8.3.6 Operador de asignación
Assignment operator
Operadores =
586 – By Gerson
int main ( nulo ) {
V v1 (4, 8), v2, v3;
v2 = v3 = v1;
cout << "(" << v2.vec [0] << "," << v2.vec [1] << ")" << endl;
devuelve 0;
}
source_08_03_06_assign.cpp
587 – By Gerson
Tipo de valor de retorno booleano
588 – By Gerson
8.3.8 Operadores lógicos
Logical operators
Operadores ! && ||
589 – By Gerson
Como la función lógica sobrecargada no puede hacer tal distinción,
las dos funciones anteriores se invocarán cuando se usen juntas
en la misma expresión.
El programa de ejemplo aquí → define el operador && para
verificar la siguiente condición, verbalmente definida:
Los vectores izquierdo y derecho tienen al menos un elemento
distinto de cero.
El segundo de los operadores devuelve un valor que refleja la
condición:
Todos los elementos del vector son distintos de cero.
El programa emitirá las siguientes dos líneas:
cierto
cierto
source_08_03_08_logical.cpp
590 – By Gerson
8.3.9 Operadores de asignación compuesta
Compound assignment operators
+ = - = * =% = / = & = | = ^ =
Operadores
>> = << =
591 – By Gerson
8.3.10 Operadores de incremento y decremento de prefij
Operadores ++--
592 – By Gerson
La forma de prefijo de ++ / - debe implementarse como una
función de operador sin parámetros y (ya que modifica su
argumento antes de su uso) debe devolver una referencia al
objeto modificado.
Usted es responsable de garantizar que los operadores de prefijo
y sufijo dejen sus argumentos en el mismo estado y que ambos
sean coherentes con + = 1 y - = 1 . El compilador no es lo
suficientemente astuto como para hacerlo por ti.
El programa de ejemplo (puede encontrarlo aquí →) le muestra un
prefijo ++ sobrecargado que afecta a todos los elementos
vectoriales. El programa genera:
(2, 3)
source_08_03_10_prefix.cpp
593 – By Gerson
8.3.11 Operadores de incremento y decremento de postfix
Operadores ++--
(3, 4)
source_08_03_11_postfix.cpp
594 – By Gerson
#include <iostream>
usando el espacio de nombres estándar ;
clase V {
public :
int vec [ 2 ] ;
V ( int a0, int a1 ) { vec [ 0 ] = a0 ; vec [ 1 ] = a1 ; }
V operador ++ ( int ninguno ) {
V v ( vec [ 0 ] , vec [ 1 ]) ; para
( int i = 0 ; i < 2 ; i ++ )
++ vec [ i ]
return v ;
}
};
int main ( nulo ) {
V v1 ( 2 , 3 ) ;
v1 ++ ;
cout << "(" << v1. vec [ 0 ] << "," << v1. vec [ 1 ] << ")" << endl ;
devuelve 0 ;
}
595 – By Gerson
8.4.1 Operador de subíndice
Operador []
arr [0] = 0;
1 [arr] = 1;
596 – By Gerson
Por ejemplo, puede ocultar búsquedas y actualizaciones de bases
de datos bajo una máscara de indexación. Además,
los índices int pueden ser negativos. La semántica de dicha
indexación está completamente definida por el
programador .
El operador de índice sobrecargado ya no es conmutativo . Lo
sentimos, por favor dirija sus quejas a otra parte.
16
9
4
1
source_08_04_01_index.cpp
597 – By Gerson
#include <iostream>
# include <stdexcept>
using namespace std ;
clase Arr {
privado :
int a, b, c, d ;
public :
Arr () { a = b = c = d = 0 ; }
int & operator [] ( int index ) {
switch ( index ) {
case 1 : return a ;
caso 2 : retorno b ;
caso 3 : retorno c ;
caso4 : retorno d ;
valor predeterminado : throw range_error ( "índice incorrecto" ) ;
}
}
};
int main ( nulo ) {
Arr arr ;
598 – By Gerson
8.4.2 Operador de invocación de funciones
Operador ()
El programa genera:
599 – By Gerson
2
3
source_08_04_02_invoke.cpp
#include <iostream>
usando el espacio de nombres estándar ;
clase Fun {
public :
int operator () ( int a1, int a2 ) {
return a1> a2 ? a1 : a2 ;
}
int operator () ( int a1, int a2, int a3 ) {
return a1> a2 ? ( A1> a3 ? A1 : a3 ) : ( a2> a3 ? A2: a3 ) ;
}
};
int main ( void ) {
Fun f ;
600 – By Gerson
8.4.3 Operadores de puntero
Operador &*
'Charlie' -> 2
601 – By Gerson
source_08_04_03_pointers
#include <iostream>
clase P {
public :
int no ;
P ( int n ) : no ( n ) {}
P () : no ( 0 ) {}
operador de cadena & () {
switch ( no ) {
case 0 : return "alpha" ;
caso 1 : devolver "bravo" ;
caso 2 : devolver "charlie" ;
}
}
};
603 – By Gerson
8.4.5 Operadores no sobrecargables
604 – By Gerson
un constructor de un parámetro , que establece la
fracción al valor igual al valor del parámetro (en
realidad parámetro / 1 )
605 – By Gerson
8.4.7 Fracción: un archivo de encabezado
fracción.h
#ifndef __FRACTION_H__
#define __FRACTION_H__
#include <stdexcept>
#include <cadena>
Fracción de clase {
privado :
int numerador, denominador ;
int LCM ( int x, int y ) ;
int GCD ( int x, int y ) ;
public :
Fraction () ;
Fracción ( int n ) ;
Fracción ( int n, int d ) throw ( std :: domain_error ) ;
606 – By Gerson
std:: string GetString ( vacío ) ;
doble GetValue ( nulo ) ;
Operador de fracciones! ( nulo ) ;
Operador de fracciones + ( Fracción arg ) ;
Operador de fracción * ( Fracción arg ) ;
Operador de fracción / ( Fracción arg ) throw ( std :: domain_error ) ;
Fracción y operador + = ( Fracción arg ) ;
};
std :: ostream & operator << ( std :: ostream & ostr, Fraction & f ) ;
#endif
8.4.9 Constructores
608 – By Gerson
8.4.10 GetString
609 – By Gerson
8.4.12 Agregar fracciones
610 – By Gerson
8.4.14 División de fracciones
611 – By Gerson
arg. numerador * common_denom / arg. denominador;
numerador = numera ;
denominador = common_denom ;
devuelve * esto ;
tester.cpp
# incluye "fracción.h"
#include <iostream>
usando el espacio de nombres estándar ;
int main ( void ) {
Fracción f1 ( 1 , 2 ) , f2 ( 2 , 3 ) , f ;
cout << f1 << "->" << f1. GetValue () << endl ;
cout << f2 << "->" << f2. GetValue () << endl ;
f = f1 + f2 ;
cout << f1 << "+" <<;
f = f2 + f2 + f2 ;
cout << f2 << "+" << f2 << "+" << f2 << "=" << f << endl ;
f =! f ;
cout << f2 << "+" << f2 << "+" << f2 << "=" << f << endl ;
f = f1 * f2 ;
cout << f1 << "*" << f2 << "=" << f << endl ;
613 – By Gerson
f = f1 / f2 ;
cout << f1 << ":" << f2 << "=" << f << endl ;
Fracción f3 ( 7, 8 ) ;
f3 + = f1 ;
cout << f3 << endl ;
devuelve 0 ;
}
614 – By Gerson
615 – By Gerson
616 – By Gerson