014 Programacion en c++
Transcript of 014 Programacion en c++
-
5/26/2018 014 Programacion en c++
1/55
8 Asignaciones compuestas con operadores de bits
Salvo el complemento a uno (~) que es unitario, los dems operadores de menejo de bits pueden
combinarse con la asignacin simple (=) para dar lugar a una asignacin compuesta( 4.9.2).
Recuerde que:
x &= y; // equivale a: x = (x & y);x ^= y; // equivale a: x = (x ^ y);x |= y; // equivale a: x = (x | y);x > y);
Ejemplo
#include
int main() {signed int x = 2, y = 7, z = 6, a = 2, b= -2;x &= -2;y ^= -2;z |= 13;a = 1;cout
-
5/26/2018 014 Programacion en c++
2/55
Comentario: en el cuadro se muestra un cuadro sinptico con los resultados de aplicar losoperadores AND, XOR y OR entre dos enteros caractersticos (los valores 0 y 1):
E101
01
E200
11
E1&E200
01
E1^E201
10
E1 |E201
11
9 En ocasiones los operadores de bits se utilizan para compactar la informacin, logrando que untipo bsico (por ejemplo un long) almacene magnitudes ms pequeas mediante
aprovechamientos parciales de los bits disponibles ( 2.2.4).
Considere el significado de las siguientes macros ( 4.9.10b)utilizadas por el compilador MSVisual C++ que expresan valores de color en programas MS Windows:
#define RGB(r,g,b)((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))24))
Comentario
Algunas de las etiquetas utilizadas (como COLORREF, DWORDo BYTE) son a su vez typedefs (
3.2.1a), muy comunes en la programacin para los entornos Windows ( Ejemplo).
Las expresiones del tipo (WORD)(w)son expresiones de modelado de tipos ( 4.9.9).
Observe la codificacin RGBen la que el color est representado por sus tres componentes [2]Rojo (Red), verde (Green) y azul (Blue). Est claro que los valores de cada componente puedenocupar un mximo de 8 bits en la expresin resultante, de forma que pueden estar comprendidos
entre 0 y 256 ( 0.1).
En la codificacin CMYKel color est representado por cuatro componentes: Cian (Cyan),magenta (Magenta), amarillo (Yellow) y negro (black). Los valores de cada componente puedenestar igualmente comprendidos entre 0 y 256, aunque el valor "resultante" es sensiblemente mayor
http://www.zator.com/Cpp/E2_2_4.htmhttp://www.zator.com/Cpp/E2_2_4.htmhttp://www.zator.com/Cpp/E2_2_4.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E3_2_1a.htmhttp://www.zator.com/Cpp/E3_2_1a.htmhttp://www.zator.com/Cpp/E3_2_1a.htmhttp://www.zator.com/Cpp/E3_2_1a1.htmhttp://www.zator.com/Cpp/E3_2_1a1.htmhttp://www.zator.com/Cpp/E3_2_1a1.htmhttp://www.zator.com/Cpp/E4_9_9.htm#Estilo%20cl%C3%A1sicohttp://www.zator.com/Cpp/E4_9_9.htm#Estilo%20cl%C3%A1sicohttp://www.zator.com/Cpp/E4_9_9.htm#Estilo%20cl%C3%A1sicohttp://www.zator.com/Cpp/E4_9_3.htm#[2]http://www.zator.com/Cpp/E4_9_3.htm#[2]http://www.zator.com/Cpp/E4_9_3.htm#[2]http://www.zator.com/Cpp/E0_1.htm#Sistema%20binariohttp://www.zator.com/Cpp/E0_1.htm#Sistema%20binariohttp://www.zator.com/Cpp/E0_1.htm#Sistema%20binariohttp://www.zator.com/Cpp/E0_1.htm#Sistema%20binariohttp://www.zator.com/Cpp/E4_9_3.htm#[2]http://www.zator.com/Cpp/E4_9_9.htm#Estilo%20cl%C3%A1sicohttp://www.zator.com/Cpp/E3_2_1a1.htmhttp://www.zator.com/Cpp/E3_2_1a.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E2_2_4.htm -
5/26/2018 014 Programacion en c++
3/55
que en la codificacin RGB. En ambos casos el resultado es modelado de forma que produzca
un COLORREF, que en dicho compilador corresponde a ununsigned long, cuyo tamao es de 4
bytes ( 4.9.13). Cuando una constante de este tipo est representada en hexadecimal, adopta lasiguiente forma:
COLORREF ulColor = 0x00bbggrr;
donde bb, ggy rrson respectivamente las componentes azul, verde y roja del color representado.
Naturalmente estos valores estn en el rango 00 - FF.
8.1 Ejemplo
#include using namespace std;typedef unsigned char BYTE;typedef unsigned short WORD;typedef unsigned long DWORD;typedef DWORD COLORREF;
#define RGB(r,g,b)((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))16))
int main() { // =================int r = 10, g = 20, b = 30;unsigned long rgbColor = RGB(r, g, b);cout
-
5/26/2018 014 Programacion en c++
4/55
An suponiendo que el lector no vaya a dedicarse a esto de la programacin y lo haga soloespordicamente, es ms que probable que antes o despus tenga que habrselas con el manejode bits individuales. Eso sin contar con que su utilizacin es constante en determinados entornos.Por ejemplo, cuando se programan sistemas embebidos ("Embedded Systems"); interfacesanalgico-digitales; sistemas de comunicaciones; de adquisicin de datos, Etc. Incluimos aqualgunos consejos, trucos y tecnicismos que le ayudarn a familiarizarse con el manejo de bits, algopor lo dems bastante sencillo cuando se dominan un par de trucos bsicos.
Nota: en el lenguaje informtico es frecuente utilizar la palabra "setear" (del ingls "set") paraindicar que uno, o todos los bits de una palabra, se ponen a uno, y limpiar ("Clear") parasealar que se ponen a cero. Aunque no est recogido en el diccionario de la AcademiaEspaola de la Lengua, utilizamos este anglicismo (setear) por ser ms breve que "poner auno".
2 Construir un patrn de bits
Es muy frecuente que las manipulaciones de bits requieran la construccin de un patrndeterminado ("bitmask"), que sirva como plantilla para comparaciones u operando de una
expresin. Por supuesto, la forma ms directa es escoger un nmero de longitud adecuada y echarmano de nuestros conocimientos de lgebra binaria para calcular el valor correspondiente delpatrn deseado. Por ejemplo, necesitamos una plantilla de 16 bits con el siguiente aspecto:
11011000 00010000
Podemos "sacar la cuenta" y llegar a la conclusin de que nuestra declaracin para el nmerodebe ser:
unsigne int X = 55312;
Cuando el patrn es ms largo, 32 o 64 bits, el clculo puede ser muy tedioso. Por ejemplo:
11111010 01011000 11011100 01100110
En estos casos no es necesario pasar el resto de la tarde para encontrar que correspondeexactamente con el unsigned long4200127590. Una alternativa es calcular el valor individual decada octeto y componer el resultado utilizando el operador OR inclusivo y los desplazamientosadecuados. En nuestro caso, el valor de los octetos (de izquierda a derecha) es: 250, 88, 220 y102. El nmero Xcorrespondiente a esa plantilla de bits es el siguiente:
unsigned long X = (250UL
-
5/26/2018 014 Programacion en c++
5/55
(unsigned char) 0x3 00000011
(unsigned char) 0x4 00000100
(unsigned char) 0x7 00000111
(unsigned char) 0x8 00001000
(unsigned char) 0xF 00001111
(unsigned char) 0x10 00010000
(unsigned char) 0x20 00100000
(unsigned char) 0x40 01000000
(unsigned char) 0x80 10000000
(unsigned short) 0xF 00000000 00001111
(unsigned int) 0xF00000000 00000000 00000000
00001111
(unsigned char) 0xFF 11111111
(unsigned short) 0xFF 00000000 11111111
(unsigned int) 0xFF00000000 00000000 00000000
11111111
(unsigned short) (0xFF
-
5/26/2018 014 Programacion en c++
6/55
(unsigned short) 0xFFF 00001111 11111111
(unsigned short) 0xFFFF 11111111 11111111
(unsigned int) 0xFFF
00000000 00000000 00001111
11111111
(unsigned int) 0xFFFF00000000 00000000 11111111
11111111
(unsigned int) (0xFF | 0xFF
-
5/26/2018 014 Programacion en c++
7/55
Y = X ^ M;
En nuestro caso:
unsigned int Y = X ^ (0xFF | 0xFF
-
5/26/2018 014 Programacion en c++
8/55
El problema es inverso al anterior: queremos que la resultante Rsea igual a la mscara M, con lasalvedad de que los bits que estuvieran seteados en P, sean limpiados (puestos a 0) en R.
R = M & (~P);
Si lo que queremos es modificar Men el sentido indicado, la expresin es:
M &= ~P;
7 Comprobar si un patrn encaja en una mscara
El problema consiste en verificar si los bits seteados (que estn a 1) en un patrn Ptienencorrespondencia con los bits correspondientes de una patrn M(tambin estn a 1 en M). Laverificacin cierto/falso, viene determinado por la expresin (M & P). Por ejemplo:
if ( M & P) ... // Encajaelse ... // No encaja
En las aplicaciones reales, es frecuente que los patrones y las mscaras estn identificadosmediante constantes cuyos valores se incluyen en "defines". Por ejemplo, en la programacinWindows, el estilo de una ventana est definido por un valor entero en el que cada uno de sus bitstiene un significado y efecto concreto. El programador puede componer un estilo particularcombinando los componentes individuales que estn definidos mediante constantes. Por ejemplo:
DWORD style = WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE |ES_WANTRETURN |
ES_AUTOVSCROLL | ES_NOHIDESEL,
Como indicbamos en la pgina anterior, DWORDes un typedefcuya traduccin exacta depende de
la plataforma, pero que probablemente ser traducida a un unsigned long. A su vez, las
constantes a la derecha (WS_CHILD | WS_VISIBLE | WS_VSCROLL, etc.) que determinan los
distintos componentes del estilo, estn definidas en los ficheros de cabecera de forma que sonDWORDs cuyos valores tienen un bit a uno y los dems a cero, por lo que son mltiplos de 2(dentro de la serie 1, 2, 4, 8, 16, 32, 64, etc). Al programador no le interesan sus valoresconcretos, solo sus nombres, que por lo dems son bastante descriptivos. Algunas caractersticasdel estilo pueden ser modificadas en runtime despus de creada la ventana, de forma que sonnormales trozos de cdigo como el que sigue:
DWORD style = GetWindowLong(hwnd, GWL_STYLE); // se obtiene el estilo deuna ventana
switch(mode) { // mode depende de una orden de usuario/* ... */case EDIT_UPPER: // orden de texto solo en maysculas
style &= ~ ES_LOWERCASE;style |= ES_UPPERCASE;break;
case EDIT_LOWER: // orden de texto solo en minsculasstyle &= ~ ES_UPPERCASE;style |= ES_LOWERCASE;break;
-
5/26/2018 014 Programacion en c++
9/55
case EDIT_NONE: // orden contenido de ventana no editablestyle &= ~(ES_UPPERCASE | ES_LOWERCASE);break;
}SetWindowLong(hwnd, GWL_STYLE, style); // establecer nuevo estilo deventana
8 Simplificacin de expresiones lgicas
Es frecuente que en la programacin de interfaces analgico/digitales; tarjetas de adquisicin dedatos; dispositivos embebidos; sistemas de comunicacin y dems parafernalia electrnica del tipocitado en la introduccin de este captulo, se utilicen expresiones lgicas que pueden resultar
bastante complicadas. De forma similar a cmo en una expresin del tipo a = b + 2c + 1.5b
-4c -3podemos simplificar y poner finalmente que a = 2.5b -2c -3, el lgebra lgica permite
utilizar ciertas identidades que pueden ayudarnos a la simplificacin de las expresiones
resultantes. En la tabla adjunta se muestran algunas de estas reglas [1].
!(!x) == xx | x == xx | !x == true!x | !y == !(x & y) //Teorema de DeMorgan!x & !y == !(x | y) //Teorema de DeMorganx & x == xx & !x == falsex | y == y | x //propiedad conmutativax & y == y & x //propiedad Conmutativa(x | y) | z == x | (y | x) //propiedad Asociativa(x & y) & z == x & (y & z) //propiedad Asociativax & y | x & z == x & (y | z) //propiedad Distributiva(x | y) & (x | x) == x | (y & z) //propiedad Distributiva
x | x & y == xx & y | x & !y == x(x & y) | (!x & z) | (y & z) == (x & y) | (!x & z)(x | y) & (!x | z) & (y | z) == (x | y) & (!x | z)x & (x | y) == x(x | y) & (x | !y) == x
4.9.5 Operador Coma
1 Sinopsis
En C++ la coma puede ser un elemento de puntuacin (separador de expresiones 3.2.6)y
unoperador, dando lugar a las denominadasexpresiones con coma( 4.10.5).
2 Sintaxis
expresion , expresion-de-asignacion
http://www.zator.com/Cpp/E4_9_3a.htm#[1]http://www.zator.com/Cpp/E4_9_3a.htm#[1]http://www.zator.com/Cpp/E4_9_3a.htm#[1]http://www.zator.com/Cpp/E3_2_6.htm#Comahttp://www.zator.com/Cpp/E3_2_6.htm#Comahttp://www.zator.com/Cpp/E4_10_5.htmhttp://www.zator.com/Cpp/E4_10_5.htmhttp://www.zator.com/Cpp/E4_10_5.htmhttp://www.zator.com/Cpp/E4_10_5.htmhttp://www.zator.com/Cpp/E3_2_6.htm#Comahttp://www.zator.com/Cpp/E4_9_3a.htm#[1] -
5/26/2018 014 Programacion en c++
10/55
3 Comentario
La coma separa elementos en las listas de parmetros de las funciones, tambin se usa como unoperador en las expresiones con coma. Es legal mezclar ambos usos, pero deben usarseparntesis para distinguirlas y evitar ambigedades. Por ejemplo, la expresin:
func(i, (j = 1, j + 4), k);
llama afunccon tres argumentos: (i, 5, k), no cuatro.
Cuando la coma se usa como operador, por ejemplo: E1, E2, el operando de la izquierdaE1esevaluado como una expresinvoid(no produce ningn resultado), despus se evala la
expresinE2de la derecha, su valor y tipo son los que toma la expresin de coma. Por recursin,
la expresin:E1, E2, ..., En, produce la evaluacin de izquierda a derecha de todas las
expresionesEiy la expresin total adopta el valor deEn.
Es el operador de precedencia ( 4.9.0a)ms baja de todos.
4 Ejemplos
sum = (i = 3, i++, i++); // sum = 4, i = 5func((exp1, exp2), (exp3, exp4, exp5)); // llama a func con dosargumentosreturn pass ? (puts("Acierto!"), 0) : (puts("Fallo!"), 1);
La invocacin afuncen la segunda lnea se realiza con dos argumentos, los resultadosdeexp2yexp5respectivamente.
En la tercera lnea, el programa devuelve 0 o 1 segn el valorpass, pero previamente indica elresultado en pantalla, ya que las dos alternativas conducen a la ejecucin de una expresin concoma.
El operador coma debe ser usado con moderacin y es frecuentemente utilizado en los
buclesforcomo en el ejemplo.
void reverse (char s[]) { // invertir la cadenasint c, i, j;for ( i = 0 , j = strlen(s)-1 ; i < j ; i++, j--) {
c = s[i], s[i] = s[j], s[j] = c;}
}
Como ejercicio, intente el lector desentraar la lgica de funcionamiento de la funcinreverse,que recibe una matriz de caracteres y la invierte. Como ayuda, tenga en cuenta que el
argumentodel bucle for ( 4.10.3), es una expresin con coma. Comocomplemento, intente figurarse como se utiliza la cadena resultante si la funcin se define como
devolviendovoid.
http://www.zator.com/Cpp/E4_9_0a.htmhttp://www.zator.com/Cpp/E4_9_0a.htmhttp://www.zator.com/Cpp/E4_9_0a.htmhttp://www.zator.com/Cpp/E4_10_3.htm#forhttp://www.zator.com/Cpp/E4_10_3.htm#forhttp://www.zator.com/Cpp/E4_10_3.htm#forhttp://www.zator.com/Cpp/E4_10_3.htm#forhttp://www.zator.com/Cpp/E4_9_0a.htm -
5/26/2018 014 Programacion en c++
11/55
Observe que esta posibilidad, incluir expresiones con coma en el argumento delos bucles, permite combinaciones muy interesantes y una notacin muy compacta, aunqueresultan algo crpticas en una primera lectura.
4.9.6 Operado r Cond icio nal
1 Sinopsis
El operador condicional es el nico operador ternario de la gramtica C++ y sirve para tomardecisiones. Proporciona un resultado entre dos posibilidades en funcin de una condicin.
Nota: Puede afirmarse que este operador ha hecho fortuna, ya que existe con la mismasintaxis e idntico comportamiento, en multitud de otros lenguajes de programacin.
2 Sintaxis
expresion-relacional ?expr1 : expr2
3 Comentario
El operador condicional ? :produce un resultado. En la expresin E1 ? E2 : E3, E1es una
expresin relacional ( 4.9.12)que se evala primero. Si el resultado es cierto, entonces se
evala E2y este es el resultado. En caso contrario (si E1resulta falso), entonces se evala E3y
este es el resultado. Observe que si la premisa E1es cierta, entonces no llega a evaluarse la
expresin E3.
3.1 El operador ? :puede usarse para sustituir ciertas sentencias del tipo if-then-else, aunque
puede conducir a expresiones ms compactas que las correspondientes if...else. En el ejemploque sigue, a yse le asigna el valor 100:
x = 10;y = x > 9 ? 100 : 200;
3.2 No es necesario poner parntesis en la primera expresin (E1), ya que la precedencia (
4.9.0a)de ? :es muy baja (justamente sobre la asignacin = ). De todos modos, es aconsejableponerlos por legibilidad.
y = (x > 9)? 100 : 200;
3.3 En caso de que E1no sea una expresin relacional, debe ser un escalar reducible a
un booleano(Conversin de tipos 3.2.1b). Por ejemplo es vlido:
int y = 6 ? 7: 8;
aunque en este caso el resultado sera siempre y == 7(el int6 se se traduce en el
booleano true).
http://www.zator.com/Cpp/E4_9_12.htmhttp://www.zator.com/Cpp/E4_9_12.htmhttp://www.zator.com/Cpp/E4_9_12.htmhttp://www.zator.com/Cpp/E4_9_0a.htmhttp://www.zator.com/Cpp/E4_9_0a.htmhttp://www.zator.com/Cpp/E4_9_0a.htmhttp://www.zator.com/Cpp/E3_2_1b.htm#Conversi%C3%B3n%20de%20tiposhttp://www.zator.com/Cpp/E3_2_1b.htm#Conversi%C3%B3n%20de%20tiposhttp://www.zator.com/Cpp/E3_2_1b.htm#Conversi%C3%B3n%20de%20tiposhttp://www.zator.com/Cpp/E4_9_0a.htmhttp://www.zator.com/Cpp/E4_9_12.htm -
5/26/2018 014 Programacion en c++
12/55
3.4 En ocasiones se aprovechan los efectos laterales ( 4.9)del operador para producir unresultado. Ejemplo:
++x ? ++y : --z;
El compilador GNU cpp permite la ausencia del segundo operando en este tipo de expresiones.Por ejemplo, es vlido:
x ? : z; // E1
El resultado de esta expresin es el valor de xsi este es distinto de cero, y zen caso contrario. Porconsiguiente, es equivalente a:
x ? x : z; // E2
El manual informa que este tipo de expresiones solo son de utilidad en caso de que la evaluacin
de xtenga efectos laterales (por ejemplo, que sea utilizada como argumento en una funcin), encuyo caso la expresin E2 tendra efecto lateral doble sixes distinto de cero. La omisin delsegundo operador en E1 evitara esta computacin indeseada y dejara el valor previamentecomputado sin que se produzca un doble efecto.
4 E2 y E3 deben seguir las reglassiguientes:
1. Si E2 y E3 son de tipos distintos, se realiza una conversin de tipo estndar, de forma queel resultado ser siempre del mismo tipo, con independencia de E1.
2. Si E2 y E3 son de tipos unin o estructuras compatibles. El resultado es una unin oestructura del tipo de E2 y E3.
3. Si E2 y E3 son de tipo void, el resultado es void.
4. Ambos operandos son punteros a versiones cualificadas o no cualificadas de tiposcompatibles. El resultado es un puntero a cualquiera de los tipos de ambos operandos.
5. Un operando es un puntero y el otro es un puntero nulo. El resultado es un puntero quepuede sealar a un tipo del primero o del segundo operando.
6. Un operando es un puntero a un objeto o tipo incompleto, y el otro es un puntero a unaversin cualificada o no cualificada de void. El tipo resultante es el del puntero distinto devoid.
5 Ejemplos
5.1 Suponiendo que ze ysean Lvalues, las siguientes expresiones son equivalentes:
(x ? y : z) = 10;(x ? y = 10 : (z = 10));
5.2 El bucle que sigue imprime nelementos de una matriz, 10 por lnea, con cada columna
separada por un espacio y con cada lnea terminada por un NL (nueva lnea), incluida la ltima.
for (i = 0; i < n; i++)printf ("%6d%c", a[i], (i%10==9 || i==n-1) ? '\n' : ' ');
http://www.zator.com/Cpp/E4_9.htmhttp://www.zator.com/Cpp/E4_9.htmhttp://www.zator.com/Cpp/E4_9.htmhttp://www.zator.com/Cpp/E4_9.htm -
5/26/2018 014 Programacion en c++
13/55
5.3 Ejemplo:
printf ( "Tienes %d item%s.\n", n, n==1 ? "" : "s");
5.4 Ejemplo:
#include #include
int main(void) { // ============time_t t;time(&t);struct tm* petm = localtime(&t);long dgt = _timezone/60;cout
-
5/26/2018 014 Programacion en c++
14/55
2 && Operador Y lgico
Tambin denominado por su nombre en ingls (generalmente en maysculas) AND lgico.
Devuelve un valor lgicotruesi ambos operandos son ciertos. En caso contrario el resultadoesfalse.
Sintaxis
expr-AND-logica&&expresion-OR-inclusive
Comentario:
La operatoria es como sigue: El primer operando (de la izquierda) es convertido a bool. Para ello,si es una expresin, se evala para obtener el resultado (esta computacin puede tener ciertos
efectos laterales). A continuacin, el valor obtenido es convertido aboolcierto/falso siguiendo las
reglas de conversin estndar ( 3.2.1b). Si el resultado esfalse, el proceso se detiene y este esel resultado, sin que en este caso sea necesario evaluar la expresin de la derecha (recurdeseque en el diseo de C++ prima la velocidad).
Si el resultado del operando izquierdo es cierto, se contina con la evaluacin de la expresin de la
derecha, que tambin es convertida abool. Si el nuevo resultado estrue, entonces el resultadodel operador estrue. En caso contrario el resultado esfalse.
Nota: la Norma informa que antes de ser evaluada la expresin derecha, han sucedido todoslos posibles efectos laterales de la expresin izquierda, a excepcin de la destruccin de losposibles objetos temporales que se hubiesen creado.
Ejemplo:
int m[3] = {0,1,2};int x = 0;if (m && x) cout
-
5/26/2018 014 Programacion en c++
15/55
else cout
-
5/26/2018 014 Programacion en c++
16/55
else cout
-
5/26/2018 014 Programacion en c++
17/55
SiEes una expresin,!Ees equivalente a (0==E). Como consecuencia, las expresiones quesiguen son equivalentes dos a dos:
if (! valid);if (valid == 0);
...if (valid);if (valid != 0);
7 Representacin explcita
Los operadores lgicos entre valores lgicos&&,||,!; la relacin de desigualdad!=; algunos de losoperadores lgicos entre bits (&,|,^,~) y sus expresiones compuestas (&=,|=,^=), tienen unarepresentacin realmente difcil de leer, con la desventaja adicional que sus smbolos no siempreestn fcilmente accesibles en ordenadores con teclados distintos del estndar USA. Para resolvereste problema, el Estndar C++ ha introducido nuevas formas para su representacin; lasdenominamos formas explcitas o naturales, en razn de que se parecen ms a las palabrascorrespondientes del lenguaje natural. Las nuevas formas constituyen palabras-clave, y la tabla deequivalencias es la siguiente:
Palabra claveSmboloReferencia Descripcin
and && Operador Y lgicoor || Operador O lgiconot ! Operador negacin lgicabitand & 4.9.3 Operador AND entre bitsxor
^ 4.9.3 Operador OR exclusivo entrebitsbitor
| 4.9.3 Operador OR inclusivo entrebitscompl
~ 4.9.3 Operador complemento auno de bitsand_eq
&= 4.9.3 Asignacin compuesta (ANDentre bits)xor_eq
^= 4.9.3 Asignacin compuesta (XORentre bits)
http://www.zator.com/Cpp/E4_9_3.htm#ANDhttp://www.zator.com/Cpp/E4_9_3.htm#ANDhttp://www.zator.com/Cpp/E4_9_3.htm#XORhttp://www.zator.com/Cpp/E4_9_3.htm#XORhttp://www.zator.com/Cpp/E4_9_3.htm#ORhttp://www.zator.com/Cpp/E4_9_3.htm#ORhttp://www.zator.com/Cpp/E4_9_3.htm#Complementohttp://www.zator.com/Cpp/E4_9_3.htm#Complementohttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_8.htmhttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_3.htm#Complementohttp://www.zator.com/Cpp/E4_9_3.htm#ORhttp://www.zator.com/Cpp/E4_9_3.htm#XORhttp://www.zator.com/Cpp/E4_9_3.htm#AND -
5/26/2018 014 Programacion en c++
18/55
or_eq|= 4.9.3 Asignacin compuesta (ORentre bits)
not_eq!= 4.9.12 Operador relacional dedesigualdad
Nota: ni el compilador Borland C++ 5.5 ni MS VC++ 6.0 soportan esta caracterstica del estndar,aunque el de Microsoft anuncia en su documentacin que pueden utilizarse "defines" (
4.9.10b). Por ejemplo:
#define bitand define bitor |#define and_eq &=#define or_eq |=#define not_eq !=
Por su parte, el compilador GNU gcc dispone de la opcin de compilacin -fno-operator-names,que permite que las palabras-claveand,bitand,bitor,compl,not, yor,nosean tratadas comosinnimos de los operadores correspondientes.
Temas relacionados:
Trigrafos y digrafos ( 3.2.3e)
Sobrecarga de los operadores lgicos ( 4.9.18g).
4.9.9 Modelado de tipo s
1 Sinopsis:
Elmodelado de tipos("typecasting") es el proceso de convertir o promover un objeto de un tipo aotro. Esta operacin es necesaria y frecuente en programacin; incluso es realizada infinidad deveces por el compilador de forma automtica y transparente para el programador, y ocurre cuando
este la solicita deforma implcita. Por ejemplo, cuando una funcin en cuyo prototipo se hadeclarado que espera unfloatcomo argumento y le pasamos un entero, o cuando necesitamossumar unintcon undouble. En todos estos casos, el compilador realiza automticamente una
conversin de tipo para que el argumento pasado concuerde con el esperado ( 4.4.6). En el
caso de operaciones aritmticas, la conversin intenta conseguir la menor prdida de precisinposible en las operaciones ( 2.2.5).
En otros casos, que tratamos en este captulo, la necesidad de modelado es indicada en el cdigo
deforma explcita, utilizando los recursos que proporciona el lenguaje con este propsito.
2 Precauciones:
http://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuestahttp://www.zator.com/Cpp/E4_9_12.htmhttp://www.zator.com/Cpp/E4_9_12.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E3_2_3e.htm#Trigrafoshttp://www.zator.com/Cpp/E3_2_3e.htm#Trigrafoshttp://www.zator.com/Cpp/E3_2_3e.htm#Trigrafoshttp://www.zator.com/Cpp/E4_9_18g.htmhttp://www.zator.com/Cpp/E4_9_18g.htmhttp://www.zator.com/Cpp/E4_9_18g.htmhttp://www.zator.com/Cpp/E4_4_6.htmhttp://www.zator.com/Cpp/E4_4_6.htmhttp://www.zator.com/Cpp/E4_4_6.htmhttp://www.zator.com/Cpp/E2_2_5.htm#Conversiones%20aritm%C3%A9ticas%20est%C3%A1ndarhttp://www.zator.com/Cpp/E2_2_5.htm#Conversiones%20aritm%C3%A9ticas%20est%C3%A1ndarhttp://www.zator.com/Cpp/E2_2_5.htm#Conversiones%20aritm%C3%A9ticas%20est%C3%A1ndarhttp://www.zator.com/Cpp/E2_2_5.htm#Conversiones%20aritm%C3%A9ticas%20est%C3%A1ndarhttp://www.zator.com/Cpp/E4_4_6.htmhttp://www.zator.com/Cpp/E4_9_18g.htmhttp://www.zator.com/Cpp/E3_2_3e.htm#Trigrafoshttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_12.htmhttp://www.zator.com/Cpp/E4_9_3.htm#Asignacion-compuesta -
5/26/2018 014 Programacion en c++
19/55
No olvidar que, cuando forzamos una conversin de tipo explcita o implcita, estamosquebrantando deliberadamente uno de los sistemas de seguridad de C++, basado precisamente enla comprobacin de tipos. El modelado puede ser causa de problemas, en especial (aunque noexclusivamente) cuando se trata de punteros. Por tanto, se recomienda usarlo con moderacin ysolo para resolver necesidades puntuales.
No obstante lo anterior, es evidente que determinadas conversiones, como las que realiza elcompilador automticamente con tipos numricos, no presentan a veces ningn problema; todo loms prdidas de precisin. Sobre todo cuando la conversin se realiza en el sentido de nmerocon ms precisin a los de menos. Por ejemplo, el compilador puede realizar automticamente unaconversin de tipo para realizar las asignaciones:
short s = 33;long n = s;float f = s;
sin que exista prdida de precisin, puesto quelongyfloatpueden albergar a todos losshort(
2.2.4). Este tipo de promocin se denominaconversin ensanchante. Sin embargo, lasconversiones en el sentido del tipo de ms precisin al de menos (conversin estrechante),
puede resultar en una prdida de informacin o incluso en errores peligrosos. Considere la salidadel ejemplo siguiente:
#include
int main() {unsigned long ul = 5000;long l = ul; int y = ul; short s = ul;cout
-
5/26/2018 014 Programacion en c++
20/55
un puente; en un monitor de electromedicina; el mezclador en una fbrica de alimentos, osimplemente durante la confeccin de nminas en el programa de administracin de una empresa[2].
Otro ejemplo de conversin estrechante que conduce a un resultado aparentemente contradictorio
en 2.2.4a.
Tampoco existe ninguna advertencia respecto de la salida obtenida en el ejemplo de promocin de
un entero a variable de enumeracin ( 4.9.9b), que fuerza al compilador a proporcionar unresultado evidentemente errneo.
En general son potencialmente peligrosas las conversiones de tipo cuando ambos no utilizan el
mismo tipo de alineacin interna ( 4.5.9a). Tambin cuando se trata de punteros ( 4.9.9d)
3 Dos tipos
Como se ha indicado, en C++ existen dos tipos de modelado:implcitoyexplcito. El primero esrealizado automticamente por el compilador cuando se mezclan tipos. Por ejemplo, las mentadasconversiones numricas, que permiten operaciones aritmticas entre tipos distintos. El segundo serealiza cuando el programador utiliza explcitamente el operador de modelado.
Aunque no sea estrictamente necesario, se recomienda como regla de buena prctica, utilizardeclaraciones explcitas incluso en los casos de modelado implcito [1]. Sobre todo cuando sequiera poner nfasis en la conversin realizada. Por ejemplo:
int x = 10;float fl = 10.0;int y = x + fl; // Ok. modelado implcitoint z = x + static_cast(fl); // Mejor !!
Aparte de que el cdigo resultante es mucho ms explcito, esta prctica facilita la depuracin deposibles errores derivados de la mixtura de tipos.
4 Dos estilos
En el C++ Estndar coexisten dos formas de sintaxis para modelado: la nueva y la clsica(heredada de C), aunque esta ltima se desaconseja y est considerada como prctica a extinguir("Deprecated").
Nota: el compilador GNU gcc dispone de la opcin-Wold-style-cast, que muestra un mensajede aviso si se utiliza el viejo estilo.
4.1 Estilo C++ de modelado
La nueva sintaxis utiliza cuatro palabras clave especficas
(static_cast, reinterpret_cast, dynamic_castyconst_cast) y una sintaxis que se presta menosa confusin que la clsica (ver a continuacin). Aparte de la anterior, las razones argumentadas enfavor del nuevo estilo es que es menos propenso a obtener resultados indeseados y ms fcil delocalizar su ocurrencia en el cdigo.
http://www.zator.com/Cpp/E4_9_9.htm#[2]http://www.zator.com/Cpp/E4_9_9.htm#[2]http://www.zator.com/Cpp/E4_9_9.htm#[2]http://www.zator.com/Cpp/E2_2_4a.htm#Ref-2http://www.zator.com/Cpp/E2_2_4a.htm#Ref-2http://www.zator.com/Cpp/E4_9_9b.htm#Peligro-1http://www.zator.com/Cpp/E4_9_9b.htm#Peligro-1http://www.zator.com/Cpp/E4_9_9b.htm#Peligro-1http://www.zator.com/Cpp/E4_6_1.htmhttp://www.zator.com/Cpp/E4_6_1.htmhttp://www.zator.com/Cpp/E4_6_1.htmhttp://www.zator.com/Cpp/E4_9_9d.htm#Ejemplo-1http://www.zator.com/Cpp/E4_9_9d.htm#Ejemplo-1http://www.zator.com/Cpp/E4_9_9d.htm#Ejemplo-1http://www.zator.com/Cpp/E4_9_9.htm#[1]http://www.zator.com/Cpp/E4_9_9.htm#[1]http://www.zator.com/Cpp/E4_9_9.htm#[1]http://www.zator.com/Cpp/E4_9_9.htm#[1]http://www.zator.com/Cpp/E4_9_9d.htm#Ejemplo-1http://www.zator.com/Cpp/E4_6_1.htmhttp://www.zator.com/Cpp/E4_9_9b.htm#Peligro-1http://www.zator.com/Cpp/E2_2_4a.htm#Ref-2http://www.zator.com/Cpp/E4_9_9.htm#[2] -
5/26/2018 014 Programacion en c++
21/55
4.1 Estilo clsico de modelado
Es el estilo heredado de C que se mantiene por compatibildad, tiene dos variedades de notacin,aunque el nuevo Estndar C++ lo desaconseja en favor del nuevo estilo.
Sintaxis:
()()
Comentario
El valor dese convierte al tipo definido porsiguiendo lasreglas estndar de conversin. Por ejemplo, la funcin de la Librera Estndarsqrt() esperaundoublecomo argumento, si queremos utilizarla con unintn, se puede utilizar cualquiera de lasexpresiones siguientes:
sqrt((double) n); // primera forma de la sintaxissqrt(double (n)); // segunda forma de la sintaxis
Observe quenno se altera, ya que la conversin se realiza antes de pasar el argumento a lafuncin. Observe tambin que si los parmetros se han especificado en el prototipo de la funcin,esta conversin de argumento no sera necesaria, ya que el compilador realiza automticamente elmodelado correspondiente.
Las expresiones que siguen son vlidas en C++:
double peso = 25;int * ptr;
ptr = (int *)&peso;cout
-
5/26/2018 014 Programacion en c++
22/55
A::A(B b) { /* asignacin */ }
Ver comentarios y aclaraciones al respecto en: Constructores de conversin ( 4.11.2d1)
Tema relacionado
Sobrecarga del operador de modelado ( 4.9.18k)
4.9.9a El operad or co nst _cast
1 Sinopsis:
La palabra claveconst_castidentifica un operador de uso muy especfico: sirve para poner oquitar los atributosconstovolatilede un objeto. La sintaxis general es:
const_cast< T > (arg)
En la expresin anterior,Tyargdeben ser del mismo tipo, excepto en los atributosconst(
3.2.1c) yvolatile( 4.1.9).Tes el tipo al que se quiere convertir,arges el tipo de partida(ver ejemplo). El modelado es resuelto en tiempo de compilacin, y el resultado es del tipo T. Unasola expresinconst_castpuede poner o quitar el atributoconstovolatilea cualquier nmerode objetos.
Ejemplo
const int x = 10;int* iptr = &x; // Error!!
Un intento de compilar las sentencias anteriores conduce a un error del compilador:
invalid conversion from `const int*' to `int*'
La razn es que se est intentando asignar la direccin de un int-consta un puntero-a-int, cuandose necesitara un puntero-a-int-const. Suponiendo que no queramos (o podamos) cambiar la
definicin deiptr, el problema de la asignacin en la segunda lnea puede resolverse medianteun "casting" adecuado:
const int x = 23;int* iptr = const_cast (&x); // Ok!!
2 cons_cast con punteros
El cambio de atributo puede utilizarse con punteros, de forma que un puntero a-tipoX-
constantepuede ser convertido en puntero a-tipoXy viceversa. El cambio tambin puederealizarse con un puntero a-tipoX-volatile.
http://www.zator.com/Cpp/E4_11_2d1.htm#Constructores%20de%20conversi%C3%B3nhttp://www.zator.com/Cpp/E4_11_2d1.htm#Constructores%20de%20conversi%C3%B3nhttp://www.zator.com/Cpp/E4_11_2d1.htm#Constructores%20de%20conversi%C3%B3nhttp://www.zator.com/Cpp/E4_9_18k.htmhttp://www.zator.com/Cpp/E4_9_18k.htmhttp://www.zator.com/Cpp/E4_9_18k.htmhttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E4_9_18k.htmhttp://www.zator.com/Cpp/E4_11_2d1.htm#Constructores%20de%20conversi%C3%B3n -
5/26/2018 014 Programacion en c++
23/55
-
5/26/2018 014 Programacion en c++
24/55
En la expresin anterior,Tyargdeben ser del mismo tipo, excepto en los atributos const(
3.2.1c) yvolatile( 4.1.9).Tes el tipo al que se quiere convertir,arges el tipo de partida
(ver ejemplo). El modelado es resuelto en tiempo de compilacin, y el resultado es del tipo T. Unasola expresinconst_castpuede poner o quitar el atributoconstovolatilea cualquier nmerode objetos.
Ejemplo
const int x = 10;int* iptr = &x; // Error!!
Un intento de compilar las sentencias anteriores conduce a un error del compilador:
invalid conversion from `const int*' to `int*'
La razn es que se est intentando asignar la direccin de un int-consta un puntero-a-int, cuandose necesitara un puntero-a-int-const. Suponiendo que no queramos (o podamos) cambiar la
definicin deiptr, el problema de la asignacin en la segunda lnea puede resolverse medianteun "casting" adecuado:
const int x = 23;int* iptr = const_cast (&x); // Ok!!
2 cons_cast con punteros
El cambio de atributo puede utilizarse con punteros, de forma que un puntero a-tipoX-
constantepuede ser convertido en puntero a-tipoXy viceversa. El cambio tambin puederealizarse con un puntero a-tipoX-volatile.
El puntero obtenido es idntico al original en todos los dems aspectos. Si la conversin tiene xitoel puntero resultante seala al mismo objeto que el original. Ejemplo:
const int kte = 35;int* ptr;ptr = &kte; // Error!ptr = (int*) &kte; // modelado antiguo desaconsejadoptr = const_cast (&kte); // Ok:volatile int x = 45;ptr = &x; // Error!ptr = const_cast (&x); // Ok:
As pues, este operador convierte un objeto (o referencia a objeto)constovolatileen un objeto (oreferencia) no-consto no-volatileque es idntico en lo dems al original.
Es importante advertir que el operadorconst_castno cambia el tipodel operando, lo quesignifica que este operador no hace que una variable constante pueda volverse no-constante y veralterado su valor despus de aplicado el operador. Considere detenidamente el resultado obtenidoen el siguiente ejemplo, e intente llegar a una explicacin (recuerde lo sealado al respecto
en 4.2.1e).
http://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_2_1e.htm#Ref-1http://www.zator.com/Cpp/E4_2_1e.htm#Ref-1http://www.zator.com/Cpp/E4_2_1e.htm#Ref-1http://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E3_2_1c.htm -
5/26/2018 014 Programacion en c++
25/55
#include
int main() {const int x = 35; // constante iniciada a 35int* ptr; // puntero a enteroptr = const_cast (&x); // Ok: (gracias al 'casting')cout
-
5/26/2018 014 Programacion en c++
26/55
const int x = 23;int* iptr = const_cast (&x); // Ok!!
2 cons_cast con punteros
El cambio de atributo puede utilizarse con punteros, de forma que un puntero a-tipoX-constantepuede ser convertido en puntero a-tipoXy viceversa. El cambio tambin puederealizarse con un puntero a-tipoX-volatile.
El puntero obtenido es idntico al original en todos los dems aspectos. Si la conversin tiene xitoel puntero resultante seala al mismo objeto que el original. Ejemplo:
const int kte = 35;int* ptr;ptr = &kte; // Error!ptr = (int*) &kte; // modelado antiguo desaconsejadoptr = const_cast (&kte); // Ok:volatile int x = 45;
ptr = &x; // Error!ptr = const_cast (&x); // Ok:
As pues, este operador convierte un objeto (o referencia a objeto)constovolatileen un objeto (oreferencia) no-consto no-volatileque es idntico en lo dems al original.
Es importante advertir que el operadorconst_castno cambia el tipodel operando, lo quesignifica que este operador no hace que una variable constante pueda volverse no-constante y veralterado su valor despus de aplicado el operador. Considere detenidamente el resultado obtenidoen el siguiente ejemplo, e intente llegar a una explicacin (recuerde lo sealado al respecto
en 4.2.1e).
#include
int main() {const int x = 35; // constante iniciada a 35int* ptr; // puntero a enteroptr = const_cast (&x); // Ok: (gracias al 'casting')cout
-
5/26/2018 014 Programacion en c++
27/55
4.9.9a El operad or co nst _cast
1 Sinopsis:
La palabra claveconst_castidentifica un operador de uso muy especfico: sirve para poner o
quitar los atributosconstovolatilede un objeto. La sintaxis general es:
const_cast< T > (arg)
En la expresin anterior,Tyargdeben ser del mismo tipo, excepto en los atributos const(
3.2.1c) yvolatile( 4.1.9).Tes el tipo al que se quiere convertir,arges el tipo de partida(ver ejemplo). El modelado es resuelto en tiempo de compilacin, y el resultado es del tipo T. Unasola expresinconst_castpuede poner o quitar el atributoconstovolatilea cualquier nmerode objetos.
Ejemplo
const int x = 10;int* iptr = &x; // Error!!
Un intento de compilar las sentencias anteriores conduce a un error del compilador:
invalid conversion from `const int*' to `int*'
La razn es que se est intentando asignar la direccin de un int-consta un puntero-a-int, cuandose necesitara un puntero-a-int-const. Suponiendo que no queramos (o podamos) cambiar la
definicin deiptr, el problema de la asignacin en la segunda lnea puede resolverse medianteun "casting" adecuado:
const int x = 23;int* iptr = const_cast (&x); // Ok!!
2 cons_cast con punteros
El cambio de atributo puede utilizarse con punteros, de forma que un puntero a-tipoX-
constantepuede ser convertido en puntero a-tipoXy viceversa. El cambio tambin puederealizarse con un puntero a-tipoX-volatile.
El puntero obtenido es idntico al original en todos los dems aspectos. Si la conversin tiene xitoel puntero resultante seala al mismo objeto que el original. Ejemplo:
const int kte = 35;int* ptr;ptr = &kte; // Error!ptr = (int*) &kte; // modelado antiguo desaconsejadoptr = const_cast (&kte); // Ok:volatile int x = 45;ptr = &x; // Error!ptr = const_cast (&x); // Ok:
http://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E3_2_1c.htmhttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E4_1_9.htm#volatilehttp://www.zator.com/Cpp/E3_2_1c.htm -
5/26/2018 014 Programacion en c++
28/55
As pues, este operador convierte un objeto (o referencia a objeto)constovolatileen un objeto (oreferencia) no-consto no-volatileque es idntico en lo dems al original.
Es importante advertir que el operadorconst_castno cambia el tipodel operando, lo quesignifica que este operador no hace que una variable constante pueda volverse no-constante y veralterado su valor despus de aplicado el operador. Considere detenidamente el resultado obtenidoen el siguiente ejemplo, e intente llegar a una explicacin (recuerde lo sealado al respecto
en 4.2.1e).
#include
int main() {const int x = 35; // constante iniciada a 35int* ptr; // puntero a enteroptr = const_cast (&x); // Ok: (gracias al 'casting')cout
-
5/26/2018 014 Programacion en c++
29/55
4 Descripcin
es el tipo al que se convertir (resultado del modelado); puede ser cualquiera de los
siguientes: puntero ( 4.2); referencia ( 4.2.3); tipo aritmtico ( 2.2.1)o enumeracin (
4.7). Este operando se denomina tipodel modelado.
arges el objeto cuyo tipo se desea convertir; debe ser asimilable al tipo de T(aqu no se
pueden pedir imposibles); este operando se denominaargumentodel modelado. Ambos
operandos, el argumento y el tipo (argy T), deben estar totalmente definidos en tiempo de
compilacin.
5 Si un tipo puede ser convertido en otro mediante algn sistema proporcionadoautomticamente por el lenguaje, utilizar la promocin explcita mediante este operador conduceexactamente al mismo resultado. Por ejemplo:
int x = 10;float f1 = x; // promocin facilitada por el compilador
float f2 = static_cast (x); // promicin explcita (preferible)
6 Los enteros (int) pueden ser convertidos a enumeraciones (enum), pero tenga muy presenteque cualquier intento de promover el argumento a un valor que no sea un elemento de laenumeracin (enumerando), proporciona un resultado indefinido. Considere las dos salidas delejemplo compilado con C++Builder:
#include
int main() {enum COLOR { ROJO, VERDE, AZUL};COLOR c1 = VERDE;
cout
-
5/26/2018 014 Programacion en c++
30/55
El puntero nulo ( 4.2.1)es convertido a s mismo.
El puntero a un objeto tipoXpuede ser promovido a puntero a cualquier otro tipoY, pero tenga encuenta que la mera promocin entre tipos de punteros puede ser motivo de problemas si los tiposequivalentes no estn alineados de forma similar.
El resultado de la conversin esttica de un puntero es otra referencia al objeto original.
Es posible convertir explcitamente, mediante una conversin esttica, un puntero a clase-Xapuntero a una clase-Y, si se dan las siguientes condiciones:
Xes una clase base paraY.
Existe una conversin sin ambigedades deYa X
Xno es una clase-base virtual
Un objeto puede ser convertido explcitamente a referencia-a-tipoX si un puntero a tal objeto puedeser explcitamente convertido a puntero-a-tipoX (tipoX*). El resultado de la conversin es un
Lvalue. No son invocados constructores o funciones de conversin como resultado de unmodelado a una referencia.
Un objeto o un valor puede ser convertido a un objeto clase, solo en el caso de que se hayandeclarado en la clase un constructor o un operador de conversin adecuados.
Un puntero a miembro (de clase) puede ser convertido explcitamente en puntero a otro tipo demiembro solo si ambos tipos son punteros a miembros de la misma clase, o punteros a miembrosde dos clases, una de las cuales es derivada sin ambigedades de la otra.
8 Convertir a referencia
Cuando el tipo Tes una referencia, el resultado del modelado esttico es un Lvalue y se refiere a la
expresin original, aunque este tipo de transformaciones puede resultar peligroso ( 4.2.3).
4.9.9c El operador dynamic _cast
Nota: El operador dynamic_castse refiere a conversiones de punteros y refencias aclases, por lo que su estudio exige un buen conocimiento previo de muchos conceptosrelacionados con ellas. Recomendamos al estudiante continuar con el estudio de las clases (
4.11)antes de volver a este operador concreto.
1 Sinopsis
Como se ha indicado, este operador est reservado para conversiones de/hacia punteros yreferencias a clases, aunque exige que los punteros y referencias se refieran a clases de la mismajerarqua. De no cumplirse este condicin, la conversin es imposible y segn los casos, eloperador produce un resultado nulo o lanza una excepcin.
Para entender los conceptos involucrados se hacen necesarias algunas puntualizacionessemnticas previas; recordemos que cuando se trata de clases emparentadas (pertenecientes auna jerarqua), hay que distinguir los casos en que las conversiones ("cast") entre punteros o
http://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulohttp://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulohttp://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulohttp://www.zator.com/Cpp/E4_2_3.htm#Modelado:http://www.zator.com/Cpp/E4_2_3.htm#Modelado:http://www.zator.com/Cpp/E4_2_3.htm#Modelado:http://www.zator.com/Cpp/E4_11.htmhttp://www.zator.com/Cpp/E4_11.htmhttp://www.zator.com/Cpp/E4_11.htmhttp://www.zator.com/Cpp/E4_2_3.htm#Modelado:http://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulo -
5/26/2018 014 Programacion en c++
31/55
referencias se realizan en sentido descendente ("Down") desde las clases-base hacia lasderivadas, o ascendente ("Up"), desde las clases-derivada hacia las superclases [1]. El primero esel sentido desde los antepasados a los descendientes; el segundo desde los descendientes a losancestros. Las conversiones en sentido descendente se denominan downcast, y lascontrarias upcast. Finalmente, cuando la conversin se da entre clases hermanas, sedenomina crosscast(modelado de cruce) [2].
2 Sintaxis
dynamic_cast (arg);
3 Comentario
El operando , denominado tipo, determina el resultado de la operacin, y debe ser un
puntero ( 4.2.1f)o referencia ( 4.2.3)a una clase definida, o un puntero genrico void*(
4.2.1d).
El operando argrecibe el nombre de argumento, es el tipo que se quiere convertir, y debe seruna expresin que se resuelva en un puntero o una referencia (este operador no se puede aplicara otros tipos).
El resultado del operador es un puntero o referencia del mismo valor que arg, apuntando o
referenciando al mismo objeto, pero del tipo expresado por . Este operador se utiliza
principalmente para realizar asignaciones que de otro modo no seran legales por diferencia detipos entre el Lvalue y el Rvalue.
Para utilizar este operador es necesaria la capacidad RTTI (Runtime type
identification 4.9.14).; As pues, los ejemplos en los que aparezca el
operador dynamic_castdeben ser compilados con la opcin -RT[4]
4 Ejemplos
class Clase1 { ... } c1, *c1ptr;class Clase2 { ... } c2, *c2ptr = &c2, &ref2 = c2;...c1ptr = dynamic_cast(c2ptr); // L.4:Clase1& ref1 = dynamic_cast(ref2); // L.5:
5 C++ exige que el donwcasto crosscastse realicen desde una clase polimrfica ( 4.11.8),
de modo que argdebe ser de este tipo [3]. Sin embargo, el resultado de este modelado puede ser
aplicado a un puntero o referencia a clase no polimrfica.
En el ejemplo anterior, si Clase2no fuese polimrfica (no tuviese una funcin virtual), en L4 y L.5
se obtendran sendos errores:
Type 'Clase2' is not a defined class with virtual functions in...
pero Clase1no tiene que serlo necesariamente para poder realizar las asignaciones anteriores.
http://www.zator.com/Cpp/E4_9_9c.htm#[1]http://www.zator.com/Cpp/E4_9_9c.htm#[1]http://www.zator.com/Cpp/E4_9_9c.htm#[1]http://www.zator.com/Cpp/E4_9_9c.htm#[2]http://www.zator.com/Cpp/E4_9_9c.htm#[2]http://www.zator.com/Cpp/E4_9_9c.htm#[2]http://www.zator.com/Cpp/E4_2_1f.htmhttp://www.zator.com/Cpp/E4_2_1f.htmhttp://www.zator.com/Cpp/E4_2_1f.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E4_2_1d.htmhttp://www.zator.com/Cpp/E4_2_1d.htmhttp://www.zator.com/Cpp/E4_2_1d.htmhttp://www.zator.com/Cpp/E4_9_14.htm#Opci%C3%B3n%20-RThttp://www.zator.com/Cpp/E4_9_14.htm#Opci%C3%B3n%20-RThttp://www.zator.com/Cpp/E4_9_9c.htm#[4]http://www.zator.com/Cpp/E4_9_9c.htm#[4]http://www.zator.com/Cpp/E4_9_9c.htm#[4]http://www.zator.com/Cpp/E4_11_8.htmhttp://www.zator.com/Cpp/E4_11_8.htmhttp://www.zator.com/Cpp/E4_11_8.htmhttp://www.zator.com/Cpp/E4_9_9c.htm#[3]http://www.zator.com/Cpp/E4_9_9c.htm#[3]http://www.zator.com/Cpp/E4_9_9c.htm#[3]http://www.zator.com/Cpp/E4_9_9c.htm#[3]http://www.zator.com/Cpp/E4_11_8.htmhttp://www.zator.com/Cpp/E4_9_9c.htm#[4]http://www.zator.com/Cpp/E4_9_14.htm#Opci%C3%B3n%20-RThttp://www.zator.com/Cpp/E4_2_1d.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E4_2_1f.htmhttp://www.zator.com/Cpp/E4_9_9c.htm#[2]http://www.zator.com/Cpp/E4_9_9c.htm#[1] -
5/26/2018 014 Programacion en c++
32/55
6 Si es un puntero genrico void*, el argumento argdebe ser tambin un puntero. En estecaso, el puntero resultante puede acceder a cualquier elemento de la clase que sea el elementoms derivado de la jerarqua. Tal clase no puede ser clase-base para ninguna otra.
7 Las conversiones de una clase derivada a clase-base (upcast) o de una clase derivada a otra(crosscast), se realiza como sigue: si Tes un puntero y ptres un puntero a una clase no-bsicade una jerarqua, el resultado es un puntero a la subclase nica. Las referencias son tratadas deforma similar: si Tes una referencia y ptres una referencia a una clase no bsica, el resultado esuna referencia a la subclase nica.
8 La convesin upcast, de una clase derivada a una clase-base se resuelve en tiempo decompilacin. Por contra, la conversin downcast, de una clase-base a clase-derivada, o a travsde una jerarqua de clases, es resuelta en tiempo de ejecucin. Es decir:
a.- Conversiones en tiempo de compilacin:
subclase* superclase*
subclase& superclase&b.- Conversiones en tiempo de ejecucin:
subclase* superclase*
subclase& superclase&
El resultado es que, en caso de haberlos, los errores de los modelados a.sern anunciados por elcompilador. En cambio, los del tipo b.solo sern detectados en ejecucin.
9 Si en la conversin de un puntero, el operador dynamic_cast< T> (ptr) tiene xito,proporciona un puntero sealando al mismo objeto que el argumento ptr, pero del tipo Trequerido.En cambio, si la conversin falla, el puntero obtenido es del tipo Tdeseado, pero se le asigna cero.
En otras palabras, si el modelado de un puntero falla, se obtiene el puntero nulo( 4.2.1). Porcontra, si falla la conversin a una referencia, se lanza la excepcin bad_cast.
Lo anterior significa que los modelados de este tipo con punteros deben ser comprobados
siempre explcitamente para verificar que ptr!= 0 (ver lneas 16 y 22 del ejemplo ). En cambio,
para verificar el xito del modelado de referencias basta el mecanismo de excepciones ( 1.6).
10 Ejemplo
En el programa que sigue se realizan modelados a travs de toda la jerarqua. Primero de realizael downcastde un puntero desde la clase base a la ms derivada, despus se realiza
un upcastpara volver a otra base superior.
#include #include
class Base1 {virtual void f(void) { /* ... */ } // L.5:
};
class Base2 { };
http://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulohttp://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulohttp://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulohttp://www.zator.com/Cpp/E1_6.htmhttp://www.zator.com/Cpp/E1_6.htmhttp://www.zator.com/Cpp/E1_6.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E4_9_9c.htmhttp://www.zator.com/Cpp/E1_6.htmhttp://www.zator.com/Cpp/E4_2_1.htm#Puntero%20nulo -
5/26/2018 014 Programacion en c++
33/55
class Derived : public Base1, public Base2 { };
int main(void) { // ==========================try {Derived d, *pd;Base1* b1 = &d; // L.14:pd = dynamic_cast(b1); // L.15:if (pd != 0) {
cout
-
5/26/2018 014 Programacion en c++
34/55
En L.21, a b2(que es tipo Base2*) se le asigna la direccin sealada por b1. En esta asignacin
ni la direccin ni el tipo son correctos. En primer lugar, b1seala a un objeto tipo Derived.
Adems, b1es tipo Base1*. En consecuencia, se necesita un modelado al tipo de b2. Este
modelado debe recorrer toda la jerarqua de clases, descendiendo (downcast) desde el
tipo Base1*a la del tipo ms derivado Derived*; despus ascendiendo (upcast) desde el
tipo derived*al tipo Base2*.
En L.35 se anuncia la finalizacin normal del programa. En cambio, las terminaciones L.29 y L.33son terminaciones anormales, por lo que devuelven un valor distinto de cero al SO.
11 Comprobacin de parentesco
Dentro de las limitaciones sealadas (que se realice sobre clases polimrficas), la circunstancia de
que el operador dynamic_castsolo funcione entre miembros de una jerarqua, es utilizado amenudo como un recurso para comprobar si dos objetos pertenecen o no a una misma familia.
Por ejemplo, supongamos que tenemos un objeto apertenecientes a la clases A. Para comprobar
si pertenece a una subclase de B(si Aderiva deB), podra utilizarse el siguiente cdigo:
if (dynamic_cast(&a)) {/* A es derivada de B */
} else {/* A no deriva de B */
}
4.9.9d Op erador reinterpr et_cast
1 Sinopsis
Las conversiones de tipo que se realizan con este operador podramos decir que son por la "fuerzabruta". Obligamos al compilador a aceptar un tipo de objeto por otro sin rechistar, por muy ilgicaque sea la transformacin (de ah el nombre).
Ni que decir tiene que tales transformaciones son de lo ms peligroso y que deben ser realizadascon extrema precaucin. En realidad se suelen utilizar solo de forma temporal, para realizar
determinadas transformaciones en los objetos [1]y volver a interpretarlos en su sentido original.Aunque en ocasiones est perfectamente justificado, su util izacin puede ser sntoma de unatcnica deficiente o de que el programador se est metiendo en problemas.
2 Sintaxis
reinterpret_cast (arg)
3 Descripcin
El operando (denominado tipo), determina el resultado de la conversin. Puede ser cualquiera
de los tipos siguientes: puntero ( 4.2); referencia ( 4.2.3); tipo aritmtico ( 2.2.1); puntero
a funcin ( 4.2.4), o puntero a miembro de clase ( 4.2.1g).
http://www.zator.com/Cpp/E4_9_9d.htm#[1]http://www.zator.com/Cpp/E4_9_9d.htm#[1]http://www.zator.com/Cpp/E4_9_9d.htm#[1]http://www.zator.com/Cpp/E4_2.htmhttp://www.zator.com/Cpp/E4_2.htmhttp://www.zator.com/Cpp/E4_2.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E2_2_1.htmhttp://www.zator.com/Cpp/E2_2_1.htmhttp://www.zator.com/Cpp/E2_2_1.htmhttp://www.zator.com/Cpp/E4_2_4.htmhttp://www.zator.com/Cpp/E4_2_4.htmhttp://www.zator.com/Cpp/E4_2_4.htmhttp://www.zator.com/Cpp/E4_2_1g.htmhttp://www.zator.com/Cpp/E4_2_1g.htmhttp://www.zator.com/Cpp/E4_2_1g.htmhttp://www.zator.com/Cpp/E4_2_1g.htmhttp://www.zator.com/Cpp/E4_2_4.htmhttp://www.zator.com/Cpp/E2_2_1.htmhttp://www.zator.com/Cpp/E4_2_3.htmhttp://www.zator.com/Cpp/E4_2.htmhttp://www.zator.com/Cpp/E4_9_9d.htm#[1] -
5/26/2018 014 Programacion en c++
35/55
Es recomendable abandonar la antigua sintaxis (tipoX)expr, usando en su lugar el nuevo
operador reinterpret_cast(expr) en todas aquellas conversiones que no sean
seguras, o que sean dependientes de la implementacin.
4 Ejemplo
#include
int main() { // =============int x = 10;float f = 20.5;int* ptx = &x; // puntero-a-enterofloat* ptf = &f; // puntero-a-float
cout
-
5/26/2018 014 Programacion en c++
36/55
La razn del error es obvia: el compilador interpreta el patrn de bits alojado a partir de la direccin0065FDFC como un tipo entero, cuando en realidad corresponde a un float, cuyo modelo de
almacenamiento es totalmente distinto ( 2.2.4a). Bajo la ptica de un entero es el valor1101266944, mientras que interpretado como floates 20.5
Ejemplo relativo a la conversin de tipo de un puntero a clase ( Ejemplo).
5 Un puntero puede ser convertido explcitamente a un tipo numrico entero. Lo cual es lgico,dado que los punteros almacenan direcciones de memoria, que son magnitudes escalares enteras.
Recprocamente, un argumento argentero puede ser convertido a un puntero. La conversin de
un puntero en un entero y posterior conversin a puntero del tipo original, conduce al valor original.
Ejemplo:
#include
int main() { // ==================int x, y;float f = 20.5;float* ptf = &f; // puntero-a-floatcout
-
5/26/2018 014 Programacion en c++
37/55
class ::C { public: char ch; }; // L.14:C c = { 'a' }; // L.15:cout
-
5/26/2018 014 Programacion en c++
38/55
puntero-a-funcin de otro tipo, y como estas transformaciones conducen fcilmente a resultadoserrneos.
#include void func(void* v) { // L.2:int x = reinterpret_cast(v); // L.3:
cout
-
5/26/2018 014 Programacion en c++
39/55
Como hemos comentado en el apartado correspondiente ( 3.2.1a1), la principal razn de su usoes la portabilidad del cdigo, ya que existen versiones de estos sistemas para mquinas de 16, 32y 64 bits. Amn de sucesivas versiones de los mismos (W98, XP, NT, 2000 etc), as comoversiones "light", como Windows ME, para dispositivos mviles; telfonos, PDAs, Handhelds, etc.
En ocasiones las funciones de la API devuelven tipos que son dependientes del contexto, por lo
que al utilizarlas, debemos asegurarnos de emplear el modelado adecuado y de que este sea loms especfico posible. En casos extremos podemos encontrar incluso modelados sucesivos enuna misma expresin. Como botn de muestra, incluimos un ejemplo de utilizacin propuesto enuna publicacin de Microsoft [1].
HBRUSH hbr;hbr = (HBRUSH)(UINT)SendMessage(hwnd, WM_CTLCOLOR, ..., ...);
Tenga en cuenta que el tipoHBRUSHes puntero a un tipo especial de estructura;queWM_CTCOLORes un tipo numrico, y queUINTes tambin un tipo numrico(probablementeunsigned int).
El documento seala que al utilizar este tipo de funciones, como SendMessage, antes de realizarel modelado al tipo necesario (HBRUSHen este caso), se debe realizar un modelado del valor
devuelto aUINT. Esto es necesario para que el cdigo se portable, ya que el tamao de unpuntero ("handle") puede ser 16 o 32 bits, dependiendo de la versin de Windows, y el
modelado(UINT)asegura que la conversin sea correcta (a la longitud adecuada).
4.9.10 Op erador de prepr oces o
1 Sinopsis
Durante la primera fase de la compilacin de un programa, elpreprocesador( 1.4.1)realizaciertas modificaciones previas en el cdigo fuente. Se trata de una autntica traduccin del cdigosiguiendo unas pautas explicitadas en las denominadasdirectivas de preproceso[1]. Sonsentencias que se sitan normalmente al principio del cdigo fuente, aunque legalmente puedenaparecer en cualquier punto de la unidad de compilacin (tienen validez desde el punto deaparicin hasta el final del fichero).
Por la razn anterior, se dice que estas directivas no respetan el mbito, por lo que (en especial
los#define) pueden presentar efectos colaterales no deseados en puntos alejados de los que elprogramador ha previsto.
2 Las directivas de preproceso se identifican por ser lneas precedidas por el smbolo#que es
eloperador de preproceso. A menos que#est incluido en una cadena alfanumrica o en uncomentario, indica que lo que sigue es unadirectiva de preprocesoolnea de control.#puedeestar precedido o seguido por un separador (whitespace) excluyendo nueva lnea (NL).
Las directivas de preprocesadononecesitan punto y coma (;) al final. Ejemplo:
#include ; // L.1: permisible#include // L.2: mejor!!
http://www.zator.com/Cpp/E3_2_1a1.htmhttp://www.zator.com/Cpp/E3_2_1a1.htmhttp://www.zator.com/Cpp/E3_2_1a1.htmhttp://www.zator.com/Cpp/E4_9_9e.htm#[1]http://www.zator.com/Cpp/E4_9_9e.htm#[1]http://www.zator.com/Cpp/E4_9_9e.htm#[1]http://www.zator.com/Cpp/E1_4_1.htmhttp://www.zator.com/Cpp/E1_4_1.htmhttp://www.zator.com/Cpp/E1_4_1.htmhttp://www.zator.com/Cpp/E4_9_10.htm#[1]http://www.zator.com/Cpp/E4_9_10.htm#[1]http://www.zator.com/Cpp/E4_9_10.htm#[1]http://www.zator.com/Cpp/E4_9_10.htm#[1]http://www.zator.com/Cpp/E1_4_1.htmhttp://www.zator.com/Cpp/E4_9_9e.htm#[1]http://www.zator.com/Cpp/E3_2_1a1.htm -
5/26/2018 014 Programacion en c++
40/55
Nota: la lnea 1, aunque permisible, puede dar un aviso de compilacin con algunos compiladores.Concretamente el compilador Borland C++ 5.5 compila sin ningn aviso, mientras que MS Visual
C++ 6.0 muestra un "Warning" ( 1.4):
Unexpected tokens following preprocessor directive - expected anewline...
Evidentemente el token al que se refiere es el punto y coma final, que es innecesario.
3 El Estndar C++ soporta las directivas que se indican a continuacin; todas ellas tienen un
sentido definido. La ltima,#pragma, se ha previsto para que cada fabricante de compilador puedainventar las suyas particulares sin que interfieran con las de otras implementaciones (si uncompilador encuentra una de estas directivas y no sabe que hacer con ella, sencillamente laignora). El sentido de las dems se indica en los epgrafes correspondientes.
#(directiva nula)
#define
#error
#if, #elif, #else, #endif
#ifdef, #ifndef
#import
#include
#line
#undef
#pragma
4 # Directiva nula
La directiva nula consiste en una lnea con un solo carcter#. Este lnea es ignorada totalmente.
Direct iva #define
1 Sinopsis
La directiva #definedefine una macro. Las macros proporcionan un mecanismo de reemplazo de
tokens ( 3.2)con o sin una serie de parmetros formales (parecidos a las funciones). Estasimilitud con las funciones hace que en ocasiones sirvan para una especie de sustitucin inline(
4.4.6b), aunque esta prctica presenta sus riesgos .
2 Sintaxis
#define macro_identificador
3 Comentario
http://www.zator.com/Cpp/E1_4.htm#Warningshttp://www.zator.com/Cpp/E1_4.htm#Warningshttp://www.zator.com/Cpp/E1_4.htm#Warningshttp://www.zator.com/Cpp/E3_2.htmhttp://www.zator.com/Cpp/E3_2.htmhttp://www.zator.com/Cpp/E3_2.htmhttp://www.zator.com/Cpp/E4_4_6b.htmhttp://www.zator.com/Cpp/E4_4_6b.htmhttp://www.zator.com/Cpp/E4_4_6b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_9_10b.htmhttp://www.zator.com/Cpp/E4_4_6b.htmhttp://www.zator.com/Cpp/E3_2.htmhttp://www.zator.com/Cpp/E1_4.htm#Warnings -
5/26/2018 014 Programacion en c++
41/55
-
5/26/2018 014 Programacion en c++
42/55
Valor x == 10Valor x == 13Valor x == 10
los nombres definidos en las macros noestn sujetos a las reglas de visibilidad de los
subespacios de nombres ( 4.1.11), lo que las hace altamente peligrosas, ya que el mecanismode sustitucin de tokens "arrasa" a lo largo de todo el cdigo, efectuando cuantas sustitucionessean congruentes con su definicin. A veces en sitios donde no pensbamos que lo hara y que, deotro modo, estaran relativamente a salvo de colisiones. Por ejemplo, en el interior de clases. Estaes una de las razones por las que se prefiere utilizar maysculas en los macro_identificadores;para disminuir la posibilidad de concordancias fortuitas. Por ejemplo, considere el siguiente cdigo:
...{#define min -1#define max 127
A a = foo(a, min, max); // L.m...B res = result (x, y, min); // L.n
}... /* ms adelante en un punto alejado */int max = getmax(a, b); // L.k
En este caso, el programador ha previsto los #defineminy maxpara mayor legibilidad y facilidad
de modificacin del cdigo, como en las sentencias L.my L.n, pero quizs ms adelante,
en L.kutiliza dicho nombre para definir una variable olvidando los #define anteriores y que estos
tienen validez desde el punto de su definicin hasta el final, con independencia de que hayan sidoincluidos dentro del mbito definido por los corchetes { }.
Como resultado de lo anterior, entre otras medidas, se considera buena prctica anular su efecto
con #undef( 4.9.10j)inmediatamente despus de que dejen de ser necesarios. Por ejemplo, laforma correcta del cdigo anterior podra ser:
...{#define min -1#define max 127
A a = foo(a, min, max);...B res = result (x, y, min);
#undef min#undef max}
...int max = getmax(a, b);
Sin embargo, un programador C++ de lite escribira:
...{
enum { min = -1, max = 127 };A a = foo(a, min, max);
http://www.zator.com/Cpp/E4_1_11.htmhttp://www.zator.com/Cpp/E4_1_11.htmhttp://www.zator.com/Cpp/E4_1_11.htmhttp://www.zator.com/Cpp/E4_9_10j.htmhttp://www.zator.com/Cpp/E4_9_10j.htmhttp://www.zator.com/Cpp/E4_9_10j.htmhttp://www.zator.com/Cpp/E4_9_10j.htmhttp://www.zator.com/Cpp/E4_1_11.htm -
5/26/2018 014 Programacion en c++
43/55
...B res = result (x, y, min);
}...
3.3 Cualquier carcter encontrado en el cuerpo de la macro aparecer en la macro-expansin. Elcuerpo de la macro termina en el primer carcter de nueva lnea NL (10) que no est precedido de(\). Cualquier secuencia de espacios y/o comentarios en la lnea de control, son reemplazados porun solo carcter de espacio.
3.4 Un cuerpo de macro vaco est permitido. Ejemplo:
#define VACIO
Su efecto es doble, de forma que puede utilizarse con dos finalidades distintas, segn se trate delcdigo fuente, o de la accin de otros elementos del preprocesador.
En lo que respecta a la lgica del preprocesador, si se encuentra una expresin como la
anterior, a la que falta la secuencia-de-tokens, el macro_identificadoradopta elvalor 1, que es cierto (true). Este tipo de expresiones suele utilizarse en conjuncin con la
directivas de preproceso #ifdefe #ifndef( 4.9.10e), que interrogan si un macro
identificador est definido (es cierto) o no lo est (es falso).
En lo que respecta al cdigo fuente, la presencia de un cuerpo de macro vaco, suponela eliminacin de cada macro-identificador del cdigo fuente, ya que cada ocurrencia
de VACIOes sustituido por un nulo.
3.5 Despus de cada macro-expansin se realiza una nueva exploracin del cdigo para ver siexisten nuevas expansiones, lo que permite la existencia de expansiones anidadas, ya que el textodespus de una expansin puede contener macro-identificadores que puedan sufrir otra expansin
subsiguiente. Si la macro se expande a algo que parezca una directiva de preprocesado, esta noser reconocida por el preprocesador.
Ejemplos
#define NIL ""#define GETSTD #include #define forever for (;;); // Loop infinito#define max(A, B) ((A) > (B) ? (A) : (B))
La ltima directiva origina que una lnea en el fuente tal como:
x = max (p+q, r+s);
ser transformada por el preprocesador en [3]:
x = ((p+q) > (r+s) ? (p+q) : (r+s));
4 Como el lector puede suponer, las caractersticas de los define, combinadas con las directivas
de preprocesado condicionales #if y #else( 4.9.10d), representan un cmulo de posibilidadespara el programador.
http://www.zator.com/Cpp/E4_9_10e.htmhttp://www.zator.com/Cpp/E4_9_10e.htmhttp://www.zator.com/Cpp/E4_9_10e.htmhttp://www.zator.com/Cpp/E4_9_10b.htm#[3]http://www.zator.com/Cpp/E4_9_10b.htm#[3]http://www.zator.com/Cpp/E4_9_10b.htm#[3]http://www.zator.com/Cpp/E4_9_10d.htmhttp://www.zator.com/Cpp/E4_9_10d.htmhttp://www.zator.com/Cpp/E4_9_10d.htmhttp://www.zator.com/Cpp/E4_9_10d.htmhttp://www.zator.com/Cpp/E4_9_10b.htm#[3]http://www.zator.com/Cpp/E4_9_10e.htm -
5/26/2018 014 Programacion en c++
44/55
Ejemplo
// # define SP 1// # define US 1// # define FR 1#if SP
# define ERRN "Error no recuperable en linea:"#elif US# define ERRN "Unrecoverable Error in line:"
#elif FR# define ERRN "Error ne pas recuperable en line:"
#endif
Para cambiar el lenguaje de los mensajes en que aparezca ERRNen el fuente, solo hay que quitar
el comentario a la lnea correspondiente al idioma que queremos. Con este sencillo truco, un solofuente puede servir para diversas versiones idiomticas del programa[1].
5 Limitaciones
La macro-expansin adolece de las siguientes limitaciones:
Cualquier ocurrencia del macro-identificador dentro de cadenas alfanumricas, constantescarcter o comentarios en el cdigo fuente son ignorados. Ejemplo:
#define pi 3.14159;...char* ptr = "Mostrar el valor de pi con decimales\n";cout
-
5/26/2018 014 Programacion en c++
45/55
Las macros tienen su sitio y su justificacin, pero tambin sus riesgos e inconvenientes. En generalno se aconseja demasiado su uso y menos su abuso, porque dan lugar a un cdigo difcil de leer.
Adems, cuando se utiliza como una especie de sustitucin inline( 4.4.6b)de funciones,presenta un inconveniente importante y es que con la macro no se realiza comprobacin estticade tipos (uno de los mecanismos de prevencin de errores de C++). Es decir, no existecomprobacin de que el tipo de los parmetros formales coincide con los argumentos actuales (
4.4.5), lo que puede generar errores difciles de depurar. Adems existe el riesgo de efectoscolaterales indeseados, en especial cuando el argumento actual es evaluado ms de una vez.
Como ejemplo de lo anterior, considere el siguiente programa que utiliza sucesivamente lafuncin cuboy una macro CUBO, para calcular la potencia 3 de una cantidad.
int cubo(int x) { // funcinreturn x*x*x;
}
#define CUBO(x) ( (x)* (x) * (x) ) // Macro sustitucin (ver nota )...int b = 0, a = 3;b = cubo(a++); // L.7: clculo mediante funcina = 3;b = CUBO(a++); // L.9: sustitucin y asignacin posterior
En el primer caso, L.7: el argumento actual pasado a la funcin es 3, de forma que b = 3*3*3 ==
27; a continuacin, aes incrementado, con lo que: a == 4.
En el segundo caso, L.9: CUBOes sustituido por la macro correspondiente, por lo que la sentencia
quedara como:
b = ((a++)*(a++)*(a++)); // L.9-bis
el resultado es que b = 3*3*3 == 27, pero despus, asufre tres incrementos unitarios
sucesivos, de forma que finalmente a == 6.
Observe que en este tipo de expresiones el parntesis no puede estar separado de la macro:
#define CUBO(x) ( (x)* (x) * (x) ) // Ok.#define CUBO (x) ( (x)* (x) * (x) ) // Error!!
7 Las macros en la prctica
Como resultado de todo esto, aunque estn ah para usarlas, la mayora de los textos y autoressealan que las macros, otrora bastante populares en C, son un recurso obsoleto que puede y
debe ser evitado. No obstante, los ficheros de cabecera de los compiladores suelen estar plagadosde macros, en especial para declarar constantes manifiestas ( 1.4.1a). Por ejemplo:
#define TABSIZE 100...int table[TABSIZE];
Sin embargo, la mayora de las veces los ficheros de cabecera hacen uso de "defines" bastantesofisticadas. Por ejemplo, los que siguen pertenecen al compilador MS Visual C++:
http://www.zator.com/Cpp/E4_4_6b.htm#Sustituci%C3%B3n%20inlinehttp://www.zator.com/Cpp/E4_4_6b.htm#Sustituci%C3%B3n%20inlinehttp://www.zator.com/Cpp/E4_4_6b.htm#Sustituci%C3%B3n%20inlinehttp://www.zator.com/Cpp/E4_4_5.htmhttp://www.zator.com/Cpp/E4_4_5.htmhttp://www.zator.com/Cpp/E4_4_5.htmhttp://www.zator.com/Cpp/E1_4_1a.htmhttp://www.zator.com/Cpp/E1_4_1a.htmhttp://www.zator.com/Cpp/E1_4_1a.htmhttp://www.zator.com/Cpp/E1_4_1a.htmhttp://www.zator.com/Cpp/E4_4_5.htmhttp://www.zator.com/Cpp/E4_4_6b.htm#Sustituci%C3%B3n%20inline -
5/26/2018 014 Programacion en c++
46/55
-
5/26/2018 014 Programacion en c++
47/55
-
5/26/2018 014 Programacion en c++
48/55
Resultado z4 == : 3Resultado z5 == : 6
9 Doble almohadilla ##
los caracteres #y ##se usan tambin para realizar sustitucin y asociacin de tokens durante lafase de anlisis del preprocesado. Este par de smbolos se conocen como tokenadhesivo("Token paste"), porque permiten pegar o asociar dos tokens situados entre las dosalmohadilla ( puede haber espacios opcionales en cada extremo).
En estos casos, el preprocesador elimina los espacios y la doble almohadilla, combinando los dostokens en uno solo. Esto puede usarse para construir identificadores. Por ejemplo, dada ladefinicin:
#define VAR(i, j) i##j
la llamada VAR(x, 6)se expande a x6.
Nota: este es el sistema nuevo, que reemplaza al antiguo (no estndar) mtodo de utilizar:
#define VAR(i, j) (i/**/j)
Ejemplo
#define WCHAR( X ) L##X#define WCHPT wchar_t*
la expresin:
WCHPT cptr = WCHAR("Hola mundo");
se transforma en:
wchar_t* cptr = L"Hola mundo";
En la pgina adjunta se muestra un ejemplo ms elaborado de uso de esta directiva ( 4.9.10b1).
Direct iva #error
1 Sintaxis
#error mensaje-de-error
2 Descripcin
La directiva #errorgenera el siguiente mensaje:
Error: filename line# : Error directive: mensaje-de-error
http://www.zator.com/Cpp/E4_9_10b1.htmhttp://www.zator.com/Cpp/E4_9_10b1.htmhttp://www.zator.com/Cpp/E4_9_10b1.htmhttp://www.zator.com/Cpp/E4_9_10b1.htm -
5/26/2018 014 Programacion en c++
49/55
Esta directiva se suele incluir en sentencias de preprocesado condicional para detectar algunacondicin indeseada en tiempo de compilacin. Generalmente dicha condicin debe ser falsa, perosi resultara cierta, se desea que el compilador muestre un mensaje de error y el proceso sedetenga. Esto puede conseguirse incluyendo una directiva #errordentro de una sentenciacondicional que resulte cierta en caso de error.
3 Ejemplo
El caso comentado en la directiva define ( #define)podra complementarse de la forma que seindica:
// # define Sp 1// # define Us 1// # define Fr 1#if Sp
# define ERRN "Error no recuperable en linea:"#elif Us
# define ERRN "Unrecoverable Error in line:"
#elif Fr# define ERRN "Error ne pas recuperable en line:"
#else# error "Seleccionar alguna de las opciones de lenguaje"
#endif
Directiv as #if, #elif, #else, #endif
1 Sinopsis
C++ ofrece la posibilidad de compilacin condicional mediante la inclusin de ciertas directivas que
controlan el comportamiento del preprocesador, de forma que este puede ignorar o compilardeterminadas lneas del cdigo en funcin de ciertas condiciones que son evaluadas durante elpreproceso.
2 Sintaxis
#ifk-expresion-1
-
5/26/2018 014 Programacion en c++
50/55
-
5/26/2018 014 Programacion en c++
51/55
El ejemplo siguiente muestra unas sentencias de compilacin condicional en funcin del valor de la
constante simblica DLEVELque se supone ha sido definida previamente.
#if DLEVEL > 5#define SIGNAL 1
#if STACKUSE == 1#define STACK 200#else#define STACK 100
#endif#else#define SIGNAL 0#if STACKUSE == 1#define STACK 100
#else#define STACK 50
#endif#endif#if DLEVEL == 0#define STACK 0
#elif DLEVEL == 1#define STACK 100
#elif DLEVEL > 5display( debugptr );
#else#define STACK 200
#endif
El primer bloque #if(primeras 15 lneas), contiene dos series dedirectivas #if, #elsey #endifanidadas en l. La primera se procesa si es cierta la
condicin DLEVEL > 5. En caso contrario se procesa la serie situada despus del #else.
El resto de lneas del ejemplo se utiliza para establecer el valor de la constante STACKa 0, 100 o
200 en funcin del valor de la constante DLEVEL, pero si su valor es mayor que 5, STACKqueda
indefinida, y en su lugar se compila una invocacin a la
funcin displayutilizando debugptrcomo argumento.
5 Operador defined
Tanto Borland C++ como MS VC++ disponen de este operador [1]que solopuede ser utilizado enconjuncin con las directivas #ify #elif. Admite dos formas de sintaxis, una de ellas con aspecto defuncin:
#if defined( )#if defined#elif defined( )#elif defined
5.1 Descripcin
http://www.zator.com/Cpp/E4_9_10d.htm#[1]http://www.zator.com/Cpp/E4_9_10d.htm#[1]http://www.zator.com/Cpp/E4_9_10d.htm#[1]http://www.zator.com/Cpp/E4_9_10d.htm#[1] -
5/26/2018 014 Programacion en c++
52/55
-
5/26/2018 014 Programacion en c++
53/55
con #undefX( 4.9.10i), con lo que podemos controlar a voluntad la zonas de cdigo en que seconsidera definido e indefinido.
Nota: La existencia semntica del identificador (el hecho de que est definido o no), esindependiente del valor concreto que pudiera tener asignado. Como veremos a continuacin,incluso si se le asigna el valor nulo, el identificador se considera definido.
Un identificador definido como NULLes considerado definido. Por ejemplo:
#define nulo NULL
3 Ejemplo
#define isSp // Flag Espaol/Ingls#ifdef isSp
# include "ztr--Sp.CH"#define VComP "C.000621Sp"
#else
# include "ztr--Us.CH"#define VComP "C.000621Us"
#endif........#undef isSp // A partir de aqu, isSp se considera indefinido........
4 Directivas de guarda
Tenga en cuenta que el lenguaje C++ es muy proclive a que se cometan cierto tipo de errores al
trabajar con ficheros de cabecera (es seguro que ocurrir a menudo). Por ejemplo, supongamosque tenemos una clase denominada Hotelque utiliza una clase denominada Suitey que cada
una de estas clases utiliza el mismo fichero de cabecera, por ejemplo ZonasHotel.h[2]. En estecaso es ms que posible que recibamos un error de compilacin del tipo
... Multiple declaration for 'FILE' ...
indicndonos que estamos redefiniendo los smbolos de ZonasHotel.hla segunda vez que lacabecera es incluida.
Una solucin es disponer el cdigo como se indica:
#ifndef zonasH#include "ZonasHotel.h"
#define zonasH // Nota [3]#endif... // aqu sigue el cdigo del programa
Sin embargo, esta disposicin tiene el inconveniente de que tenemos que acordarnos de
definir zonasHcada vez que vayamos a incluir la cabecera. Si lo olvidamos, volver a producirse el
error (esto es muy probable en ambientes donde trabajan varios programadores en el mismoproyecto).
http://www.zator.com/Cpp/E4_9_10j.htmhttp://www.zator.com/Cpp/E4_9_10j.htmhttp://www.zator.com/Cpp/E4_9_10j.htmhttp://www.zator.com/Cpp/E4_9_10e.htm#[2]http://www.zator.com/Cpp/E4_9_10e.htm#[2]http://www.zator.com/Cpp/E4_9_10e.htm#[2]http://www.zator.com/Cpp/E4_9_10e.htm#[3]http://www.zator.com/Cpp/E4_9_10e.htm#[3]http://www.zator.com/Cpp/E4_9_10e.htm#[3]http://www.zator.com/Cpp/E4_9_10e.htm#[3]http://www.zator.com/Cpp/E4_9_10e.htm#[2]http://www.zator.com/Cpp/E4_9_10j.htm -
5/26/2018 014 Programacion en c++
54/55
-
5/26/2018 014 Programacion en c++
55/55
// ZonasHotel.h Ejemplo de fichero de cabecera
#if !defined( ZONASH )#define ZONASH
class MiClase {...
};
#endif