SlideShare une entreprise Scribd logo
1  sur  160
Télécharger pour lire hors ligne
Una visión global del lenguaje C++ 
(pensando en sistemas embebidos) 
Miriam Ruiz <miriam@debian.org> 
Octubre, 2014
Índice 
1.- Introducción al lenguaje C++ 
2.- Características y sintaxis 
3.- Programación orientada a objetos 
4.- Clases y objetos 
5.- Herencia 
6.- Modificadores de clase 
7.- Relaciones entre clases 
8.- Programación genérica
Introducción al lenguaje C++
4 / 160 
¿Qué es C++? 
● Es un lenguaje de programación... 
– De tipado estático (static typing): Las comprobaciones de 
tipos se realizan en tiempo de compilación, no de ejecución. 
– De tipado fuerte (strong typing): Las variables tienen 
asociadas un tipo de datos, que define lo que se puede hacer. 
– De forma libre (free form): La posición de los caracteres en 
la página es irrelevante. 
– Multiparadigma: Soporta más de un paradigma de 
programación, y la combinación de los mismos. 
– Compilado: Es necesario convertirlo al código de la máquina 
para poder ejecutarlo. 
– De propósito general: Puede ser usado para realizar tareas 
que no pertenecen a un dominio concreto. 
– De nivel intermedio: Incorporando características tanto de 
bajo nivel (cercano a la máquina) como de alto nivel (cercano 
al ser humano). 
– Independiente de la plataforma: “Write once, compile 
anywhere” (WOCA)
5 / 160 
Principios de diseño de C++ 
● Lenguaje multipropósito tan eficiente y portable como C. 
● Soportar de forma directa y comprensiva diferentes estilos de 
programación: 
– Procedimental o funcional 
– Abstracción de los datos 
– Orientada a objetos 
– Programación genérica o metaprogramación 
● Permitir que la persona que está programando sea la que tome 
las decisiones, aunque ello pueda significar que las decisiones 
sean equivocadas. 
● Ser tan compatible con el lenguaje C como sea posible, para 
permitir una transición suave desde este lenguaje. 
● Evitar las características que no sean de propósito general, o 
que sean específicas de una plataforma. 
● No incurrir en un sobrecoste o una penalización por 
características que no se quieran usar. 
● No necesitar un sofisticado entorno de desarrollo.
6 / 160 
Características del lenguaje 
● Uso de operadores, y sobrecarga de los operadores. 
● 4 tipos de gestión de la memoria: 
– Memoria estática, asignada en tiempo de compilación 
– Memoria asignada automáticamente, en la pila de ejecución 
– Memoria de asignación dinámica (new/delete o malloc/free) 
– Uso de garbage collectors a través de librerías externas 
● Tipos básicos: booleanos, caracteres, números enteros, 
números en coma flotante. Modificadores: unsigned / signed, 
short / long. 
● Programación orientada a objetos basada en clases: 
– Encapsulación: public, protected, private, friend. 
– Herencia jerárquica, que puede ser simple y múltiple. Herencia virtual. 
– Polimorfismo: Un único interfaz para diferentes implementaciones. 
● Estático: Sobrecarga de operadores. Templates. 
● Dinámico: Herencia. Funciones virtuales. 
– Gestión de recursos: Constructores y destructores. 
● Plantillas o templates: Permiten que una clase o función trabaje 
con tipos de datos abstractos, especificándose más adelante 
cuales son los que se quieren usar
7 / 160 
La evolución de C++ 
● 1980: C with class 
– Clases. Herencia 
● 1983-1986: CFront 1.1 
– Funciones virtuales 
– Sobrecarga de operadores 
– Referencias 
● 1989: CFront 2.0 
– Herencia múltiple 
– Clases abstractas 
● 1991: CFront 3.0 
– Plantillas o templates 
● 1992: HP C++ 
– Excepciones 
● 1996: C++ 98/03 
– STL 
– Espacios de nombres 
● 2011: C++11 
– Expresiones lambda 
– Tipos automáticos 
– Hilos de ejecución (threading)
8 / 160 
Etapas en la compilación de un programa 
● Código fuente (source code) 
– Archivos .h, .c, .cpp, .hpp, .cc 
● Preprocesado (preprocessing) 
– Archivos con las cabeceras incluidas y las macros 
expandidas: .i, .ii 
● Compilación (compilation) 
– Archivos en código ensamblador: .s 
● Ensamblado (assembling) 
– Archivos en código máquina: .o 
● Archivado (library) 
– Bibliotecas estáticas (.a) o dinámicas (.so, .dll) 
● Enlazado (linking) 
– Archivos ejecutables (.exe, .elf)
Características y sintaxis de C++
10 / 160 
El modelo de memoria de C++ 
● La memoria consiste en una serie de objetos referenciados por 
punteros: 
● Hay una serie de tipos básicos predefinidos, y unos mecanismos 
para construir estructuras más complejas a partir de ellos 
● El almacenamiento de las estructuras se hace de tal forma que la 
composición y la herencia son fáciles de implementar
11 / 160 
Tipos básicos de datos en C++ 
● Simples 
– Booleanos 
● bool 
– Enteros (o decimales en coma fija) 
● char, short, int, long 
– Enumeraciones 
● enum 
– Decimales en coma flotante 
● float, double, long double 
● Estructurados 
– Estructuras de datos: arrays, strings (zero-terminated), union 
– Definición de objetos: class, struct 
● Direcciones 
– Punteros (*) 
– Referencias (&)
Conversiones automáticas entre tipos básicos 
● Booleanos: Si el tipo original es bool, false se convierte a cero y 
true se convierte a uno. 
● Enumeraciones: Conversión implícita de tipos enum a tipos int, 
heredada de los tiempos de C. Suponen un problema. 
● Typedef: Solo establece un nombre diferente para un tipo ya 
existente. Por tanto, los tipos se pueden convertir implícitamente. 
● Conversiones de ampliación: El valor de una variable menor se 
asigna a una variable mayor sin pérdida de datos. 
● Conversiones de restricción o coerción: El compilador realiza 
las conversiones de restricción implícitamente, pero advierte 
sobre la posible pérdida de datos. 
● Conversiones con y sin signo: Un tipo entero con signo y su 
homólogo sin signo son siempre del mismo tamaño, aunque 
difieren en cuanto a la forma de interpretar el patrón de bits. 
● Punteros: Una matriz del estilo de C se convierte implícitamente 
a un puntero al primer elemento de la matriz. Esto puede 
ocasionar efectos curiosos. Ej: char * s = "Help" + 3; 
12 / 160
Conversiones automáticas en expresiones C++ 
● Cualquier tipo entero pequeño como char o short es convertido a 
int o unsigned int. 
● Si un operando es de tipo long double, el otro se convertirá a 
long double. 
● Si un operando es de tipo double, el otro se convertirá a double. 
● Si un operando es de tipo float, el otro se convertirá a float. 
● Si un operando es de tipo unsigned long long, el otro se 
convertirá a unsigned long long. 
● Si un operando es de tipo long long, el otro se convertirá a long 
long. 
● Si un operando es de tipo unsigned long, el otro se convertirá a 
unsigned long. 
● Si un operando es de tipo long, el otro se convertirá a long. 
● Si un operando es de tipo unsigned int, el otro se convertirá a 
unsigned int. 
● Si no se da ninguno de los casos anteriores, ambos operandos 
son int. 
13 / 160
Modificadores y calificadores de tipos de datos 
14 / 160 
● Modificadores de los tipos de datos: 
– signed, unsigned, long, short 
● Calificadores de los tipos de datos: 
– const: Los objetos de este tipo no pueden ser modificados 
● const int, const char * 
– volatile: Indica al compilador que los datos referenciados. 
pueden ser alterados de formas no explícitamente 
especificadas por el programa. 
● volatile REGISTER * io_ = 0x1234; 
– restrict: Indica al compilador que ese puntero es el único 
mecanismo de acceso a los datos a los que apunta. 
● size_t *restrict ptrA
15 / 160 
Punteros 
#include <cstdlib> 
#include <cstdio> 
int main() { 
char ch = 'c'; 
char *chptr = &ch; 
int i = 20; 
int *intptr = &i; 
float f = 1.20000; 
float * fptr = &f; 
const char * ptr = "I am a string"; 
printf("n [%c], [%d], [%f], [%c], [%s]n", 
*chptr, *intptr, *fptr, *ptr, ptr); 
return EXIT_SUCCESS; 
}
16 / 160 
Punteros 
#include <cstdlib> 
#include <cstdio> 
int main() { 
char ch = 'c'; 
char *chptr = &ch; 
int i = 20; 
int *intptr = &i; 
float f = 1.20000; 
float * fptr = &f; 
const char * ptr = "I am a string"; 
printf("n [%c], [%d], [%f], [%c], [%s]n", 
*chptr, *intptr, *fptr, *ptr, ptr); 
return EXIT_SUCCESS; 
} 
[c], [20], [1.200000], [I], [I am a string]
17 / 160 
Referencias a variables 
#include <cstdlib> 
#include <cstdio> 
void swap(int & i, int & j) { 
int tmp = i; 
i = j; 
j = tmp; 
} 
int main() { 
int x = 0; 
int y = 1; 
swap(x,y); 
printf("x=%d, y=%dn", x, y); 
int & a = x; 
int b = x; 
a = 5; 
b = 7; 
printf("x=%d, y=%d, a=%d, b=%dn", x, y, a, b); 
return EXIT_SUCCESS; 
}
18 / 160 
Referencias a variables 
#include <cstdlib> 
#include <cstdio> 
void swap(int & i, int & j) { 
int tmp = i; 
i = j; 
j = tmp; 
} 
int main() { 
int x = 0; 
int y = 1; 
swap(x,y); 
printf("x=%d, y=%dn", x, y); 
int & a = x; 
int b = x; 
a = 5; 
b = 7; 
printf("x=%d, y=%d, a=%d, b=%dn", x, y, a, b); 
return EXIT_SUCCESS; 
} 
x=1, y=0 
x=5, y=0, a=5, b=7
19 / 160 
Punteros vs. Referencias 
● Puntero: 
– Identifican un contenido ubicado en un lugar de la memoria. 
– Se define añadiendo el carácter '*' a un tipo de dato. 
● char * pChar; int * pInt; Shape * pShape; 
– Se usa por convenio el valor NULL (igual a 0L) para no 
señalar ninguna dirección significativa. 
● Referencia: 
– No es una variable 
– Es un alias (o nombre alternativo) de un objeto o dato que ya 
existe. 
– Se define añadiendo el carácter '&' a un tipo de dato. 
● char & rChar; int & rInt; Shape & rShape; 
– No siempre necesitan ocupar memoria. 
– No pueden ser NULL. 
– No pueden ser modificadas. 
– A menudo son implementados con punteros por parte de los 
compiladores, pero no son lo mismo.
20 / 160 
Sobrecarga de funciones 
● Permite asignar el mismo nombre a funciones distintas, siempre que 
tengan diferentes parámetros. 
● Para el compilador estas funciones no tienen nada en común a 
excepción del identificador. 
● Debe haber diferencia en los parámetros. 
● Si se diferencian únicamente en el valor de retorno, no es suficiente. 
● Los últimos parámetros de una función pueden tener asignado un 
valor por omisión, que se usará cuando no se le pase uno explícito. 
● Orden de preferencia (reglas de congruencia estándar de argumentos): 
– Concordancia exacta en número y tipo, incluyendo conversiones triviales 
como de nombre de matriz a puntero, de nombre de función a puntero a 
función, o de tipo de datos a tipo de datos constante. 
– Concordancia después de realizar promociones de los tipos asimilables a 
enteros, o de los tipos float a double. 
– Concordancia después de realizar conversiones estándares, como de int a 
double, de double a long double, de un puntero de una clase derivada a una 
superclase, o de un puntero a un puntero a void. 
– Concordancia después de realizar conversiones definidas por el usuario/a. 
– Concordancia usando la elipsis (...) en funciones con número variable de 
parámetros.
21 / 160 
Sobrecarga de funciones 
#include <iostream> 
void function(void) { 
std::cout << "Sin parametros" << std::endl; 
} 
void function(int x) { 
std::cout << "Un numero entero" << std::endl; 
} 
void function(int x, int y) { 
std::cout << "Dos numeros enteros" << std::endl; 
} 
void function(int x, double y) { 
std::cout << "Un numero entero y un numero flotante" << std::endl; 
} 
int main(void) { 
function(); 
function(1); 
function(1, 2); 
function(1, 2.); 
return 0; 
}
22 / 160 
Sobrecarga de funciones 
#include <iostream> 
void function(void) { 
std::cout << "Sin parametros" << std::endl; 
} 
void function(int x) { 
std::cout << "Un numero entero" << std::endl; 
} 
void function(int x, int y) { 
std::cout << "Dos numeros enteros" << std::endl; 
} 
void function(int x, double y) { 
std::cout << "Un numero entero y un numero flotante" << std::endl; 
} 
int main(void) { 
function(); 
function(1); 
function(1, 2); 
function(1, 2.); 
return 0; 
} 
“Sin parametros” 
“Un numero entero” 
“Dos numeros enteros” 
“Un numero entero y un numero flotante”
23 / 160 
Expresiones y operadores 
● Variable: es una entidad que permite a un programa almacenar 
información, y cuyo valor puede cambiar a lo largo de su ejecución. 
● Operando: cada una de las constantes, variables o expresiones que 
intervienen en una expresión. 
● Operador: cada uno de los símbolos que indican las operaciones a 
realizar sobre los operandos, así como los operandos a los que afecta. 
● Expresión: es una combinación gramaticalmente válida de operadores 
y operandos, que dan como resultado un valor. 
● Sobrecarga de operadores: es uno de los mecanismos que nos 
permite ampliar las capacidades de los lenguajes de programación 
orientados a objetos. En C++, la declaración y definición de una 
sobrecarga de operador es muy similar a la declaración y definición de 
una función cualquiera.
24 / 160 
Operadores en C++ 
● Aritméticos: suma, resta, multiplicación, división y módulo 
● Asignación: Operadores de asignación simple ('=') y compuestos 
● Manejo de bits: Manejo de bits (bitwise) entre enteros: complemento, 
desplazamientos, AND, XOR y OR 
● Lógicos: Producen resultados booleanos: AND, OR y NOT. Los 
operandos no son siempre evaluados. 
● De Puntero: Operadores de indirección (*) y de referencia (&) 
● Relacionales: ==, !=, <, >, <=, >= 
● Manejo de memoria: new, delete, new[], delete[] 
● Modelado de tipos (cast): Convierte datos de un tipo a otro 
● Otros: 
– '::' - Acceso a ámbito (también llamado de resolución) 
– '.' - Dereferencia punteros a miembros de clase 
– '->' - Dereferencia punteros a punteros a miembros de clases 
– '?' - Operador ternario condicional 
– ',' - Operador en la expresiones con coma 
– 'typeid' - Obtiene identificación de tipos y expresiones en tiempo de 
ejecución 
– 'sizeof' - Obtiene el tamaño de memoria utilizado por el operando
25 / 160 
Operadores en C++ 
● Operadores unitarios: solo requieren un operando y operan 
generalmente de izquierda a derecha (el operador a la izquierda, el 
operando a la derecha). C++ dispone de los siguientes operadores 
unitarios: 
– '!' - Negación lógica 
– '*' - Indirección 
– '&' - Referencia 
– '~' - Complemento de bits 
– '++' - Incremento (prefijo o postfijo: ++a, a++) 
– '--' - Decremento (prefijo o postfijo: --a, a--) 
– '-' - Menos unitario 
– '+' - Más unitario 
● Operadores binarios: Operadores de asignación simple ('=') y 
compuestos 
● Operadores ternarios: El único operador ternario es el operador 
relacional ? :
26 / 160 
Espacios de nombres (namespace) 
● Cuando un programa alcanza un gran tamaño, la probabilidad de colisiones 
en los nombres o identificadores aumenta. 
● El problema puede llegar a ser aún mayor cuando se usan librerías externas. 
● Un espacio de nombres es una zona donde se pueden declarar y definir 
identificadores de cualquier tipo (clases, estructuras, funciones, etc), a la que 
se asigna un nombre o identificador propio. 
● Esto permite diferenciar estos elementos de los que puedan tener 
identificadores iguales en otros espacios. 
● El identificador del espacio, usado como prefijo, permite acceder a los 
nombres o identificadores declarados en su interior a través del operador de 
especificador de ámbito (“::”). 
● También se puede indicar al programa que busque por defecto en los 
espacios que se quiera (“using namespace”). 
● Incluso sin utilizar explícitamente los subespacios, dentro de un mismo 
ámbito, C++ distingue automáticamente varios espacios de nombres distintos. 
● El espacio de nombres sencillo, que contiene las variables, funciones, 
definiciones de tipo (typedef) y enumeradores (enum). 
● El espacio de nombres de miembros de clases 
● El espacio de nombres de miembros de estructuras 
● El espacio de nombres de miembros de uniones 
● El espacio de nombres de etiquetas
27 / 160 
Espacios de nombres (namespace) 
namespace EspacioA { 
long double LD; 
float f(float y) { return y; } 
namespace Sub1 { long double LD; } 
namespace Sub2 { long double LD; } 
} 
namespace EspacioB { 
long double LD; 
float f(float z) { return z; } 
namespace Sub1 { long double LD; } 
} 
EspacioA::LD = 1.1; // Aceso a variable LD del espacio A 
EspacioA::f(1.1); // Aceso a función f de A 
EspacioB::LD = 1.0; // Aceso a variable LD del espacio B 
EspacioB::f(1.1); // Aceso a función f de B 
EspacioB::X = 1 // Error: Elemento X no definido en B 
EspacioA::Sub1::LD = 3; // Aceso a variable LD del subespacio 1 de A 
EspacioA::Sub2::LD = 4; // Aceso a variable LD del subespacio 2 de A 
EspacioB::Sub1::LD = 5; // Aceso a variable LD del subespacio 1 de A 
::EspacioA::LD = 1.1; // Acceso comenzando a buscar desde la raiz 
::EspacioB::LD = 1.0; // Acceso comenzando a buscar desde la raiz
28 / 160 
Espacios de nombres automáticos 
int x = 1, y = 2, z = 3; // Espacio principal 
struct E { int x; int y; int z; } e1 = {1, 2, 3}; // Estructuras 
class C { int x; int y; int z; } c1 = {1, 2, 3}; // Clases 
union U { int x; char y; float z; } u1 = { x }; // Uniones 
func(1, 2, 3); 
... 
int func(int x, int y, int z) { 
if (x == 0) 
goto x; 
return (x + y + z); 
x: // Etiquetas 
return (1 + y + z); 
}
29 / 160 
Decoración de Nombres (Name Mangling) 
● El mecanismo tradicional de asignación de nombres a los 
elementos de C, ya no es válido para C++ (espacios de 
nombres, sobrecarga de funciones). 
● El compilador cambiará el nombre de la función, añadiendo 
un identificador del espacio de nombres en el que está declarada, 
y de los parámetros aceptados por la función. 
● Cada compilador de C++ realiza la decoración de los nombres 
de una forma diferente, incompatible con los demás. La posible 
estandarización de la decoración de los nombres, de todas 
formas, sería insuficiente para garantizar la compatibilidad entre 
diferentes compiladores (es necesario que haya compatibilidad 
también en la ABI: gestión de excepciones, distribución de la 
tabla virtual, etc.) 
● Cuando se quiere buscar la compatibilidad con otros 
componentes, se usa la expresión extern “C” { } 
● Ejemplos de Name Mangling para diferentes compiladores: 
http://en.wikipedia.org/wiki/Name_mangling#How_different_compilers_mangle_the_same_functions
30 / 160 
Name Mangling: Integrando C y C++ 
example.h: 
#ifndef EXAMPLE_H_ 
#define EXAMPLE_H_ 
#ifndef __cplusplus 
extern "C" { 
#endif 
extern int Number; 
int Function(char parameter); 
#ifndef __cplusplus 
} 
#endif 
#endif /* EXAMPLE_H_ */ 
example.c: 
#include "example.h" 
int Number; 
int Function(char parameter) { 
return 4*parameter; 
} 
Main.cpp: 
#include "example.h" 
int main(void) { 
Number = Function(7); 
return 0; 
} 
Include Guards 
Definiciones 
Símbolos exportados como C 
(sólo si el programa está en C++) 
Símbolos exportados como C 
(el programa está en C) 
Símbolos usados como C 
(aunque el programa esté en C++)
31 / 160 
Conversiones de tipos (casting) 
● Se usan para convertir variables, objetos o expresiones a otros tipos 
de datos. 
● Pueden ser implícitas o explícitas. 
● Sigue siendo válida la sintaxis de C, aunque no es recomendable. 
● C++ permite 4 formas diferentes de realizar conversiones explícitas: 
● const_cast <>: Sirve para eliminar o añadir los modificadores const y volatile de 
una variable. Intentar modificar una variable que era originalmente constante da un 
resultado indefinido. 
● reinterpret_cast <>: Sirve para interpretar de una forma diferente los datos a los 
que apunta un puntero, garantizando su reversibilidad. En principio no genera código 
adicional y mantiene las direcciones de los punteros, pero depende del compilador. 
● static_cast <>: Convierte entre diferentes tipos de datos mediante una 
combinación entre las conversiones provistas por el compilador y las definidas 
explícitamente en el código. La conversión de punteros desde/hacia void * no 
modifica el valor del puntero (si la alineación en memoria lo permite). Permite hacer 
upcast a clases base, o downcast sin ningún tipo de comprobación de validez. . 
Equivalente a las conversiones de tipos de C. 
● dynamic_cast <>: Es parte del sistema RTTI (Run-Time Type Information) de C++. 
Permite convertir punteros y referencias, realizando comprobaciones de validez en 
tiempo de ejecución al hacerlas. Permite tanto upcast como downcast. No se suele 
usar en el desarrollo de sistemas empotrados. Equivalente a las conversiones de 
tipos de Java.
32 / 160 
Notas sobre las conversiones de tipos 
● reinterpret_cast no está definido por el estándar C++, por lo que –en teoría– 
podría tener resultados inesperados. En la práctica, los compiladores suelen 
interpretar los bits como si fueran del tipo al que se están convirtiendo. Si se 
sabe qué es lo que va a hacer el compilador que se esté usando, se puede usar, 
pero su portabilidad no está garantizada. 
● El estándar C++ garantiza que la conversión con static_cast desde un puntero a 
void* mantiene la dirección, siempre que la alineación en la memoria lo permita. 
Es decir, en el siguiente ejemplo, a, b y c probablemente apuntan –dependiendo 
de la arquitectura y el tipo de datos– a la misma dirección. 
A * a = new A(); 
void * b = static_cast<void*>(a); 
A * c = static_cast<A*>(b); 
● reinterpret_cast sólo garantiza que si se convierte un puntero a un tipo diferente, 
y se usa de nuevo reinterpret_cast para volver a convertirlo al tipo original, se 
obtiene el valor original. En el siguiente ejemplo, a y c contienen el mismo valor, 
pero b no está especificado. En la práctica será normalmente también el mismo, 
pero no se especifica en la norma, y puede no ser cierto en máquinas con 
sistemas de memoria más complejos. 
A * a = new A(); 
void * b = reinterpret_cast<void*>(a); 
A * c = reinterpret_cast<A*>(b);
33 / 160 
Conversiones de tipos (casting) 
int i1 = 5, i2 = 5u, i3 = 5.; 
int i4 = int(5u), i5 = int(5.); 
int i6 = (int)5u, i7 = (int)5.; 
float f1 = i1, f2 = float(i1), f3 = (float)i1; 
const int j1 = 5; 
int j2 = j1; 
enum E { X, Y, Z, T }; 
E e = X; 
int ei1 = e; 
int ei2 = static_cast<int>(e); 
int i = 1; 
// E ie1 = i; // Error! 
E ie2 = static_cast<E>(i); // Aviso! No se comprueba en tiempo de ejecucion! 
struct S_a { int a; S_a(int v) : a(v) { } }; 
const S_a s1(5); 
//S_a * ps1 = &s1; // Error! Intento quitar el const implicitamente! 
S_a * ps1 = const_cast<S_a*>(&s1); 
struct S_b { bool x; }; 
S_a s2(6); 
//S_b * ps2 = static_cast<S_b*>(&s2); // Error! S_b y S_a no están relacionadas! 
S_b * ps2 = reinterpret_cast<S_b*>(&s2); // es probable que ps2 sea igual a &s2 
S_a * ps3 = reinterpret_cast<S_a*>(ps2); // ps3 ha de ser igual a &s2
Programación Orientada a Objetos
Complejidad en la programación estructurada 
35 / 160
36 / 160 
Pensar en objetos 
● La programación orientada a objetos es un paradigma diferente 
de la programación estructurada, y no una simple ampliación del 
mismo. 
● Requiere una forma diferente de pensar. 
● Permite trabajar con sistemas más complejos de una forma 
más sencilla. 
● En la programación estructurada, descomponemos el problema 
en acciones, en verbos. En la programación orientada a objetos, 
lo descomponemos en objetos, en nombres. 
● Al analizar el problema, lo primero que tenemos que ver son las 
entidades que lo forman. 
● Estas entidades poseen un conjunto de propiedades o 
atributos, y un conjunto de métodos mediante los cuales se 
puede interaccionar con ellas. 
● Las entidades se interrelacionan entre ellas mediante mensajes, 
respondiendo a ellos mediante la ejecución de ciertas acciones.
37 / 160 
Pensar en objetos
38 / 160 
Programación orientada a objetos 
● Es un paradigma de programación que usa los objetos como elemento 
base. 
● Los objetos están constituidos por propiedades (o variables) y por métodos 
(o funciones). 
● Las propiedades de un objeto almacenan su estado en un instante 
determinado. 
● Los métodos de un objeto permiten interaccionar con él para obtener 
información, y cambiar su estado. 
● La POO está basada en varias técnicas, incluyendo: 
– Herencia: Permite reutilizar el código mediante la especialización de unos 
objetos a partir de otros. 
– Cohesión: Pretende que cada objeto del sistema se refiera a un único 
proceso o entidad. 
– Abstracción: Consiste en aislar un componente de su entorno y del resto 
de elementos, haciendo énfasis en qué hace, en lugar de cómo lo hace. 
– Polimorfismo: Se refiere a la posibilidad de interactuar con objetos 
heterogéneos de una forma homogénea, a través del mismo interfaz. 
– Acoplamiento: Cuanto menor acoplamiento entre unos objetos y otros, 
más sencillo será de desarrollar y mantener. 
– Encapsulamiento: Se refiere al ocultamiento del estado interno y a la 
protección del mismo respecto a modificaciones externas.
Un ejemplo de sistema organizado en objetos 
39 / 160
Un ejemplo de sistema organizado en objetos 
40 / 160
Un ejemplo de sistema organizado en objetos 
41 / 160
Clases y Objetos en C++
43 / 160 
Clases vs. Objetos 
● Clase: 
– Es la definición abstracta de un tipo de objeto. 
– Sólo tiene sentido en tiempo de programación. 
– Definen el aspecto que tendrán los objetos que se creen 
durante la ejecución del programa. 
– Son una especie de molde o plantilla. 
– Definen qué atributos tendrán los objetos, y las cosas que se 
pueden hacer con él. 
● Objeto o instancia: 
– Suponen la concreción del concepto de clase en un elemento 
concreto con características determinadas. 
– Existen durante la ejecución del programa, e interaccionan 
entre ellos. Nacen, viven, se comunican y mueren. 
– El valor concreto de cada atributo es único e independiente 
para cada objeto.. 
– Los conceptos de clase y objetos son análogos a los de tipo 
de datos y variable: definida una clase, podemos crear objetos 
de esa clase.
44 / 160 
Definición de una clase en C++ 
class Rectangle { 
public: 
Rectangle(int h, int w); 
int getHeight(); 
int getWidth(); 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) : 
height(h), width(w) { 
} 
int Rectangle::getHeight() { 
return height; 
} 
int Rectangle::getWidth() { 
return width; 
}
45 / 160 
Definición de una clase en C++ 
class Rectangle { 
public: 
Ámbito de utilización 
Rectangle(int h, int w); 
int getHeight(); 
int getWidth(); 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) : 
height(h), width(w) { 
} 
int Rectangle::getHeight() { 
return height; 
} 
int Rectangle::getWidth() { 
return width; 
} 
Definición de métodos 
Definición de atributos 
Constructor 
Implementación de métodos 
Ámbito de utilización
46 / 160 
Constructores 
● Son funciones miembro especiales que sirven para inicializar los 
objetos 
● Tienen el mismo nombre que la clase a la que pertenecen. 
● No pueden devolver ningún valor. 
● No pueden ser heredados. 
● Cuando no especifiquemos un constructor para una clase, el 
compilador crea uno por defecto sin argumentos. 
● Pueden definirse diferentes constructores para cada clase, 
siempre que tengan diferentes parámetros. 
● Un constructor copia crea un objeto a partir de otro objeto 
existente. Si no se especifica ninguno, el compilador también 
crea uno por defecto. 
● Se pueden invocar de forma directa de forma excepcional para 
inicializar una zona de memoria ya reservada, con un objeto de 
un tipo dado.
47 / 160 
Destructores 
● Son funciones miembro especiales que sirven para eliminar un 
objeto de una determinada clase. 
● Tienen el mismo nombre que la clase a la que pertenecen, pero 
con el símbolo tilde ('~') delante. 
● No retornan ningún valor. 
● No tienen parámetros. 
● No pueden ser heredados. 
● Deben ser públicos. 
● No pueden ser sobrecargados. 
● Si la clase tiene algún método virtual, es conveniente declarar el 
destructor también como virtual. 
● Son llamados automáticamente cuando un objeto deja de existir.
48 / 160 
El puntero 'this' 
● Cada objeto declarado tiene unas propiedades diferentes. Por 
tanto, cada objeto mantiene una copia de sus datos, diferente 
de los datos de otros objetos de la misma clase. 
● Sin embargo, todos los objetos de la misma clase comparten 
la misma copia de sus métodos y funciones, es decir, del 
código ejecutable. 
● El puntero especial this permite acceder a los datos de un 
objeto concreto, aunque sea desde el código genérico de los 
métodos definidos en una clase. 
● El puntero this está asociado a cada objeto, y apunta a la 
estructura de datos que está asociada con dicho objeto. 
● Aunque la sintaxis de C++ hace que el puntero this no se pase 
explícitamente como parámetro al llamar a un método del mismo, 
sí que se está pasando como un primer parámetro oculto al 
invocar a cualquiera de los métodos de un objeto. 
● Al acceder a los métodos y propiedades de un objeto, no es 
necesario explicitarlo (mediante 'this->'). Opcionalmente se 
puede poner, pero no es necesario.
49 /4 91 6/ 700 
El puntero 'this' 
class Rectangle { 
public: 
Rectangle(int h, int w); 
int getSize(); 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) { 
height = h; 
width = w; 
} 
int Rectangle::getSize() { 
return height * width; 
} 
class Rectangle { 
public: 
Rectangle(int h, int w); 
int getSize(); 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) { 
this->height = h; 
this->width = w; 
} 
int Rectangle::getSize() { 
return this->height * this->width; 
} 
Equivalentes
50 / 160 
¿Cómo se almacena una clase en memoria? 
name 
layer 
class Shape { 
public: 
Shape(const char* n); 
inline const char* getName() const { 
return name; } 
inline int getLayer() const { 
return layer; } 
inline char getColor() const { 
return color; } 
protected: 
const char* name; 
int layer; 
char color; 
}; 
color padding 
for alignment
51 /5 11 6/ 700 
Definición de una clase en C++ 
Implementación en C++ 
class Shape { 
public: 
Shape(); 
~Shape(); 
void draw(); 
double x, y; 
}; 
Implementación equivalente en C 
Typedef struct ShapeT { 
double x, y; 
} Shape; 
void Shape_new(Shape * this); 
void Shape_delete(Shape * this); 
void Shape_draw(Shape * this);
52 / 160 
Gestión de recursos 
● Recursos: Son aquellos elementos que, al ser limitados o tener 
que ser compartidos por diferentes componentes del sistema, 
han de ser adquiridos y liberados en determinados momentos: 
– Memoria 
– Descriptores de archivos 
– Hilos, procesos, elementos de bloqueo 
– Eventos, mensajes, modelos 
– Etc. 
● Resource Acquisition Is Initialization (RAII): Los recursos son 
adquiridos durante la inicialización de los objetos que los usan o 
gestionan (cuando no hay posibilidad de que sean usados antes 
de ser disponibles), y liberados cuando se destruyan los mismos 
objetos, que se garantiza que sucede incluso cuando hay errores.
Herencia
54 / 160 
Herencia 
● Permite crear una clase nueva a partir de una ya existente. 
● Esta nueva clase contiene los atributos y métodos de la clase primaria. 
● Este mecanismo permite construir una jerarquía de objetos cada vez 
más especializados. 
● La principal ventaja de la herencia es la capacidad para definir atributos 
y métodos nuevos para la subclase, que luego se aplican a los atributos 
y métodos heredados. 
Herencia Simple Herencia Múltiple
55 / 160 
Herencia simple 
class Shape { 
public: 
Shape(const char * n) : name(n) { } 
const char * getName() const { return name; } 
protected: 
const char * name; 
}; 
class Rectangle : public Shape { 
public: 
Rectangle(int h, int w); 
inline int getHeight() const { return height; } 
inline int getWidth() const { return width; } 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) : 
Shape("Rectangle"), height(h), width(w) { }
56 / 160 
¿Cómo funciona la herencia simple? 
name 
layer 
color padding 
for alignment 
radius 
class Shape { 
public: 
Shape(const char * n); 
inline const char * getName() const { return name; } 
inline int getLayer() const { return layer; } 
inline char getColor() const { return color; } 
virtual draw(int x, int y); 
protected: 
const char * name; 
int layer; 
char color; 
}; 
class Circle : public Shape { 
public: 
Circle(int r) : Shape("Circle"), radius(r) { } 
inline int getRadius() const { return radius; } 
virtual draw(int x, int y); 
private: 
int radius; 
};
57 /5 71 6/ 700 
Implementación de la herencia 
Implementación en C++ 
class Shape { 
public: 
Shape(); 
~Shape(); 
void draw(); 
double x, y; 
}; 
class Box : public Shape { 
public: 
Box(); 
~Box(); 
double area(); 
double h, w; 
}; 
Implementación equivalente en C 
typedef struct ShapeT { 
double x, y; 
} Shape; 
void Shape_new(Shape * this); 
void Shape_delete(Shape * this); 
void Shape_draw(Shape * this);; 
typedef struct BoxT { 
struct Shape shape; 
double h, w; 
} Box; 
void Box_new(Box* this); 
void Box_delete(Box* this); 
double Box_area(Box * this);
58 / 160 
Herencia múltiple 
class Shape { 
public: 
Shape(const char * n) : name(n) { } 
const char * getName() const { return name; } 
protected: 
const char * name; 
}; 
class Storage { 
public: 
Storage(int type); 
}; 
class Rectangle : public Shape, public Storage { 
public: 
Rectangle(int h, int w); 
inline int getHeight() const { return height; } 
inline int getWidth() const { return width; } 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) : 
Shape("Rectangle"), Storage(1), height(h), width(w) { }
59 / 160 
name 
layer 
color padding 
for alignment 
file 
radius 
Herencia múltiple 
class Shape { 
public: 
Shape(const char * n); 
inline const char * getName() const { return name; } 
inline int getLayer() const { return layer; } 
inline char getColor() const { return color; } 
void draw(int x, int y); 
protected: 
const char * name; 
int layer; 
char color; 
}; 
class Storage { 
public: 
bool save(int len, const char * buffer); 
bool load(int maxlen, char * buffer); 
private: 
FILE * file; 
}; 
class Circle : public Shape, public Storage { 
public: 
Circle(int r) : Shape("Circle"), radius(r) { } 
inline int getRadius() const { return radius; } 
virtual draw(int x, int y); 
private: 
int radius; 
};
60 / 160 
Conversiones de tipos (casting) 
struct A { 
A(int i) : x(i) { } 
int x; 
}; 
struct B : public A { 
B(int i, int j) : A(i), y(j) { } 
int y; 
}; 
struct C { 
C(int i) : x(i) { } 
int x; 
}; 
A a(1); 
B b(2, 3); 
C c(4); 
A cb = static_cast<A>(b); 
A & rb = static_cast<A&>(b); 
A * pb = static_cast<A*>(&b); 
// A cc = static_cast<A>(c); // Error! 
// A & rc = static_cast<A&>(c); // Error! 
// A * pc = static_cast<A*>(&c); // Error! 
// B ca = static_cast<B>(a); // Error! 
B & ra = static_cast<B&>(a); // Aviso! No se comprueba en tiempo de ejecucion! 
B * pa = static_cast<B*>(&a); // Aviso! No se comprueba en tiempo de ejecucion!
&circle, &shape, pshape, &cfstorage, 
&cfshape, pvoidc, &circle.name 
&circle.layer 
&circle.color 
&storage, pstorage, pvoids, &circle.file 
61 / 160 
Conversión de tipos en herencia múltiple 
name 
layer 
color 
padding 
file 
padding 
radius 
Shape 
Storage 
Circle 
padding 
&circle.radius 
Memoria 
Lineal 
sizeof(Circle) 
sizeof sizeof(Shape) 
Circle circle; 
Storage & storage = static_cast<Storage&>(circle); 
Storage * pstorage = static_cast<Storage*>(&circle); 
Shape & shape = static_cast<Shape&>(circle); 
Shape * pshape = static_cast<Shape*>(&circle); 
Circle & cfstorage = static_cast<Circle&>(storage); 
Circle & cfshape = static_cast<Circle&>(shape); 
void * pvoidc = static_cast<void*>(&circle); 
void * pvoids = static_cast<void*>(&storage);
62 /6 21 6/ 700 
Implementación de la herencia múltiple 
Implementación en C++ 
class Shape { 
public: 
Shape(); 
~Shape(); 
void draw(); 
double x, y; 
}; 
class Storage { 
public: 
bool save(int len, const char * buffer); 
bool load(int maxlen, char * buffer); 
private: 
FILE * file; 
}; 
class Box : public Shape, public Storage { 
public: 
Box(); 
~Box(); 
double area(); 
double h, w; 
}; 
Implementación equivalente en C 
typedef struct ShapeT { 
double x, y; 
} Shape; 
void Shape_new(Shape * this); 
void Shape_delete(Shape * this); 
void Shape_draw(Shape * this);; 
typedef struct StorageT { 
FILE * file; 
} Storage; 
int Storage_save(Storage *this, int len, 
const char * buffer); 
int Storage_load(Storage *this, int maxlen, 
char * buffer); 
typedef struct BoxT { 
Shape shape; 
Storage storage; 
double h, w; 
} Box; 
void Box_new(Box* this); 
void Box_delete(Box* this); 
double Box_area(Box * this);
63 / 160 
La necesidad de funciones virtuales 
#include <cstdlib> 
#include <cstdio> 
class Shape { 
public: 
const char * getName() const { return "Shape"; }; 
}; 
class Rectangle : public Shape { 
public: 
const char * getName() const { return "Rectangle"; } 
}; 
class Circle : public Shape { 
public: 
const char * getName() const { return "Circle"; } 
}; 
class Triangle : public Shape { 
public: 
const char * getName() const { return "Triangle"; } 
}; 
int main() { 
Rectangle r1, r2; 
Circle c1, c2, c3; 
Triangle t1; 
Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; 
for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); 
return EXIT_SUCCESS; 
}
64 / 160 
La necesidad de funciones virtuales 
#include <cstdlib> 
#include <cstdio> 
class Shape { 
public: 
const char * getName() const { return "Shape"; }; 
}; 
class Rectangle : public Shape { 
public: 
const char * getName() const { return "Rectangle"; } 
}; 
class Circle : public Shape { 
public: 
const char * getName() const { return "Circle"; } 
}; 
class Triangle : public Shape { 
public: 
const char * getName() const { return "Triangle"; } 
}; 
int main() { 
Rectangle r1, r2; 
Circle c1, c2, c3; 
Triangle t1; 
Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; 
for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); 
return EXIT_SUCCESS; 
} 
Shape 
Shape 
Shape 
Shape 
Shape 
Shape
65 / 160 
Funciones virtuales 
#include <cstdlib> 
#include <cstdio> 
class Shape { 
public: 
virtual const char * getName() const = 0; 
}; 
class Rectangle : public Shape { 
public: 
virtual const char * getName() const { return "Rectangle"; } 
}; 
class Circle : public Shape { 
public: 
virtual const char * getName() const { return "Circle"; } 
}; 
class Triangle : public Shape { 
public: 
virtual const char * getName() const { return "Triangle"; } 
}; 
int main() { 
Rectangle r1, r2; 
Circle c1, c2, c3; 
Triangle t1; 
Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; 
for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); 
return EXIT_SUCCESS; 
}
66 / 160 
Funciones virtuales 
Rectangle 
Circle 
Triangle 
Rectangle 
Circle 
Circle 
#include <cstdlib> 
#include <cstdio> 
class Shape { 
public: 
virtual const char * getName() const = 0; 
}; 
class Rectangle : public Shape { 
public: 
virtual const char * getName() const { return "Rectangle"; } 
}; 
class Circle : public Shape { 
public: 
virtual const char * getName() const { return "Circle"; } 
}; 
class Triangle : public Shape { 
public: 
virtual const char * getName() const { return "Triangle"; } 
}; 
int main() { 
Rectangle r1, r2; 
Circle c1, c2, c3; 
Triangle t1; 
Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; 
for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); 
return EXIT_SUCCESS; 
}
67 / 160 
¿Cómo funcionan las funciones virtuales? 
vptr 
name 
layer 
color alignment 
class Shape { 
public: 
Shape(const char * n); 
inline const char * getName() const { return name; } 
inline int getLayer() const { return layer; } 
inline char getColor() const { return color; } 
virtual draw(int x, int y); 
protected: 
const char * name; 
int layer; 
char color; 
};
68 / 160 
¿Cómo funcionan las funciones virtuales? 
vptr type_info 
name 
layer 
color alignment 
draw 
type_info 
draw 
vtable
69 /6 91 6/ 700 
Implementación de las funciones virtuales 
Implementación en C++ 
class Virt { 
int a, b; 
virtual void foo(int); 
}; 
void f(Virt *v) { 
v->foo(x); 
} 
Implementación equivalente en C 
typedef struct VtableT { 
void *(*foo)(Virt * this, int x); 
} Vtable; 
typedef struct VirtT { 
int a, b; 
Vtable * vptr; 
} Virt; 
void f(Virt *v) 
{ 
(*(v->vptr.foo))(v, x); 
}
70 / 160 
Herencia múltiple con métodos virtuales 
vptr 
name 
layer 
color alignment 
file 
radius 
class Shape { 
public: 
Shape(const char * n); 
inline const char * getName() const { return name; } 
inline int getLayer() const { return layer; } 
inline char getColor() const { return color; } 
virtual void draw(int x, int y); 
protected: 
const char * name; 
int layer; 
char color; 
}; 
class Storage { 
public: 
bool save(int len, const char * buffer); 
bool load(int maxlen, char * buffer); 
private: 
FILE * file; 
}; 
class Circle : public Shape, public Storage { 
public: 
Circle(int r) : Shape("Circle"), radius(r) { } 
inline int getRadius() const { return radius; } 
virtual draw(int x, int y); 
private: 
int radius; 
};
71 / 160 
Funciones virtuales puras. Interfaces 
class IName { 
public: 
virtual const char * getName() const = 0; 
}; 
class Shape : public IName { 
public: 
Shape(const char * n) : name(n) { } 
virtual const char * getName() const { return name; } // IName 
protected: 
const char * name; 
}; 
class Rectangle : public Shape { 
public: 
Rectangle(int h, int w); 
inline int getHeight() const { return height; } 
inline int getWidth() const { return width; } 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) : 
Shape("Rectangle"), height(h), width(w) { }
72 / 160 
Funciones virtuales puras. Interfaces 
class IName { 
public: 
virtual const char * getName() const = 0; 
}; 
class Shape : public IName { 
public: 
Shape(const char * n) : name(n) { } 
virtual const char * getName() const { return name; } // IName 
protected: 
const char * name; 
}; 
class Rectangle : public Shape { 
public: 
Rectangle(int h, int w); 
inline int getHeight() const { return height; } 
inline int getWidth() const { return width; } 
private: 
int height; 
int width; 
}; 
Rectangle::Rectangle(int h, int w) : 
Shape("Rectangle"), height(h), width(w) { } 
Interfaz 
Clase base 
Clase derivada
73 / 160 
Herencia virtual 
Herencia no virtual Herencia virtual
74 / 160 
El problema del diamante: Herencia Virtual 
class Storable { 
public: 
Storable(const char*); 
virtual void read(); 
virtual void write(); 
virtual ~Storable(); 
private: 
... 
} 
class Transmitter: public Storable { 
public: 
void write(); 
... 
} 
class Receiver: public Storable { 
public: 
void read(); 
... 
}; 
class radio: public Transmitter, public Receiver { 
public: 
void read(); 
... 
};
75 / 160 
El problema del diamante: Herencia Virtual 
class Transmitter: public virtual Storable { 
public: 
void read(); 
... 
} 
class Receiver: public virtual Storable { 
public: 
void read(); 
... 
} 
class Radio: public Transmitter, public Receiver { 
public: 
void read(); 
... 
}; 
Radio::Radio () : 
Storable(10), Transmitter(), Receiver() { }
Modificadores
77 / 160 
Modificadores de métodos de clase 
● Métodos en línea (inline): El código generado para la función se 
insertará en el punto donde se invoca a la función, en lugar de 
invocarlo mediante una llamada. 
● Métodos constantes (const): Cuando una función miembro no 
deba modificar ningún elemento de la clase, es conveniente 
declararla como constante. Esto impedirá que la función 
modifique los datos del objeto y permitirá acceder a este método 
desde objetos declarados como constantes. 
● Métodos con un valor de retorno constante: Cuando se 
devuelvan punteros o referencias a elementos internos que no 
deban ser modificados, es conveniente devolverlos como valores 
constantes. 
● Miembros estáticos (static): Este tipo de componentes son 
esencialmente elementos globales, de los que sólo existirá una 
copia que compartirán todos los objetos de la misma clase. 
● Constructores explícitos (explicit): Indica al compilador que no 
use de forma automática las conversiones implícitas.
78 / 160 
El modificador const 
int main() { 
int var = 1; 
const int const_var = 1; 
int * pnt_to_var = &var; 
const int * pnt_to_const_var = &var; 
int * const const_pnt_to_var = &var; 
var = 2; 
ccoonnsstt__vvaarr == 22;; //// EERRRROORR 
*pnt_to_var = 2; 
**ppnntt__ttoo__ccoonnsstt__vvaarr == 22;; //// EERRRROORR 
*const_pnt_to_var = 2; 
pnt_to_var = NULL; 
pnt_to_const_var = NULL; 
ccoonnsstt__ppnntt__ttoo__vvaarr == NNUULLLL;; //// EERRRROORR 
return EXIT_SUCCESS; 
}
79 / 160 
Métodos constantes 
class A { 
public: 
A() : state(0) { 
} 
void setState(int new_state) { 
state = new_state; 
} 
int getState() const { 
return state; 
} 
private: 
int state; 
}; 
int main() { 
A a; 
a.setState(5); 
a.getState(); 
const A b; 
bb..sseettSSttaattee((55));; //// EErrrroorr 
b.getState(); 
return EXIT_SUCCESS; 
}
80 / 160 
Métodos constantes y punteros 
class A { 
public: 
A() : pointer(NULL) { 
} 
A(const A & other) : pointer(other.pointer) { 
} 
void setPointer(int * new_pointer) { 
pointer = new_pointer; 
} 
void setPointer(int & new_pointer) { 
pointer = &new_pointer; 
} 
int * getPointer() const { 
return pointer; 
} 
private: 
int * pointer; 
}; 
int main() { 
int val; 
A a; 
a.setPointer(&val); 
a.setPointer(val); 
a.getPointer(); 
const A b = a; 
bb..sseettPPooiinntteerr((&&vvaall));; //// EErrrroorr 
bb..sseettPPooiinntteerr((vvaall));; //// EErrrroorr 
b.getPointer(); 
*b.getPointer() = 5; 
return EXIT_SUCCESS; 
}
81 / 160 
Métodos constantes y retornos constantes 
class A { 
public: 
A() : pointer(NULL) { 
} 
A(const A & other) : pointer(other.pointer) { 
} 
void setPointer(int * new_pointer) { 
pointer = new_pointer; 
} 
void setPointer(int & new_pointer) { 
pointer = &new_pointer; 
} 
int * getPointer() const { 
return pointer; 
} 
const int * getConstPointer() const { 
return pointer; 
} 
private: 
int * pointer; 
}; 
int main() { 
int val; 
A a; 
a.setPointer(&val); 
a.setPointer(val); 
a.getPointer(); 
*a.getPointer() = 5; 
**aa..ggeettCCoonnssttPPooiinntteerr(()) == 55;; //// EErrrroorr 
const A b = a; 
bb..sseettPPooiinntteerr((&&vvaall));; //// EErrrroorr 
bb..sseettPPooiinntteerr((vvaall));; //// EErrrroorr 
b.getPointer(); 
*b.getPointer() = 5; 
**bb..ggeettCCoonnssttPPooiinntteerr(()) == 55;; //// EErrrroorr 
return EXIT_SUCCESS; 
}
82 / 160 
Métodos constantes 
class A { 
public: 
A() : pointer(NULL) { 
} 
A(const A & other) : pointer(other.pointer) { 
} 
void setPointer(int * new_pointer) { 
pointer = new_pointer; 
} 
void setPointer(int & new_pointer) { 
pointer = &new_pointer; 
} 
int * getPointer() { 
return pointer; 
} 
const int * getPointer() const { 
return pointer; 
} 
private: 
int * pointer; 
}; 
int main() { 
int val; 
A a; 
a.setPointer(&val); 
a.setPointer(val); 
a.getPointer(); 
*a.getPointer() = 5; 
const A b = a; 
bb..sseettPPooiinntteerr((&&vvaall));; //// EErrrroorr 
bb..sseettPPooiinntteerr((vvaall));; //// EErrrroorr 
b.getPointer(); 
**bb..ggeettPPooiinntteerr(()) == 55;; //// EErrrroorr 
return EXIT_SUCCESS; 
}
83 / 160 
Variables y métodos de clase (static) 
● Pertenecen a la clase, y no a los objetos que puedan crearse de ella. 
● Sus valores son compartidos por todos los objetos de esa clase. 
● No se puede usar el puntero this. No hay ningún objeto que 
referenciar. 
● Van precedidas del modificador static. 
● Para referenciar una variable estática, o invocar a un método estático, 
no es necesario crear un objeto de la clase. 
class Particle { 
public: 
Particle(); 
Particle(const & Particle p); 
~Particle(); 
static inline int NumParticles() { return num_particles; } 
static int num_particles; 
}; 
int Particle::num_particles = 0; 
Particle::Particle() { ++num_particles; } 
Particle::Particle(const & Particle p) { ++num_particles; } 
Particle::~Particle() { --num_particles; } 
Particle::NumParticles(); 
Particle::num_particles();
Modificador explicit en conversiones de datos 
84 / 160 
struct ClaseUno { 
ClaseUno() { } 
}; 
struct ClaseDos { 
ClaseDos(const ClaseUno &) { } 
}; 
void func(ClaseDos) { } 
int main() { 
ClaseUno uno; 
func(uno); // Quiere una clase ClaseDos, pero tiene una ClaseUno 
} 
struct ClaseUno { 
ClaseUno() {} 
}; 
struct ClaseDos { 
explicit ClaseDos(const ClaseUno &) { } 
}; 
void func(ClaseDos) { } 
int main() { 
ClaseUno uno; 
// func(uno); //Mal: No se hace una conversion automatica 
func(ClaseDos(uno)); // Bien: La conversion es realizada explicitamente 
}
Relaciones entre clases
86 / 160 
Relaciones entre clases: herencia 
La clase derivada es semejante a la clase original, pero con algunas 
propiedades o métodos añadidos o modificados. La clase derivada -o 
subclase- es una especialización -o extensión- de la clase base -o 
superclase-. 
Ejemplo: Una moto, o un coche, son un tipo especial de vehículos.
87 / 160 
Relaciones entre clases: herencia 
class Vehicle { 
public: 
int Length; 
int Width; 
int Height; 
int Weight; 
}; 
class MotorVehicle : public Vehicle { 
public: 
int HorsePower; 
int MaxSpeed; 
}; 
class Car : public MotorVehicle { 
public: 
int NumDoors; 
};
88 / 160 
Relaciones entre clases: agregación 
La clase agregada tiene una relación “débil” con la clase que contiene la 
agregación. La destrucción de un objeto de la clase contenedora no implica 
la destrucción de los objetos que están agregados por el mismo. 
Ejemplo: Yo tengo una relación con mis amigos, pero no les “poseo”.
89 / 160 
Relaciones entre clases: agregación 
class Car { 
public: 
int NumDoors; 
}; 
class Road { 
public: 
static const int MaxNumVehicles = 4; 
Vehicle * Vehicles[MaxNumVehicles]; 
};
90 / 160 
Relaciones entre clases: composición 
La composición define una relación “fuerte” entre objetos. El objeto 
contenedor “posee” los objetos que están contenidos en él, de tal forma que 
la destrucción del mismo implica la destrucción de todas sus partes. 
Ejemplo: Una mesa contiene un tablero y varias patas.
91 / 160 
Relaciones entre clases: composición 
class Wheel { 
int Radius; 
int Wear; 
int Pressure; 
}; 
class Car { 
public: 
static const int NumWheels = 4; 
Wheel Wheels[NumWheels]; 
int NumDoors; 
};
92 / 160 
Relaciones entre clases: implementación 
La implementación de un 
interfaz equivale a la 
aceptación de un contrato 
entre las partes 
relacionadas, de tal forma 
que el interfaz define de 
qué formas puede 
interaccionar la clase con 
el resto de objetos. 
En C++ no existe 
específicamente la figura 
del interfaz, y se 
implementan con clases 
abstractas en las que 
todos sus métodos son 
virtuales. 
Un interfaz no debe 
contener atributos. 
Unos interfaces pueden 
heredar de otros, y añadir 
nuevos métodos.
93 / 160 
Relaciones entre clases: implementación 
class IDrivable { 
virtual void SpeedUp(int value) = 0; 
virtual void Brake(int value) = 0; 
virtual void Turn(int value) = 0; 
}; 
class Car : public IDrivable { 
public: 
virtual void SpeedUp(int value) { ... } 
virtual void Brake(int value) { ... } 
virtual void Turn(int value) { ... } 
int NumDoors; 
};
94 / 160 
Habitualmente se usan todas ellas 
class Vehicle { 
public: 
int Length; 
int Width; 
int Height; 
int Weight; 
}; 
class MotorVehicle : public Vehicle { 
public: 
int HorsePower; 
int MaxSpeed; 
}; 
class Wheel { 
int Radius; 
int Wear; 
int Pressure; 
}; 
class IDrivable { 
virtual void SpeedUp(int value) = 0; 
virtual void Brake(int value) = 0; 
virtual void Turn(int value) = 0; 
}; 
class Car : public MotorVehicle, public IDrivable { 
public: 
virtual void SpeedUp(int value) { ... } 
virtual void Brake(int value) { ... } 
virtual void Turn(int value) { ... } 
static const int NumWheels = 4; 
Wheel Wheels[NumWheels]; 
int NumDoors; 
}; 
class Road { 
public: 
static const int MaxNumVehicles = 4; 
Vehicle * Vehicles[MaxNumVehicles]; 
};
La Programación Genérica
96 / 160 
La Programación Genérica 
● En su definición más sencilla, es un estilo de programación 
centrado en los algoritmos, en el que éstos se programan 
en función de tipos de datos que serán especificados 
más tarde. Este enfoque permite escribir funciones y 
estructuras que se diferencian sólo en el conjunto de tipos 
de datos sobre los que se opera, lo que reduce la 
duplicación de código. 
● En un sentido más específico, describe un paradigma de 
programación en el que los requisitos fundamentales 
sobre los tipos se abstraen de ejemplos concretos de 
algoritmos y estructuras de datos y se formalizan como 
conceptos, y en el que las funciones se implementan de 
forma genérica en términos de estos conceptos. 
● En C++ se usan templates (o plantillas) para permitir el 
uso de técnicas de programación genéricas.
97 / 160 
Ejemplo de templates en C++ 
template <typename T> 
T max(T x, T y) { 
return x < y ? y : x; 
} 
Cuando especializa esa función templatizada, el compilador instancia una versión se esa 
función, en la que el tipo genérico T es sustituido por el tipo de dato que queramos usar: 
std::cout << max(3, 7); // el resultado es 7 
El compilador genera entonces, de forma automática, una función correspondiente a la 
sustitución de T por int: 
int max(int x, int y) { 
return x < y ? y : x; 
} 
La función resultante de la especialización de una función genérica puede ser usada 
como cualquier otra función dentro del lenguaje. 
Como se puede ver en el código, los requisitos necesarios para poder usar esta función 
con un tipo de datos cualquiera son: 
● Existencia del operador < para el tipo de dato T 
● Existencia de un operador asignación para T
98 / 160 
Templates: Cálculo del máximo 
// Maximo de dos valores enteros 
inline int const& max (int const& a, int const& b) { 
return a < b ? b : a; 
} 
// Maximo de dos valores de cualquier tipo 
template <typename T> 
inline T const& max (T const& a, T const& b) { 
return a < b ? b : a; 
} 
// Maximo de tres valores de cualquier tipo 
template <typename T> 
inline T const& max (T const& a, T const& b, T const& c) { 
return ::max (::max(a,b), c); 
} 
int main() { 
::max(7, 42, 68); // calls the template for three arguments 
::max(7.0, 42.0); // calls max<double> (by argument deduction) 
::max('a', 'b'); // calls max<char> (by argument deduction) 
::max(7, 42); // calls the nontemplate for two ints 
::max<>(7, 42); // calls max<int> (by argument deduction) 
::max<double>(7, 42); // calls max<double> (no argument deduction) 
::max('a', 42.7); // calls the nontemplate for two ints 
} 
Fuente: http://www.josuttis.com/tmplbook/basics/max2.cpp.html
99 / 160 
Templates: Singleton 
template <class T> 
class Singleton { 
public: 
static T* Instance() { 
if(!m_pInstance) m_pInstance = new T; 
assert(m_pInstance != NULL); 
return m_pInstance; 
} 
protected: 
Singleton(); 
~Singleton(); 
private: 
Singleton(Singleton const&); 
Singleton& operator=(Singleton const&); 
static T* m_pInstance; 
}; 
template <class T> T* Singleton<T>::m_pInstance = NULL; 
class Logger { 
// ... 
}; 
int main () { 
// ... 
Singleton<Logger>::Instance()->openLogFile("logFile.txt"); 
// ... 
Archivo .h 
Archivo .cpp 
} Fuente: http://www.yolinux.com/TUTORIALS/C++Singleton.html
100 / 160 
Especialización de templates 
// Template vacio por omision 
template <bool b> 
struct StaticAssert {}; 
// Template especializado en true 
template <> 
struct StaticAssert<true> { 
static void assert() {} 
}; 
int f() { 
// Compila correctamente, existe el miembro assert() 
StaticAssert<1==1>::assert(); 
// Error de compilacion, no existe assert() para StaticAssert<false> 
StaticAssert<1==2>::assert(); 
}
Algunos patrones de diseño
102 / 160 
Los Patrones de Diseño 
● Un patrón de diseño es una solución estandarizada a un problema 
de diseño. 
● Para que una solución sea considerada un patrón debe poseer ciertas 
características: 
● Debe haber comprobado su efectividad resolviendo problemas 
similares en ocasiones anteriores. 
● Debe ser reutilizable, lo que significa que es aplicable a diferentes 
problemas de diseño en distintas circunstancias. 
● Los patrones de diseño pretenden: 
● Proporcionar catálogos de elementos reusables en el diseño de 
sistemas software. 
● Evitar la reiteración en la búsqueda de soluciones a problemas ya 
conocidos y solucionados anteriormente. 
● Formalizar un vocabulario común entre diseñadores. 
● Estandarizar el modo en que se realiza el diseño. 
● Facilitar el aprendizaje de las nuevas generaciones de 
diseñadores condensando conocimiento ya existente.
103 / 160 
Abstract Factory Pattern (estructural) 
Proporciona una interfaz para crear familias de objetos 
relacionados o dependientes, sin especificar sus clases 
concretas. Se utiliza este patrón cuando se necesita: 
● Crear una familia de objetos relacionados, diseñada para 
ser utilizada en conjunto. 
● Que un sistema sea independiente de la forma en que 
sus productos son creados, compuestos o 
representados. 
● Que un sistema sea configurado con una de múltiples 
familias de productos. 
● Proporcionar una biblioteca de clases de productos, y 
sólo se quiere revelar sus interfaces, no sus 
implementaciones. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Abstract%20Factory%20Pattern
104 / 160 
Abstract Factory Pattern (estructural) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Abstract%20Factory%20Pattern
105 / 160 
Adapter Pattern (estructural) 
Transforma la interfaz de un objeto existente en otra que 
los clientes puedan utilizar. De este modo, una clase que 
no puede utilizar la primera, puede hacer uso de ella a 
través de la segunda. Se utiliza este patrón cuando se 
necesita: 
● Utilizar una clase existente, Usando composición 
pero su interfaz no coincide 
con la que se necesita. 
● Crear una clase reutilizable que coopera con clases que 
no tienen interfaces compatibles. 
● Utilizar varias subclases existentes, pero como es poco 
práctico adaptar cada interfaz, se crea un objeto que 
adapte la interfaz de la clase padre. 
Usando herencia múltiple 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Adapter%20Pattern
106 / 160 
Adapter Pattern (estructural) 
Usando composición 
Usando herencia múltiple 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Adapter%20Pattern
107 / 160 
Decorator Pattern (estructural) 
Extiende la funcionalidad de un objeto en forma dinámica, 
proporcionando una alternativa flexible a la creación de 
subclases. Se utiliza este patrón cuando se necesita: 
● Añadir responsabilidades a objetos individuales dinámica 
y transparente, es decir, sin afectar a otros objetos. 
● Retirar responsabilidades de algunos objetos. 
● La extensión por subclases es poco práctica. Por 
ejemplo, un gran número de extensiones independientes 
son posibles y produciría una explosión de subclases 
por cada combinación. También cuando la definición de 
clase puede estar oculta o no disponible para subclases. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Decorator%20Pattern
108 / 160 
Decorator Pattern (estructural) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Decorator%20Pattern
109 / 160 
Facade Pattern (estructural) 
Proporciona una interfaz unificada para un conjunto de 
interfaces de un sistema, y hace que los subsistemas sean 
mas facil de usar. Se utiliza este patrón cuando se 
necesita: 
● Minimizar la comunicación y las dependencias entre 
subsistemas. 
● Proporcionar una interfaz sencilla para un subsistema 
complejo. 
● Eliminar dependencias entre clientes y clases de 
implementación, porque son demasiadas. 
● Dividir conjuntos de subsistemas en capas. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Facade%20Pattern
110 / 160 
Facade Pattern (estructural) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Facade%20Pattern
111 / 160 
Iterator Pattern (de comportamiento) 
Proporciona una forma de acceder secuencialmente a los 
elementos de un objeto agregado, sin exponer su 
representación interna. Se utiliza este patrón cuando se 
necesita: 
● Para acceder al contenido de un objeto agregado sin 
exponer su representación interna. 
● Para apoyar recorridos múltiples sobre objetos 
agregados. 
● Para proporcionar una interfaz uniforme para atravesar 
diferentes estructuras agregadas (es decir, para apoyar 
iteración polimórfica). 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Iterator%20Pattern
112 / 160 
Iterator Pattern (de comportamiento) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Iterator%20Pattern
113 / 160 
Observer Pattern (de comportamiento) 
Define una dependencia de uno-a-muchos con otros 
objetos, de forma que cuando un objeto cambia de estado 
todos sus dependientes son notificados y actualizados 
automáticamente. Se utiliza este patrón cuando se 
necesita: 
● Cuando una abstracción tiene dos aspectos 
dependientes. Encapsular éstos en objetos separados 
permite modificarlos y usarlos de forma independiente. 
● Cuando un cambio en un objeto requiere cambiar a los 
demás, y no se sabe cuáles ni cuántos objetos serán. 
● Cuando un objeto debe ser capaz de notificar a otros 
objetos sin hacer suposiciones acerca de quién son 
estos objetos. En otras palabras, no se quiere que estos 
objetos estén estrechamente acoplados. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Observer%20Pattern
114 / 160 
Observer Pattern (de comportamiento) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Observer%20Pattern
115 / 160 
Singleton Pattern (creacional) 
Garantiza que una clase tenga únicamente una instancia y 
proporciona un punto de acceso global a la misma. Se 
utiliza este patrón cuando se necesita: 
● Debe haber exactamente una instancia de una clase, y 
debe ser accesible a los clientes desde un punto de 
acceso conocido. 
● La instancia única debe ser extensible por medio de 
subclases, y los clientes deben ser capaces de utilizar 
esta instancia extendida sin modificar su código. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Singleton%20Pattern
116 / 160 
Singleton Pattern (creacional) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Singleton%20Pattern
117 / 160 
State Pattern (de comportamiento) 
Altera el comportamiento de un objeto según el estado 
interno en que se encuentre. Así, el objeto aparentará 
cambiar de clase. Se utiliza este patrón cuando se 
necesita: 
● El comportamiento de un objeto depende de su estado, y 
tiene que cambiar su comportamiento en tiempo de 
ejecución en función de ese estado. 
● Se presentan muchos condicionales en el código. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/State%20Pattern
118 / 160 
State Pattern (de comportamiento) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/State%20Pattern
119 / 160 
Strategy Pattern (de comportamiento) 
Define un conjunto de clases que representan 
comportamientos similares: se trata de hacer lo mismo, 
pero de diferente manera. Permite que un algoritmo varíe 
independientemente de los clientes que lo utilizan, y 
puedan intercambiarlos en tiempo de ejecución. Se utiliza 
este patrón cuando se necesita: 
● Muchas clases relacionadas difieren sólo en su 
comportamiento. 
● Se necesita diferentes variantes de un algoritmo. 
● Se presentan muchos condicionales en el código, es 
posible que sea necesario aplicar este patrón. 
● Si un algoritmo utiliza información que no deberían 
conocer los clientes, la utilización del patrón estrategia 
evita la exposición de dichas estructuras. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Strategy%20Pattern
120 / 160 
Strategy Pattern (de comportamiento) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Strategy%20Pattern
121 / 160 
Template Pattern (de comportamiento) 
Define el esqueleto de un algoritmo, dejando que las 
subclases redefinan ciertos pasos, pero sin cambiar su 
estructura. Se utiliza este patrón cuando se necesita: 
● Aplicar las partes invariables de un algoritmo una vez y 
dejar en manos de las subclases la implementación del 
comportamiento que puede variar. 
● Evitar la replicación de código mediante generalización: 
se factoriza el comportamiento común de varias 
subclases en una única superclase. 
● Controlar las extensiones de las subclases. El Método 
Plantilla utiliza métodos especiales (métodos de 
enganche o hooks) en ciertos puntos, siendo los únicos 
puntos que pueden ser redefinidos y, por tanto, los 
únicos puntos donde es posible la extensión. 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Template%20Pattern
122 / 160 
Template Pattern (de comportamiento) 
Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Template%20Pattern
Metaprogramación
124 / 160 
Metaprogramación basada en plantillas 
● La Metaprogramación basada en plantillas o Template 
metaprogramming (TMP) es una técnica en la que, mediante 
el uso de plantillas, el compilador genera un código 
fuente temporal que es añadido al resto del código del 
programa antes de que éste sea compilado. 
● La salida de estas plantillas incluyen constantes en tiempo 
de compilación, estructuras de datos y funciones 
completas. 
● El uso de plantillas puede ser interpretado como “ejecución 
en tiempo de compilación”. 
● Históricamente, la TMP fue descubierta accidentalmente 
durante el proceso de estandarización del lenguaje C++, al 
darse cuenta de que el sistema de plantillas de C++ es 
Turing-completo (es decir, que tiene un poder 
computacional equivalente a la máquina universal de Turing 
y, por tanto, se puede programar cualquier cosa en él).
125 / 160 
TMP: Valores y Funciones 
#include <cstdlib> 
#include <iostream> 
struct NumberTwoHolder { 
enum { value = 2 }; 
}; 
template<int N> 
struct ValueHolder { 
enum { value = N }; 
}; 
template<int X, int Y> 
struct Adder { 
enum { result = X + Y }; 
}; 
struct TypeHolder { 
typedef int value; 
}; 
int main() { 
std::cout << NumberTwoHolder::value << std::endl; // 2 
std::cout << ValueHolder<3>::value << std::endl; // 3 
std::cout << Adder<3,4>::result << std::endl; // 7 
std::cout << sizeof(TypeHolder::value) << std::endl; // 4 
return EXIT_SUCCESS; 
}
126 / 160 
TMP: Diferentes líneas de ejecución 
template<typename X, typename Y> 
struct SameType 
{ 
enum { result = 0 }; 
}; 
template<typename T> 
struct SameType<T, T> 
{ 
enum { result = 1 }; 
}; 
if (SameType<SomeThirdPartyType, int>::result) 
{ 
// ... codigo optimizado, asumiendo que el tipo es un entero 
} 
else 
{ 
// ... codigo defensivo que no hace ninguna suposicion sobre el tipo 
}
127 / 160 
TMP: Recursión 
template <unsigned n> 
struct factorial 
{ 
enum { value = n * factorial<n-1>::value }; 
}; 
template <> 
struct factorial<0> 
{ 
enum { value = 1 }; 
}; 
int main() { 
// Como los calculos se realizan en tiempo de compilacion, 
// se puede usar para cosas como el tamaño de los arrays 
int array[ factorial<7>::value ]; 
}
TMP: Ejemplo: “if” en tiempo de compilación 
128 / 160 
#include <cstdlib> 
#include <iostream> 
template <bool Condition, typename TrueResult, typename FalseResult> 
class if_; 
template <typename TrueResult, typename FalseResult> 
struct if_<true, TrueResult, FalseResult> { 
typedef TrueResult result; 
}; 
template <typename TrueResult, typename FalseResult> 
struct if_<false, TrueResult, FalseResult> { 
typedef FalseResult result; 
}; 
int main() { 
typename if_<true, int, void*>::result number(3); 
typename if_<false, int, void*>::result pointer(&number); 
typedef typename if_<(sizeof(void *) > sizeof(uint32_t)), uint64_t, uint32_t>::result 
integral_ptr_t; 
integral_ptr_t converted_pointer = reinterpret_cast<integral_ptr_t>(pointer); 
std::cout << sizeof(void *) << std::endl; 
std::cout << sizeof(uint32_t) << std::endl; 
std::cout << sizeof(integral_ptr_t) << std::endl; 
return EXIT_SUCCESS; 
}
129 / 160 
TMP: Ejemplo: Comprobaciones estáticas 
template<class T, class B> struct Derived_from { 
static void constraints(T * p) { 
B * pb = p; pb = pb; 
} 
Derived_from() { 
void(*p)(T*) = constraints; p = p; 
} 
}; 
template<class T1, class T2> struct Can_copy { 
static void constraints(T1 a, T2 b) { 
T2 c = a; b = a; c = a; b = a; 
} 
Can_copy() { 
void(*p)(T1,T2) = constraints; 
} 
}; 
template<class T1, class T2 = T1> struct Can_compare { 
static void constraints(T1 a, T2 b) { 
a == b; a != b; a < b; 
} 
Can_compare() { 
void(*p)(T1,T2) = constraints; 
} 
};
130 / 160 
TMP: Ejemplo: Lista de Valores (1) 
#include <cstdlib> 
#include <iostream> 
struct NullNumList {}; 
template<size_t H, typename T> 
struct NumList { 
enum { head = H }; 
typedef T tail; 
}; 
template<typename NL> 
struct binaryOr; 
template<size_t NL_H, typename NL_TAIL> 
struct binaryOr<NumList<NL_H, NL_TAIL> > { 
enum { value = NL_H | binaryOr<NL_TAIL>::value }; 
}; 
template<> 
struct binaryOr<NullNumList> { 
enum { value = 0 }; 
};
131 / 160 
TMP: Ejemplo: Lista de Valores (y 2) 
template<char T> 
struct MyList; 
template<> 
struct MyList<'a'> { 
Typedef NumList<1, 
NumList<2, 
NullNumList> > 
data; // 1 | 2 = 3 
}; 
template<> 
struct MyList<'b'> { 
Typedef NumList<1, 
NumList<4, 
NumList<8, 
NullNumList> > > 
data; // 1 | 4 | 8 = 13 
}; 
int main() { 
std::cout << binaryOr<MyList<'a'>::data >::value << std::endl; // 3 
std::cout << binaryOr<MyList<'b'>::data >::value << std::endl; // 13 
return EXIT_SUCCESS; 
}
C++ como lenguaje multiparadigma
133 / 160 
¿Qué quiere decir multiparadigma? 
● C++ no es solamente un lenguaje orientado a objetos, sino 
que es compatible con muchos estilos diferentes de 
programación, o paradigmas. La programación orientada 
a objetos es sólo uno de ellos. 
● Ningún paradigma es capaz de resolver todos los 
problemas de forma sencilla y eficiente, por lo que es muy 
útil poder elegir el que más conviene para cada tarea. 
● Habitualmente se combinan diferentes tipos de 
paradigmas dentro de los programas.
134 / 160 
C++ como ensamblador de alto nivel 
● C++ permite programar de una forma muy cercana al propio 
funcionamiento de la máquina. 
● La programación imperativa describe las operaciones en términos del estado 
de un programa, y de operaciones que cambian dicho estado. Los programas 
imperativos son un conjunto de instrucciones que le indican al ordenador 
cómo realizar una tarea. 
● El hardware habitual de los ordenadores actuales implementa el concepto de 
máquina de Turing y, por tanto, está diseñado para ejecutar código escrito en 
forma imperativa. 
● C++ hereda de C un sistema de tipos de datos que se pueden mapear de una 
forma muy cercana a los tipos nativos de la CPU, y operaciones primitivas que 
también se pueden mapear de una forma muy directa a instrucciones en 
código máquina. 
● Se pueden incorporar instrucciones directas en ensamblador dentro del 
programa, lo que permite un control muy exacto del programa resultante, a 
cambio de perder en claridad y portabilidad. 
● Esta forma de programación puede resultar muy críptica y oscura a veces, 
pero a la hora de hacer desarrollos de bajo nivel, incluidos los componentes 
que interaccionan con el hardware o aquellos que necesitan un alto nivel de 
optimización, es imprescindible.
135 / 160 
C++ como ensamblador de alto nivel 
uint8_t mask = 0x3F; 
mask |= 0x40; 
uint16_t reg1 = 0x25; 
uint16_t reg2 = reg1 << 3; 
if (tp->pending & tp->ewmask) != 0) { 
do_e(tp); 
} else { 
queue->add(tp); 
}
136 / 160 
Programación estructurada en C++ 
● Este es el estilo de programación clásico heredado de C. El programa 
comienza en una función principal, llamada main, que llama a otras funciones, 
que a su vez llaman a otras. 
● El flujo de ejecución del programa está controlado por expresiones 
estructuradas como for, while, switch o until. 
● Las variables son visibles dentro del bloque en el que han sido definidas, y no 
son accesibles directamente desde fuera de ese bloque. 
● Las funciones tienen un único punto de entrada, y una única forma de 
terminación. 
● Este estilo de programación incluye también la estructuración de los datos. 
Para ello existe un mecanismo, struct, que permite organizar los datos en 
forma de una única entidad que los englobe, y que puede ser copiada por 
valor, transferida por valor a otras funciones, etc.
137 / 160 
Programación estructurada en C++ 
void funcC(void) { 
for (int i = 0; i < MaxI(); ++i) { 
if (funcB(i)) { 
doSomething() 
} 
} 
while (funcA()) { 
whatever(); 
}; 
}
138 / 160 
Abstracción de datos en C++ 
● Consiste agrupar en componentes, de forma unificada, tanto los datos 
como los métodos que permiten manipularlos. 
● Ejemplos clásicos de esta abstracción de tipos de datos son las pilas y las 
listas. 
● En lugar de usar estructuras de datos con funciones separadas para 
manipular estos datos, las funciones son incorporadas al propio componente 
que los contiene. En el caso de una pila, estas funciones serían las 
operaciones push y pop, por ejemplo. 
● El sello distintivo de este paradigma es el uso de tipos de datos concretos. Por 
ello, las funciones virtuales apenas se usan, y los objetos son copiados y 
asignados libremente. 
● En concreto, los operadores de copia y construcción existen para poder dar 
soporte a este estilo de programación, y Tienen una gran importancia en 
permitir la creación de nuevos tipos de datos que se comporten casi igual que 
los tipos nativos, como int o double.
139 / 160 
Abstracción de datos en C++ 
struct Queue { 
Queue(); 
void push(int v); 
int pop(); 
static const MAX = 29; 
int data[NAX] 
}; 
Queue q; 
q.push(5); 
q.push(3); 
int a = q.pop();
140 / 160 
Programación orientada a objetos en C++ 
● La programación orientada a objetos en C++ se implementa en base a 
clases. 
● Las propiedades de los objetos se almacenan en estructuras (class o struct). 
En ellas se almacena de forma estructurada toda la información relativa a un 
objeto. 
● C++ da soporte también a métodos y propiedades de clase (que son, en 
muchos aspectos, semejantes a las variables y funciones globales). 
● Los mensajes entre objetos se implementan en base a métodos o funciones, 
que se comportan de una forma parecida a las funciones de C, añadiéndoles 
un primer parámetro oculto que referencia la estructura de datos que contiene 
las propiedades del objeto, y que pueden llevar información adicional en forma 
de parámetros. 
● Se puede restringir el acceso a las propiedades o a los métodos de una clase 
mediante los modificadores public, protected y private. 
● El paradigma de orientación a objetos hace un uso extensivo de las funciones 
virtuales y del polimorfismo. 
● En C++, los tipos polimórficos son la referencia y el puntero. Hay que tener 
mucho cuidado con ellos a la hora de copiar o asignar objetos, puesto que la 
asignación de un objeto derivado a una clase base puede implicar que el 
objeto sea truncado, copiándose sólo la información perteneciente al tipo 
base.
141 / 160 
Programación orientada a objetos en C++ 
class IDrivable { 
virtual void SpeedUp(int value) = 0; 
virtual void Brake(int value) = 0; 
virtual void Turn(int value) = 0; 
}; 
class Car : public IDrivable { 
public: 
virtual void SpeedUp(int value) { ... } 
virtual void Brake(int value) { ... } 
virtual void Turn(int value) { ... } 
int NumDoors; 
}; 
IDrivable auto = new Car(); 
Car.SpeedUp(15);
142 / 160 
Programación genérica en C++ 
● La programación genérica es la programación con conceptos (concepts) . 
● Los algoritmos son abstraidos, para permitirles trabajar sobre cualquier tipo de 
dato que pueda satisfacer el interfaz usado por el algoritmo. 
● En la librería estándar de C++, hay componentes como container, iterator o 
algorithm que forman una triada para dar soporte a la programación genérica. 
● Este paradigma está construido también sobre la abstracción de los datos, 
pero tomándola en una dirección diferente a la de la programación orientada a 
objetos. 
● El mecanismo de C++ que permite soportar la programación genérica son las 
plantillas o templates, que es el mecanismo de parametrización de tipos 
provisto por el lenguaje. 
● EL uso de plantillas tiene un precio: las librerías son más difíciles de usar, y 
los problemas se traducen en mensajes de error confusos. 
● Tal y como están definidas en C++98, las plantillas no tienen restricciones, y la 
comprobación de tipos se realiza al final del proceso de compilación, es decir, 
después de combinar la plantilla con definición del tipo de datos. 
● C++11 incluye los conceptos (concepts) para expresar el comportamiento 
sintáctico y semántico de los tipos, y para restringir los parámetros de tipo que 
se pueden usar en una plantilla de C++.
143 / 160 
Programación genérica en C++ 
template <unsigned n> 
struct factorial 
{ 
enum { value = n * factorial<n-1>::value }; 
}; 
template <> 
struct factorial<0> 
{ 
enum { value = 1 }; 
}; 
int main() { 
// Como los calculos se hacen en tiempo de compilacion, 
// se puede usar para cosas como el tamaño de los arrays 
int array[ factorial<7>::value ]; 
}
144 / 160 
Programación funcional en C++ 
● La esencia de la programación funcional consiste en trabajar con valores, en 
lugar de hacerlo con identidades. 
● La principal diferencia entre un valor y una identidad, es que el valor es 
constante e inalterable (el número 1 es siempre el mismo), mientras que el 
valor asociado a una identidad puede cambiar (el contenido de una variable). 
● El modificador const provee un método eficiente para el paso de objetos 
grandes a la hora de trabajar con sus valores, y no con sus identidades. 
● Mediante el uso del modificador const, C++ permite tipos de datos inmutables, 
semejantes a los que se encuentran en la mayor parte de los lenguajes de 
programación funcionales. 
● Sin embargo, trabajar con estos tipos de datos inmutables en C++ es difícil y 
engorroso. En particular, la necesidad de hacer copias completas de objetos 
de gran tamaño para cada pequeño cambio, no es eficiente. 
● C++11 incorpora una serie de herramientas nuevas para facilitar el estilo de 
porgramación funcional en C++. La más importante de ellas quizás sean las 
funciones lambda (también llamadas closures o funciones anónimas). Esta 
funcionalidad, de todas formas, ya estaba accesible en base al uso de 
functors, muy poderosos pero menos prácticos de usar. De hecho, entre 
bastidores, C++ implementa las funciones lambda como functors. 
● C++11 también provee estructuras para trabajar con información compartida, 
de tal forma que se facilite el trabajo eficiente con tipos de datos inmutables.
145 / 160 
Programación funcional en C++ 
#include <iostream> 
// abstract base class for a ontinuation functor 
struct continuation { 
virtual void operator() (unsigned) const = 0; 
}; 
// accumulating continuation functor 
struct accum_cont: public continuation { 
private: 
unsigned accumulator_; 
const continuation &enclosing_; 
public: 
accum_cont(unsigned accumulator, 
const continuation &enclosing) 
: accumulator_(accumulator), 
enclosing_(enclosing) { 
}; 
virtual void operator() (unsigned n) const { 
enclosing_(accumulator_ * n); 
}; 
}; 
void fact_cps (unsigned n, const continuation &c) 
{ 
if (n == 0) 
c(1); 
else 
fact_cps(n - 1, accum_cont(n, c)); 
} 
int main () 
{ 
// continuation which displays argument 
// when called 
struct disp_cont: public continuation { 
virtual void operator() (unsigned n) const { 
std::cout << n << std::endl; 
}; 
} dc; 
// continuation which multiplies argument by 2 
// and displays it when called 
struct mult_cont: public continuation { 
virtual void operator() (unsigned n) const { 
std::cout << n * 2 << std::endl; 
}; 
} mc; 
fact_cps(4, dc); // prints 24 
fact_cps(5, mc); // prints 240 
return 0; 
} 
Factorial Functor 
Fuente: http://stackoverflow.com/questions/1981400/functional-programming-in-c
Los límites de C++
147 / 160 
Programación eficiente en C++ 
● Lo que se haga en tiempo de compilación (o de ensamblado, o enlazado) tiene 
menor coste que lo que se tenga que hacer en ejecución (run-time). 
● Que el coste mínimo de alguna característica de C++ sea bajo, no implica que la 
implementación real de un compilador concreto sea la más optimizada. 
● Las optimizaciones de los compiladores mejoran con el tiempo, y pueden dejar 
obsoletas algunas recomendaciones (como el uso de register e inline). 
● Verifica el coste real de la compilación del código en un compilador determinado. 
● Características de C++ que no tienen por qué tener un coste adicional: 
● Variables static const inicializadas (en vez de #define del preprocesador) 
● Ubicación arbitraria de las declaraciones 
● Referencias (en lugar de punteros) 
● Espacios de nombres 
● Operadores new/delete (en vez del uso de malloc/calloc/free) 
● Sobrecarga de funciones 
● Características de C++ con un coste adicional bajo: 
● Inicialización/Conversión/Terminación de variables 
● Posicionamiento inline del código 
● Herencia múltiple 
● Uso de templates o plantillas 
● Características de C++ con un coste adicional alto: 
● Run-Time Type Identification (RTTI) 
● Uso de excepciones (EH, Exception Handling)
Los compiladores y los tipos de datos en C++ 
● Los compiladores tienen cierta libertad para elegir el tamaño de los tipos 
de datos comunes 
● sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) 
● char por lo menos de tamaño suficiente para el conjunto de caracteres básico 
● short al menos de 16 bits 
● long al menos de 32 bits 
● C++ permite realizar operaciones entre variables de diferente tamaño, o 
combinando con y sin signo. 
148 / 160 
unsigned char a = 200; 
int b = -20; 
a = a + b; 
● Los compiladores generalmente cambian cada tipo a uno de más bits que 
incluye todos los valores posibles del original. 
● La conversión de tipos se hace frecuentemente de forma transparente. 
● Las reglas de conversión de tipos son complejas, tienen en cuenta la 
eficiencia, y dependen del compilador usado. 
● C++ hereda de C el uso de enteros y punteros como booleanos, 
produciéndose una conversión transparente de tipos. 
● Los números en coma flotante dependen del compilador y la arquitectura. 
● Uso de modificadores que afectan al almacenamiento y acceso a la 
memoria, y a las optimizaciones a aplicar: const, volatile.
149 / 160 
La gestión de la memoria en C++ 
● Existen tres tipos principales de memoria en C++: 
● Memoria global (variables estáticas, tienen asignado un espacio en la 
memoria al enlazar, y viven durante toda la ejecución del programa). 
● Memoria dinámica o 'heap' (es asignada dinámicamente con las 
funciones malloc/free o con los operadores new/delete). 
● Memoria local (variables automáticas, se almacenan en la pila, o 'stack') 
● Normalmente, el stack crece en en sentido, y el heap en otro, pero el heap 
puede estar fragmentado, ya que no es una pila 
● En la mayoría de las plataformas, al llamar a una función, se reserva una 
porción de memoria en el stack (llamada 'stack frame') para guardar: 
● La dirección de retorno. 
● Los parámetros que se le pasan a la función. 
● Las variables de la función que sólo viven mientras se ejecuta esta. 
● Ni C ni C++ ponen ninguna restricción de acceso a la memoria. Ni se 
comprueba automáticamente que éste se efectúe dentro de los límites de los 
arrays, ni que los punteros para acceder a la memoria tienen sentido. 
● La gestión de la memoria es decidida por el compilador, que ajusta el 
tamaño de los tipos de datos a lo que más le convenga para adecuarse a sus 
criterios de optimización, y que también suele dejar huecos vacíos entre las 
zonas de memoria usadas ('padding'), para optimizar su acceso. A menudo los 
compiladores tienen opciones para configurar esto ('pack').
150 / 160 
Estructura de la memoria en C y C++ 
Fuente: http://www.bogotobogo.com/cplusplus/assembly.php
151 / 160 
El modelo de memoria en C++ 
● El modelo de memoria de C++ es la especificación de cuándo y por qué se 
lee o se escribe en la memoria real en la ejecución de un programa en C++. 
● Antes de C++11, el modelo de memoria de C++ era el mismo que el de C: 
● Sólo se especifica el comportamiento de las operaciones de memoria 
observables por el programa actual. 
● No se dice nada acerca de los accesos concurrentes a la memoria 
cuando varios procesos, subprocesos o tareas acceden a la misma (no 
existe la noción de memoria compartida, de procesos compartidos ni de 
hilos de ejecución). 
● No se ofrece ninguna forma de especificar un oorrddeenn ddee aacccceessoo aa 
mmeemmoorriiaa (las optimizaciones del compilador incluyen el movimiento de 
código, y los procesadores modernos pueden reordenar los accesos). 
● Por tanto, antes de C++11 sólo se tiene en cuenta la existencia de un solo 
proceso, con un único hilo de ejecución, y no se debe depender de un 
orden específico de acceso a variables en la memoria. 
● Puntos importantes a la hora de tener en cuenta la memoria: 
● Atomicidad: ¿Qué instrucciones tienen efectos indivisibles? 
● Visibilidad: ¿Cuándo son visibles los efectos de un hilo para otro? 
● Orden: ¿Bajo qué condiciones los efectos de las operaciones pueden 
aparecer fuera de orden para otro hilo?
Papel de los registros al trabajar con la memoria 
152 / 160 
Fuente: http://www.bogotobogo.com/cplusplus/assembly.php
Papel de los registros al trabajar con la memoria 
153 / 160 
i = 17; 
j = 20; 
j += i; 
● Leer i de la memoria y guardarlo en un registro 
● Leer j de la memoria y guardarlo en otro registro 
● Sumar los dos valores de los registros usados 
● Almacenar el resultado en la memoria asignada a 
j 
Fuente: http://www.bogotobogo.com/cplusplus/assembly.php
154 / 160 
Estándares de programación en C++ 
● Motor Industry Software Reliability Association (MISRA C++): Forman un 
subconjunto seguro del lenguaje C++ para el desarrollo de los sistemas 
críticos de seguridad en aplicaciones embebidas. Funciona en base a una 
serie de restricciones sobre el uso del lenguaje. La norma se basa en 
estándares de codificación establecidos como MISRA C, Joint Strike Fighter 
Air Vehicle C++ coding standard (JSF++) de Lockheed Martin y High-Integrity 
C++ coding standard (HICPP) de PRQA. 
● Joint Strike Fighter Air Vehicle C++ (JSF++ AV++): Desarrollado por 
Lockheed Martin para ayudar a desarrollar código que se ajuste a los 
principios de seguridad de software crítico. En esencia, se propone que los 
programas están escritos en un subconjunto "más seguro" de C++. 
● High Integrity C++ (HICPP): Presentado por primera vez en 2003 por 
Programming Research, la norma adopta el criterio de que se deben aplicar 
restricciones sobre el lenguaje ISO C++ con el fin de limitar la flexibilidad que 
éste permite. Este enfoque tiene el efecto de minimizar los problemas creados 
por la diversidad de compiladores, los diferentes estilos de programación y los 
aspectos peligrosos y confusos del lenguaje. 
● En términos generales, la eficacia de un estándar depende mucho de lo que 
se pueda automatizar la detección de sus infracciones. La inspección de 
código manual ha demostrado ser ineficaz, costosa, lenta y propensa a 
errores humanos.
155 / 160 
Tipos habituales de normas 
Tipo: Claridad del código 
Descripción: Se trata de escribir código claro, legible y poco confuso, evitando 
construcciones que, siendo perfectamente válidas, puedan hacer el código difícil de leer. 
Ejemplo: Relativas a la instrucción goto (6-6-1, 6-6-2), terminación de bucles for (6-5-6) 
Consejo: Sea flexible, ya que la claridad es una cuestión muy subjetiva. Fomente la 
coherencia entre las y los diferentes desarrolladores. 
Tipo: Simplicidad del código 
Descripción: Mantener el código lo más simple posible, para minimizar los errores y hacer 
más sencillo el análisis. Permite ayudar además a reducir el coste de los tests. 
Ejemplo: uso de continue (6-6-3), eliminación de código no usado (0-1-1, 0-1-2) 
Consejo: Sea flexible, pero ten en cuenta que el incumplimiento de estas normas puede 
afectar a los costes de las pruebas. 
Tipo: Previsibilidad en la ejecución del código 
Descripción: Hacer previsible la ejecución del software en todas las circunstancias, 
eliminando las fuentes de ambigüedad . Esto además ayuda a la portabilidad. 
Ejemplo: No recursividad (7-5-4), no memoria dinámica (18-4-1), no tipos dinámicos en el 
constructor (12-1-1), división de enteros (1-0-3), una única definición (3-2-2, 3-2-3, 3-2-4) 
Consejo: Evite el incumplimiento de las normas relativas a la previsibilidad del código.
Tipo: Programación Defensiva 
Descripción: Cuanto más protegido esté el software ante situaciones inesperadas, por 
improbables que sean, mejor. Esto mejora además la mantenibilidad del software. 
Ejemplo: sentencias switch (6-4-3), no modificación de contadores en los bucles for (6-5- 
3), no dar acceso a variables internas (9-3-2), tener en cuenta los errores (0-3-2) 
Consejo: Sea moderadamente flexible, pero justifique bien las excepciones. 
156 / 160 
Tipos de normas 
Tipo: Conformidad a normas 
Descripción: Siempre que sea posible, hay que intentar adecuarse a normas reconocidas. 
Cumplir estas normas , además, ayuda a mejorar la portabilidad. 
Ejemplo: Uso de formatos estándar de coma flotante: ANSI/IEEE (0-4-3), compiladores 
con interfaz común (1-0-2), set de caracteres (2-2-1), secuencias de escape (2-13-1) 
Consejo: Sea flexible, pero tenga en cuenta los posibles costes de transición en el futuro. 
Tipo: Proceso de desarrollo del software 
Descripción: Se refieren, no tanto al propio código, sino al propio proceso mediante el 
cual se desarrolla éste. 
Ejemplo: Uso de mecanismos de análisis estático y dinámico (0-3-1) 
Consejo: Evite incumplir estas normas, ya que seguirlas proporciona el mayor retorno de 
la inversión
157 / 160 
Las normas MISRA 
● MISRA significa "Motor Industry Software Reliability Association". 
● MISRA-C:1998 tenía 127 normas, de las cuales 93 eran requisitos y 34 
eran recomendaciones; las reglas estaban numeradas 
secuencialemente desde el 1 al 127. 
● MISRA-C:2004 contiene 142 normas, de las cuales 122 son requisitos 
y 20 recomendaciones. Se dividen en 21 categorías temáticas, desde 
"Entorno" hasta "Fallos en tiempo de ejecución" . 
● MISRA-C:2012 contiene 143 normas (el cumplimiento de las cuales es 
analizable mediante el análisis estático del programa) y 16 directivas 
(cuyo cumplimiento está más abierto a la interpretación , o se refiere a 
cuestiones de proceso o de procedimiento), clasificadas por una parte 
como "obligatorias", "necesarias" o "recomendables". 
● MISRA-C++:2008, como era de esperar, incluye un solapamiento 
importante con MISRA C. Sin embargo, el estándar MISRA C++ incluye 
228 normas, aproximadamente un 50% más que el estándar MISRA C, 
ya que comprende además normas relativas a las funciones virtuales , 
manejo de excepciones , espacios de nombres, parámetros de 
referencia, acceso a los datos de la clase encapsuladas, y otras facetas 
específicas del lenguaje C++.
¡Preguntar es gratis!
159 / 160 
Algunos enlaces 
● http://c.conclase.net/curso/ 
● http://es.cppreference.com/w/cpp 
● http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html 
● http://arco.esi.uclm.es/~david.villa/pensar_en_C++/ 
● https://bitbucket.org/crysol_org/pensarenc/overview 
● http://www.learncpp.com/cpp-tutorial/ 
● http://www.cplusplus.com/doc/tutorial/ 
● http://www.zator.com/Cpp/ 
● http://www.doc.ic.ac.uk/~wjk/C++Intro/CourseStructure.html 
● http://www.youtube.com/playlist?list=PL4A486BBFC5AD733B 
● http://mazyod.com/category/software-engineering/ 
● http://www.cdsonline1.co.uk/EmailImages/mae/MAE09_speaker_presentations/MAE2009.ppt 
● http://assembly.ynh.io/ ( https://github.com/ynh/cpp-to-assembly ) 
● http://msdn.microsoft.com/en-us/magazine/jj553512.aspx 
● http://www.open-std.org/jtc1/sc22/wg21/docs/ESC_San_Jose_98_401_paper.pdf 
● http://design-patterns-with-uml.blogspot.com.ar 
● http://en.wikipedia.org/wiki/Software_design_patterns 
● http://www.eventhelix.com/realtimemantra/patterns/
Licencia de este documento 
Copyright © 2014, Miriam Ruiz 
This work is licensed under the Creative 
Commons Attribution-Share Alike 3.0 
(CC-by-sa 3.0) license. You can use, copy, 
modify, merge, remix, distribute, display, 
perform, sublicense and/or sale it freely under 
the conditions defined in that license. 
See http://creativecommons.org/licenses/by-sa/3.0/

Contenu connexe

Tendances

Lenguajes diapositivas
Lenguajes diapositivasLenguajes diapositivas
Lenguajes diapositivas
starduslex
 
Librerias en-lenguaje-c
Librerias en-lenguaje-cLibrerias en-lenguaje-c
Librerias en-lenguaje-c
Kevin2811
 
Republica bolivariana de venezuela
Republica bolivariana de venezuelaRepublica bolivariana de venezuela
Republica bolivariana de venezuela
royimar
 

Tendances (17)

Lenguajec diapositivas
Lenguajec diapositivasLenguajec diapositivas
Lenguajec diapositivas
 
Lenguaje C para Administradores de Red - Script II Punteros
Lenguaje C para Administradores de Red - Script II PunterosLenguaje C para Administradores de Red - Script II Punteros
Lenguaje C para Administradores de Red - Script II Punteros
 
Introduccion al lenguaje c
Introduccion al lenguaje cIntroduccion al lenguaje c
Introduccion al lenguaje c
 
Introduccion al lenguaje de programacion c
Introduccion al lenguaje de programacion cIntroduccion al lenguaje de programacion c
Introduccion al lenguaje de programacion c
 
Estructura de Lenguaje C++
Estructura de Lenguaje C++Estructura de Lenguaje C++
Estructura de Lenguaje C++
 
Lenguajes diapositivas
Lenguajes diapositivasLenguajes diapositivas
Lenguajes diapositivas
 
ESTRUCTURA BÁSICA PARA C++
ESTRUCTURA BÁSICA PARA C++ESTRUCTURA BÁSICA PARA C++
ESTRUCTURA BÁSICA PARA C++
 
C++
C++C++
C++
 
Webcd
WebcdWebcd
Webcd
 
Transparencias4
Transparencias4Transparencias4
Transparencias4
 
Librerias en-lenguaje-c
Librerias en-lenguaje-cLibrerias en-lenguaje-c
Librerias en-lenguaje-c
 
03 - Entrada y salida en lenguaje C
03 - Entrada y salida en lenguaje C03 - Entrada y salida en lenguaje C
03 - Entrada y salida en lenguaje C
 
Elementos basicos c
Elementos basicos cElementos basicos c
Elementos basicos c
 
Republica bolivariana de venezuela
Republica bolivariana de venezuelaRepublica bolivariana de venezuela
Republica bolivariana de venezuela
 
Manual de c c++
Manual de c c++Manual de c c++
Manual de c c++
 
Tipos de datos_para_c_(2)
Tipos de datos_para_c_(2)Tipos de datos_para_c_(2)
Tipos de datos_para_c_(2)
 
Algoritmos y programacion en C++
Algoritmos y programacion en C++Algoritmos y programacion en C++
Algoritmos y programacion en C++
 

En vedette

Ejemplos Para Dev C++
Ejemplos Para Dev C++Ejemplos Para Dev C++
Ejemplos Para Dev C++
cemayoral
 
Repaso del lenguaje C++
Repaso del lenguaje C++Repaso del lenguaje C++
Repaso del lenguaje C++
g_torrealba
 
Presentación de C++
Presentación de C++Presentación de C++
Presentación de C++
Sylvert
 
Lenguaje de programacion c++ basico 2da parte instalación del compilador
Lenguaje de programacion c++ basico 2da parte instalación del compiladorLenguaje de programacion c++ basico 2da parte instalación del compilador
Lenguaje de programacion c++ basico 2da parte instalación del compilador
Dunkherz
 
(Meta 5.1)función sin parámetros que no retorna valor dev c++
(Meta 5.1)función sin parámetros que no retorna valor dev c++ (Meta 5.1)función sin parámetros que no retorna valor dev c++
(Meta 5.1)función sin parámetros que no retorna valor dev c++
Eli Diaz
 
Arrays bidimensionales
Arrays bidimensionalesArrays bidimensionales
Arrays bidimensionales
asvargas
 

En vedette (20)

Lenguaje c++
Lenguaje c++Lenguaje c++
Lenguaje c++
 
Manual c++
Manual c++Manual c++
Manual c++
 
Ejemplos Para Dev C++
Ejemplos Para Dev C++Ejemplos Para Dev C++
Ejemplos Para Dev C++
 
Clase 5
Clase 5Clase 5
Clase 5
 
C# desde cero sesion 2
C# desde cero   sesion 2C# desde cero   sesion 2
C# desde cero sesion 2
 
Repaso del lenguaje C++
Repaso del lenguaje C++Repaso del lenguaje C++
Repaso del lenguaje C++
 
Programación en c++
Programación en c++Programación en c++
Programación en c++
 
Presentación de C++
Presentación de C++Presentación de C++
Presentación de C++
 
Lenguaje de programacion c++ basico 2da parte instalación del compilador
Lenguaje de programacion c++ basico 2da parte instalación del compiladorLenguaje de programacion c++ basico 2da parte instalación del compilador
Lenguaje de programacion c++ basico 2da parte instalación del compilador
 
Programa c++
Programa c++Programa c++
Programa c++
 
Lenguaje de-programacion-c++
Lenguaje de-programacion-c++Lenguaje de-programacion-c++
Lenguaje de-programacion-c++
 
(Meta 5.1)función sin parámetros que no retorna valor dev c++
(Meta 5.1)función sin parámetros que no retorna valor dev c++ (Meta 5.1)función sin parámetros que no retorna valor dev c++
(Meta 5.1)función sin parámetros que no retorna valor dev c++
 
Funciones en C++
Funciones en C++Funciones en C++
Funciones en C++
 
Exp compi(2)
Exp compi(2)Exp compi(2)
Exp compi(2)
 
Memoria memoria dinamica
 Memoria memoria dinamica Memoria memoria dinamica
Memoria memoria dinamica
 
Administración de memoria continuación -matrices estáticas y dinámicas
Administración de memoria continuación -matrices estáticas y dinámicasAdministración de memoria continuación -matrices estáticas y dinámicas
Administración de memoria continuación -matrices estáticas y dinámicas
 
Trabajo de estructura de datos
Trabajo de estructura de datosTrabajo de estructura de datos
Trabajo de estructura de datos
 
Estructuras de datos_dinamicas_definicion_e_implementacion_
Estructuras de datos_dinamicas_definicion_e_implementacion_Estructuras de datos_dinamicas_definicion_e_implementacion_
Estructuras de datos_dinamicas_definicion_e_implementacion_
 
Lenguaje c++
Lenguaje c++Lenguaje c++
Lenguaje c++
 
Arrays bidimensionales
Arrays bidimensionalesArrays bidimensionales
Arrays bidimensionales
 

Similaire à Curso de C++ (2014)

Introducci _ã_n a c - unidad 02 - elementos del lenguaje
Introducci  _ã_n a c - unidad 02 - elementos del lenguajeIntroducci  _ã_n a c - unidad 02 - elementos del lenguaje
Introducci _ã_n a c - unidad 02 - elementos del lenguaje
Abraham Marcos Garrido
 
Curso lenguaje c_segundo_modulo_
Curso lenguaje c_segundo_modulo_Curso lenguaje c_segundo_modulo_
Curso lenguaje c_segundo_modulo_
Jennybeatriz1
 
Lenguajec 1
Lenguajec 1Lenguajec 1
Lenguajec 1
joeshego
 
Curso C Ii
Curso C IiCurso C Ii
Curso C Ii
yuli
 

Similaire à Curso de C++ (2014) (20)

Lenguaje c
Lenguaje cLenguaje c
Lenguaje c
 
programación Milton.pptx
programación Milton.pptxprogramación Milton.pptx
programación Milton.pptx
 
Introducci _ã_n a c - unidad 02 - elementos del lenguaje
Introducci  _ã_n a c - unidad 02 - elementos del lenguajeIntroducci  _ã_n a c - unidad 02 - elementos del lenguaje
Introducci _ã_n a c - unidad 02 - elementos del lenguaje
 
Curso lenguaje c_segundo_modulo_
Curso lenguaje c_segundo_modulo_Curso lenguaje c_segundo_modulo_
Curso lenguaje c_segundo_modulo_
 
tutorial de c++
tutorial de c++tutorial de c++
tutorial de c++
 
Tutorial C++
Tutorial C++Tutorial C++
Tutorial C++
 
02 - Tipos de datos escalares en Python 3
02 - Tipos de datos escalares en Python 302 - Tipos de datos escalares en Python 3
02 - Tipos de datos escalares en Python 3
 
Actividades 1 7
Actividades 1 7Actividades 1 7
Actividades 1 7
 
Actividades 1 7
Actividades 1 7Actividades 1 7
Actividades 1 7
 
Curso c++
Curso c++Curso c++
Curso c++
 
Lenguajec 1
Lenguajec 1Lenguajec 1
Lenguajec 1
 
02 - Conceptos fundamentales sobre tipos de datos en lenguaje C
02 - Conceptos fundamentales sobre tipos de datos en lenguaje C02 - Conceptos fundamentales sobre tipos de datos en lenguaje C
02 - Conceptos fundamentales sobre tipos de datos en lenguaje C
 
Lenguaje c
Lenguaje cLenguaje c
Lenguaje c
 
Dev c 1 2011
Dev c  1 2011Dev c  1 2011
Dev c 1 2011
 
ELEMENTOS DE PROGRA 30-05.pdf
ELEMENTOS DE PROGRA 30-05.pdfELEMENTOS DE PROGRA 30-05.pdf
ELEMENTOS DE PROGRA 30-05.pdf
 
Elementos basicos de_programacion
Elementos basicos de_programacionElementos basicos de_programacion
Elementos basicos de_programacion
 
Sesion 4
Sesion 4Sesion 4
Sesion 4
 
Curso c ii
Curso c iiCurso c ii
Curso c ii
 
Curso C Ii
Curso C IiCurso C Ii
Curso C Ii
 
2 punteros y lenguaje c
2 punteros y lenguaje c2 punteros y lenguaje c
2 punteros y lenguaje c
 

Plus de Miriam Ruiz

Planets in our Solar System (2015)
Planets in our Solar System (2015)Planets in our Solar System (2015)
Planets in our Solar System (2015)
Miriam Ruiz
 
Understanding Debian Packages (2014)
Understanding Debian Packages (2014)Understanding Debian Packages (2014)
Understanding Debian Packages (2014)
Miriam Ruiz
 
El Paradigma de la Cultura Libre (2014)
El Paradigma de la Cultura Libre (2014)El Paradigma de la Cultura Libre (2014)
El Paradigma de la Cultura Libre (2014)
Miriam Ruiz
 
Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)
Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)
Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)
Miriam Ruiz
 
UML Design Class Diagrams (2014)
UML Design Class Diagrams (2014)UML Design Class Diagrams (2014)
UML Design Class Diagrams (2014)
Miriam Ruiz
 
El Software Libre: Una visión global (2012)
El Software Libre: Una visión global (2012)El Software Libre: Una visión global (2012)
El Software Libre: Una visión global (2012)
Miriam Ruiz
 
El Sistema Operativo Debian GNU/Linux (2012)
El Sistema Operativo Debian GNU/Linux (2012)El Sistema Operativo Debian GNU/Linux (2012)
El Sistema Operativo Debian GNU/Linux (2012)
Miriam Ruiz
 

Plus de Miriam Ruiz (20)

MBTI (Myers-Briggs Type Indicator) (doc. v3)
MBTI (Myers-Briggs Type Indicator) (doc. v3)MBTI (Myers-Briggs Type Indicator) (doc. v3)
MBTI (Myers-Briggs Type Indicator) (doc. v3)
 
Patrones de Escalas Musicales (Draft)
Patrones de Escalas Musicales (Draft)Patrones de Escalas Musicales (Draft)
Patrones de Escalas Musicales (Draft)
 
Diagramas de Escalas Musicales (draft)
Diagramas de Escalas Musicales (draft)Diagramas de Escalas Musicales (draft)
Diagramas de Escalas Musicales (draft)
 
Diagramas tonales de acordes musicales (draft)
Diagramas tonales de acordes musicales (draft)Diagramas tonales de acordes musicales (draft)
Diagramas tonales de acordes musicales (draft)
 
Mapas Tonales Musicales [Draft]
Mapas Tonales Musicales [Draft]Mapas Tonales Musicales [Draft]
Mapas Tonales Musicales [Draft]
 
Ukelele Chords Cheat Sheet v2
Ukelele Chords Cheat Sheet v2Ukelele Chords Cheat Sheet v2
Ukelele Chords Cheat Sheet v2
 
Ukelele Chords Cheat Sheet
Ukelele Chords Cheat SheetUkelele Chords Cheat Sheet
Ukelele Chords Cheat Sheet
 
Mujeres en el Software Libre (Campus Party Colombia, 2020)
Mujeres en el Software Libre (Campus Party Colombia, 2020)Mujeres en el Software Libre (Campus Party Colombia, 2020)
Mujeres en el Software Libre (Campus Party Colombia, 2020)
 
MBTI (Myers-Briggs Type Indicator)
MBTI (Myers-Briggs Type Indicator)MBTI (Myers-Briggs Type Indicator)
MBTI (Myers-Briggs Type Indicator)
 
DiSC (Dominance, Influence, Steadiness, Conscientiousness)
DiSC (Dominance, Influence, Steadiness, Conscientiousness)DiSC (Dominance, Influence, Steadiness, Conscientiousness)
DiSC (Dominance, Influence, Steadiness, Conscientiousness)
 
MBTI (Myers-Briggs Type Indicator) [old]
MBTI (Myers-Briggs Type Indicator) [old]MBTI (Myers-Briggs Type Indicator) [old]
MBTI (Myers-Briggs Type Indicator) [old]
 
Mujeres en el Software Libre: El proyecto Debian Women (2015)
Mujeres en el Software Libre: El proyecto Debian Women (2015)Mujeres en el Software Libre: El proyecto Debian Women (2015)
Mujeres en el Software Libre: El proyecto Debian Women (2015)
 
Planets in our Solar System (2015)
Planets in our Solar System (2015)Planets in our Solar System (2015)
Planets in our Solar System (2015)
 
Understanding Debian Packages (2014)
Understanding Debian Packages (2014)Understanding Debian Packages (2014)
Understanding Debian Packages (2014)
 
El Paradigma de la Cultura Libre (2014)
El Paradigma de la Cultura Libre (2014)El Paradigma de la Cultura Libre (2014)
El Paradigma de la Cultura Libre (2014)
 
Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)
Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)
Mnemonic Acronym and Mnemonic Images for Object Oriented Principles (2014)
 
UML Design Class Diagrams (2014)
UML Design Class Diagrams (2014)UML Design Class Diagrams (2014)
UML Design Class Diagrams (2014)
 
Feminismo en la Red (2013)
Feminismo en la Red (2013)Feminismo en la Red (2013)
Feminismo en la Red (2013)
 
El Software Libre: Una visión global (2012)
El Software Libre: Una visión global (2012)El Software Libre: Una visión global (2012)
El Software Libre: Una visión global (2012)
 
El Sistema Operativo Debian GNU/Linux (2012)
El Sistema Operativo Debian GNU/Linux (2012)El Sistema Operativo Debian GNU/Linux (2012)
El Sistema Operativo Debian GNU/Linux (2012)
 

Dernier

redes informaticas en una oficina administrativa
redes informaticas en una oficina administrativaredes informaticas en una oficina administrativa
redes informaticas en una oficina administrativa
nicho110
 

Dernier (10)

investigación de los Avances tecnológicos del siglo XXI
investigación de los Avances tecnológicos del siglo XXIinvestigación de los Avances tecnológicos del siglo XXI
investigación de los Avances tecnológicos del siglo XXI
 
Buenos_Aires_Meetup_Redis_20240430_.pptx
Buenos_Aires_Meetup_Redis_20240430_.pptxBuenos_Aires_Meetup_Redis_20240430_.pptx
Buenos_Aires_Meetup_Redis_20240430_.pptx
 
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptxEVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
EVOLUCION DE LA TECNOLOGIA Y SUS ASPECTOSpptx
 
Innovaciones tecnologicas en el siglo 21
Innovaciones tecnologicas en el siglo 21Innovaciones tecnologicas en el siglo 21
Innovaciones tecnologicas en el siglo 21
 
redes informaticas en una oficina administrativa
redes informaticas en una oficina administrativaredes informaticas en una oficina administrativa
redes informaticas en una oficina administrativa
 
How to use Redis with MuleSoft. A quick start presentation.
How to use Redis with MuleSoft. A quick start presentation.How to use Redis with MuleSoft. A quick start presentation.
How to use Redis with MuleSoft. A quick start presentation.
 
Avances tecnológicos del siglo XXI 10-07 eyvana
Avances tecnológicos del siglo XXI 10-07 eyvanaAvances tecnológicos del siglo XXI 10-07 eyvana
Avances tecnológicos del siglo XXI 10-07 eyvana
 
Guia Basica para bachillerato de Circuitos Basicos
Guia Basica para bachillerato de Circuitos BasicosGuia Basica para bachillerato de Circuitos Basicos
Guia Basica para bachillerato de Circuitos Basicos
 
Avances tecnológicos del siglo XXI y ejemplos de estos
Avances tecnológicos del siglo XXI y ejemplos de estosAvances tecnológicos del siglo XXI y ejemplos de estos
Avances tecnológicos del siglo XXI y ejemplos de estos
 
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
 

Curso de C++ (2014)

  • 1. Una visión global del lenguaje C++ (pensando en sistemas embebidos) Miriam Ruiz <miriam@debian.org> Octubre, 2014
  • 2. Índice 1.- Introducción al lenguaje C++ 2.- Características y sintaxis 3.- Programación orientada a objetos 4.- Clases y objetos 5.- Herencia 6.- Modificadores de clase 7.- Relaciones entre clases 8.- Programación genérica
  • 4. 4 / 160 ¿Qué es C++? ● Es un lenguaje de programación... – De tipado estático (static typing): Las comprobaciones de tipos se realizan en tiempo de compilación, no de ejecución. – De tipado fuerte (strong typing): Las variables tienen asociadas un tipo de datos, que define lo que se puede hacer. – De forma libre (free form): La posición de los caracteres en la página es irrelevante. – Multiparadigma: Soporta más de un paradigma de programación, y la combinación de los mismos. – Compilado: Es necesario convertirlo al código de la máquina para poder ejecutarlo. – De propósito general: Puede ser usado para realizar tareas que no pertenecen a un dominio concreto. – De nivel intermedio: Incorporando características tanto de bajo nivel (cercano a la máquina) como de alto nivel (cercano al ser humano). – Independiente de la plataforma: “Write once, compile anywhere” (WOCA)
  • 5. 5 / 160 Principios de diseño de C++ ● Lenguaje multipropósito tan eficiente y portable como C. ● Soportar de forma directa y comprensiva diferentes estilos de programación: – Procedimental o funcional – Abstracción de los datos – Orientada a objetos – Programación genérica o metaprogramación ● Permitir que la persona que está programando sea la que tome las decisiones, aunque ello pueda significar que las decisiones sean equivocadas. ● Ser tan compatible con el lenguaje C como sea posible, para permitir una transición suave desde este lenguaje. ● Evitar las características que no sean de propósito general, o que sean específicas de una plataforma. ● No incurrir en un sobrecoste o una penalización por características que no se quieran usar. ● No necesitar un sofisticado entorno de desarrollo.
  • 6. 6 / 160 Características del lenguaje ● Uso de operadores, y sobrecarga de los operadores. ● 4 tipos de gestión de la memoria: – Memoria estática, asignada en tiempo de compilación – Memoria asignada automáticamente, en la pila de ejecución – Memoria de asignación dinámica (new/delete o malloc/free) – Uso de garbage collectors a través de librerías externas ● Tipos básicos: booleanos, caracteres, números enteros, números en coma flotante. Modificadores: unsigned / signed, short / long. ● Programación orientada a objetos basada en clases: – Encapsulación: public, protected, private, friend. – Herencia jerárquica, que puede ser simple y múltiple. Herencia virtual. – Polimorfismo: Un único interfaz para diferentes implementaciones. ● Estático: Sobrecarga de operadores. Templates. ● Dinámico: Herencia. Funciones virtuales. – Gestión de recursos: Constructores y destructores. ● Plantillas o templates: Permiten que una clase o función trabaje con tipos de datos abstractos, especificándose más adelante cuales son los que se quieren usar
  • 7. 7 / 160 La evolución de C++ ● 1980: C with class – Clases. Herencia ● 1983-1986: CFront 1.1 – Funciones virtuales – Sobrecarga de operadores – Referencias ● 1989: CFront 2.0 – Herencia múltiple – Clases abstractas ● 1991: CFront 3.0 – Plantillas o templates ● 1992: HP C++ – Excepciones ● 1996: C++ 98/03 – STL – Espacios de nombres ● 2011: C++11 – Expresiones lambda – Tipos automáticos – Hilos de ejecución (threading)
  • 8. 8 / 160 Etapas en la compilación de un programa ● Código fuente (source code) – Archivos .h, .c, .cpp, .hpp, .cc ● Preprocesado (preprocessing) – Archivos con las cabeceras incluidas y las macros expandidas: .i, .ii ● Compilación (compilation) – Archivos en código ensamblador: .s ● Ensamblado (assembling) – Archivos en código máquina: .o ● Archivado (library) – Bibliotecas estáticas (.a) o dinámicas (.so, .dll) ● Enlazado (linking) – Archivos ejecutables (.exe, .elf)
  • 10. 10 / 160 El modelo de memoria de C++ ● La memoria consiste en una serie de objetos referenciados por punteros: ● Hay una serie de tipos básicos predefinidos, y unos mecanismos para construir estructuras más complejas a partir de ellos ● El almacenamiento de las estructuras se hace de tal forma que la composición y la herencia son fáciles de implementar
  • 11. 11 / 160 Tipos básicos de datos en C++ ● Simples – Booleanos ● bool – Enteros (o decimales en coma fija) ● char, short, int, long – Enumeraciones ● enum – Decimales en coma flotante ● float, double, long double ● Estructurados – Estructuras de datos: arrays, strings (zero-terminated), union – Definición de objetos: class, struct ● Direcciones – Punteros (*) – Referencias (&)
  • 12. Conversiones automáticas entre tipos básicos ● Booleanos: Si el tipo original es bool, false se convierte a cero y true se convierte a uno. ● Enumeraciones: Conversión implícita de tipos enum a tipos int, heredada de los tiempos de C. Suponen un problema. ● Typedef: Solo establece un nombre diferente para un tipo ya existente. Por tanto, los tipos se pueden convertir implícitamente. ● Conversiones de ampliación: El valor de una variable menor se asigna a una variable mayor sin pérdida de datos. ● Conversiones de restricción o coerción: El compilador realiza las conversiones de restricción implícitamente, pero advierte sobre la posible pérdida de datos. ● Conversiones con y sin signo: Un tipo entero con signo y su homólogo sin signo son siempre del mismo tamaño, aunque difieren en cuanto a la forma de interpretar el patrón de bits. ● Punteros: Una matriz del estilo de C se convierte implícitamente a un puntero al primer elemento de la matriz. Esto puede ocasionar efectos curiosos. Ej: char * s = "Help" + 3; 12 / 160
  • 13. Conversiones automáticas en expresiones C++ ● Cualquier tipo entero pequeño como char o short es convertido a int o unsigned int. ● Si un operando es de tipo long double, el otro se convertirá a long double. ● Si un operando es de tipo double, el otro se convertirá a double. ● Si un operando es de tipo float, el otro se convertirá a float. ● Si un operando es de tipo unsigned long long, el otro se convertirá a unsigned long long. ● Si un operando es de tipo long long, el otro se convertirá a long long. ● Si un operando es de tipo unsigned long, el otro se convertirá a unsigned long. ● Si un operando es de tipo long, el otro se convertirá a long. ● Si un operando es de tipo unsigned int, el otro se convertirá a unsigned int. ● Si no se da ninguno de los casos anteriores, ambos operandos son int. 13 / 160
  • 14. Modificadores y calificadores de tipos de datos 14 / 160 ● Modificadores de los tipos de datos: – signed, unsigned, long, short ● Calificadores de los tipos de datos: – const: Los objetos de este tipo no pueden ser modificados ● const int, const char * – volatile: Indica al compilador que los datos referenciados. pueden ser alterados de formas no explícitamente especificadas por el programa. ● volatile REGISTER * io_ = 0x1234; – restrict: Indica al compilador que ese puntero es el único mecanismo de acceso a los datos a los que apunta. ● size_t *restrict ptrA
  • 15. 15 / 160 Punteros #include <cstdlib> #include <cstdio> int main() { char ch = 'c'; char *chptr = &ch; int i = 20; int *intptr = &i; float f = 1.20000; float * fptr = &f; const char * ptr = "I am a string"; printf("n [%c], [%d], [%f], [%c], [%s]n", *chptr, *intptr, *fptr, *ptr, ptr); return EXIT_SUCCESS; }
  • 16. 16 / 160 Punteros #include <cstdlib> #include <cstdio> int main() { char ch = 'c'; char *chptr = &ch; int i = 20; int *intptr = &i; float f = 1.20000; float * fptr = &f; const char * ptr = "I am a string"; printf("n [%c], [%d], [%f], [%c], [%s]n", *chptr, *intptr, *fptr, *ptr, ptr); return EXIT_SUCCESS; } [c], [20], [1.200000], [I], [I am a string]
  • 17. 17 / 160 Referencias a variables #include <cstdlib> #include <cstdio> void swap(int & i, int & j) { int tmp = i; i = j; j = tmp; } int main() { int x = 0; int y = 1; swap(x,y); printf("x=%d, y=%dn", x, y); int & a = x; int b = x; a = 5; b = 7; printf("x=%d, y=%d, a=%d, b=%dn", x, y, a, b); return EXIT_SUCCESS; }
  • 18. 18 / 160 Referencias a variables #include <cstdlib> #include <cstdio> void swap(int & i, int & j) { int tmp = i; i = j; j = tmp; } int main() { int x = 0; int y = 1; swap(x,y); printf("x=%d, y=%dn", x, y); int & a = x; int b = x; a = 5; b = 7; printf("x=%d, y=%d, a=%d, b=%dn", x, y, a, b); return EXIT_SUCCESS; } x=1, y=0 x=5, y=0, a=5, b=7
  • 19. 19 / 160 Punteros vs. Referencias ● Puntero: – Identifican un contenido ubicado en un lugar de la memoria. – Se define añadiendo el carácter '*' a un tipo de dato. ● char * pChar; int * pInt; Shape * pShape; – Se usa por convenio el valor NULL (igual a 0L) para no señalar ninguna dirección significativa. ● Referencia: – No es una variable – Es un alias (o nombre alternativo) de un objeto o dato que ya existe. – Se define añadiendo el carácter '&' a un tipo de dato. ● char & rChar; int & rInt; Shape & rShape; – No siempre necesitan ocupar memoria. – No pueden ser NULL. – No pueden ser modificadas. – A menudo son implementados con punteros por parte de los compiladores, pero no son lo mismo.
  • 20. 20 / 160 Sobrecarga de funciones ● Permite asignar el mismo nombre a funciones distintas, siempre que tengan diferentes parámetros. ● Para el compilador estas funciones no tienen nada en común a excepción del identificador. ● Debe haber diferencia en los parámetros. ● Si se diferencian únicamente en el valor de retorno, no es suficiente. ● Los últimos parámetros de una función pueden tener asignado un valor por omisión, que se usará cuando no se le pase uno explícito. ● Orden de preferencia (reglas de congruencia estándar de argumentos): – Concordancia exacta en número y tipo, incluyendo conversiones triviales como de nombre de matriz a puntero, de nombre de función a puntero a función, o de tipo de datos a tipo de datos constante. – Concordancia después de realizar promociones de los tipos asimilables a enteros, o de los tipos float a double. – Concordancia después de realizar conversiones estándares, como de int a double, de double a long double, de un puntero de una clase derivada a una superclase, o de un puntero a un puntero a void. – Concordancia después de realizar conversiones definidas por el usuario/a. – Concordancia usando la elipsis (...) en funciones con número variable de parámetros.
  • 21. 21 / 160 Sobrecarga de funciones #include <iostream> void function(void) { std::cout << "Sin parametros" << std::endl; } void function(int x) { std::cout << "Un numero entero" << std::endl; } void function(int x, int y) { std::cout << "Dos numeros enteros" << std::endl; } void function(int x, double y) { std::cout << "Un numero entero y un numero flotante" << std::endl; } int main(void) { function(); function(1); function(1, 2); function(1, 2.); return 0; }
  • 22. 22 / 160 Sobrecarga de funciones #include <iostream> void function(void) { std::cout << "Sin parametros" << std::endl; } void function(int x) { std::cout << "Un numero entero" << std::endl; } void function(int x, int y) { std::cout << "Dos numeros enteros" << std::endl; } void function(int x, double y) { std::cout << "Un numero entero y un numero flotante" << std::endl; } int main(void) { function(); function(1); function(1, 2); function(1, 2.); return 0; } “Sin parametros” “Un numero entero” “Dos numeros enteros” “Un numero entero y un numero flotante”
  • 23. 23 / 160 Expresiones y operadores ● Variable: es una entidad que permite a un programa almacenar información, y cuyo valor puede cambiar a lo largo de su ejecución. ● Operando: cada una de las constantes, variables o expresiones que intervienen en una expresión. ● Operador: cada uno de los símbolos que indican las operaciones a realizar sobre los operandos, así como los operandos a los que afecta. ● Expresión: es una combinación gramaticalmente válida de operadores y operandos, que dan como resultado un valor. ● Sobrecarga de operadores: es uno de los mecanismos que nos permite ampliar las capacidades de los lenguajes de programación orientados a objetos. En C++, la declaración y definición de una sobrecarga de operador es muy similar a la declaración y definición de una función cualquiera.
  • 24. 24 / 160 Operadores en C++ ● Aritméticos: suma, resta, multiplicación, división y módulo ● Asignación: Operadores de asignación simple ('=') y compuestos ● Manejo de bits: Manejo de bits (bitwise) entre enteros: complemento, desplazamientos, AND, XOR y OR ● Lógicos: Producen resultados booleanos: AND, OR y NOT. Los operandos no son siempre evaluados. ● De Puntero: Operadores de indirección (*) y de referencia (&) ● Relacionales: ==, !=, <, >, <=, >= ● Manejo de memoria: new, delete, new[], delete[] ● Modelado de tipos (cast): Convierte datos de un tipo a otro ● Otros: – '::' - Acceso a ámbito (también llamado de resolución) – '.' - Dereferencia punteros a miembros de clase – '->' - Dereferencia punteros a punteros a miembros de clases – '?' - Operador ternario condicional – ',' - Operador en la expresiones con coma – 'typeid' - Obtiene identificación de tipos y expresiones en tiempo de ejecución – 'sizeof' - Obtiene el tamaño de memoria utilizado por el operando
  • 25. 25 / 160 Operadores en C++ ● Operadores unitarios: solo requieren un operando y operan generalmente de izquierda a derecha (el operador a la izquierda, el operando a la derecha). C++ dispone de los siguientes operadores unitarios: – '!' - Negación lógica – '*' - Indirección – '&' - Referencia – '~' - Complemento de bits – '++' - Incremento (prefijo o postfijo: ++a, a++) – '--' - Decremento (prefijo o postfijo: --a, a--) – '-' - Menos unitario – '+' - Más unitario ● Operadores binarios: Operadores de asignación simple ('=') y compuestos ● Operadores ternarios: El único operador ternario es el operador relacional ? :
  • 26. 26 / 160 Espacios de nombres (namespace) ● Cuando un programa alcanza un gran tamaño, la probabilidad de colisiones en los nombres o identificadores aumenta. ● El problema puede llegar a ser aún mayor cuando se usan librerías externas. ● Un espacio de nombres es una zona donde se pueden declarar y definir identificadores de cualquier tipo (clases, estructuras, funciones, etc), a la que se asigna un nombre o identificador propio. ● Esto permite diferenciar estos elementos de los que puedan tener identificadores iguales en otros espacios. ● El identificador del espacio, usado como prefijo, permite acceder a los nombres o identificadores declarados en su interior a través del operador de especificador de ámbito (“::”). ● También se puede indicar al programa que busque por defecto en los espacios que se quiera (“using namespace”). ● Incluso sin utilizar explícitamente los subespacios, dentro de un mismo ámbito, C++ distingue automáticamente varios espacios de nombres distintos. ● El espacio de nombres sencillo, que contiene las variables, funciones, definiciones de tipo (typedef) y enumeradores (enum). ● El espacio de nombres de miembros de clases ● El espacio de nombres de miembros de estructuras ● El espacio de nombres de miembros de uniones ● El espacio de nombres de etiquetas
  • 27. 27 / 160 Espacios de nombres (namespace) namespace EspacioA { long double LD; float f(float y) { return y; } namespace Sub1 { long double LD; } namespace Sub2 { long double LD; } } namespace EspacioB { long double LD; float f(float z) { return z; } namespace Sub1 { long double LD; } } EspacioA::LD = 1.1; // Aceso a variable LD del espacio A EspacioA::f(1.1); // Aceso a función f de A EspacioB::LD = 1.0; // Aceso a variable LD del espacio B EspacioB::f(1.1); // Aceso a función f de B EspacioB::X = 1 // Error: Elemento X no definido en B EspacioA::Sub1::LD = 3; // Aceso a variable LD del subespacio 1 de A EspacioA::Sub2::LD = 4; // Aceso a variable LD del subespacio 2 de A EspacioB::Sub1::LD = 5; // Aceso a variable LD del subespacio 1 de A ::EspacioA::LD = 1.1; // Acceso comenzando a buscar desde la raiz ::EspacioB::LD = 1.0; // Acceso comenzando a buscar desde la raiz
  • 28. 28 / 160 Espacios de nombres automáticos int x = 1, y = 2, z = 3; // Espacio principal struct E { int x; int y; int z; } e1 = {1, 2, 3}; // Estructuras class C { int x; int y; int z; } c1 = {1, 2, 3}; // Clases union U { int x; char y; float z; } u1 = { x }; // Uniones func(1, 2, 3); ... int func(int x, int y, int z) { if (x == 0) goto x; return (x + y + z); x: // Etiquetas return (1 + y + z); }
  • 29. 29 / 160 Decoración de Nombres (Name Mangling) ● El mecanismo tradicional de asignación de nombres a los elementos de C, ya no es válido para C++ (espacios de nombres, sobrecarga de funciones). ● El compilador cambiará el nombre de la función, añadiendo un identificador del espacio de nombres en el que está declarada, y de los parámetros aceptados por la función. ● Cada compilador de C++ realiza la decoración de los nombres de una forma diferente, incompatible con los demás. La posible estandarización de la decoración de los nombres, de todas formas, sería insuficiente para garantizar la compatibilidad entre diferentes compiladores (es necesario que haya compatibilidad también en la ABI: gestión de excepciones, distribución de la tabla virtual, etc.) ● Cuando se quiere buscar la compatibilidad con otros componentes, se usa la expresión extern “C” { } ● Ejemplos de Name Mangling para diferentes compiladores: http://en.wikipedia.org/wiki/Name_mangling#How_different_compilers_mangle_the_same_functions
  • 30. 30 / 160 Name Mangling: Integrando C y C++ example.h: #ifndef EXAMPLE_H_ #define EXAMPLE_H_ #ifndef __cplusplus extern "C" { #endif extern int Number; int Function(char parameter); #ifndef __cplusplus } #endif #endif /* EXAMPLE_H_ */ example.c: #include "example.h" int Number; int Function(char parameter) { return 4*parameter; } Main.cpp: #include "example.h" int main(void) { Number = Function(7); return 0; } Include Guards Definiciones Símbolos exportados como C (sólo si el programa está en C++) Símbolos exportados como C (el programa está en C) Símbolos usados como C (aunque el programa esté en C++)
  • 31. 31 / 160 Conversiones de tipos (casting) ● Se usan para convertir variables, objetos o expresiones a otros tipos de datos. ● Pueden ser implícitas o explícitas. ● Sigue siendo válida la sintaxis de C, aunque no es recomendable. ● C++ permite 4 formas diferentes de realizar conversiones explícitas: ● const_cast <>: Sirve para eliminar o añadir los modificadores const y volatile de una variable. Intentar modificar una variable que era originalmente constante da un resultado indefinido. ● reinterpret_cast <>: Sirve para interpretar de una forma diferente los datos a los que apunta un puntero, garantizando su reversibilidad. En principio no genera código adicional y mantiene las direcciones de los punteros, pero depende del compilador. ● static_cast <>: Convierte entre diferentes tipos de datos mediante una combinación entre las conversiones provistas por el compilador y las definidas explícitamente en el código. La conversión de punteros desde/hacia void * no modifica el valor del puntero (si la alineación en memoria lo permite). Permite hacer upcast a clases base, o downcast sin ningún tipo de comprobación de validez. . Equivalente a las conversiones de tipos de C. ● dynamic_cast <>: Es parte del sistema RTTI (Run-Time Type Information) de C++. Permite convertir punteros y referencias, realizando comprobaciones de validez en tiempo de ejecución al hacerlas. Permite tanto upcast como downcast. No se suele usar en el desarrollo de sistemas empotrados. Equivalente a las conversiones de tipos de Java.
  • 32. 32 / 160 Notas sobre las conversiones de tipos ● reinterpret_cast no está definido por el estándar C++, por lo que –en teoría– podría tener resultados inesperados. En la práctica, los compiladores suelen interpretar los bits como si fueran del tipo al que se están convirtiendo. Si se sabe qué es lo que va a hacer el compilador que se esté usando, se puede usar, pero su portabilidad no está garantizada. ● El estándar C++ garantiza que la conversión con static_cast desde un puntero a void* mantiene la dirección, siempre que la alineación en la memoria lo permita. Es decir, en el siguiente ejemplo, a, b y c probablemente apuntan –dependiendo de la arquitectura y el tipo de datos– a la misma dirección. A * a = new A(); void * b = static_cast<void*>(a); A * c = static_cast<A*>(b); ● reinterpret_cast sólo garantiza que si se convierte un puntero a un tipo diferente, y se usa de nuevo reinterpret_cast para volver a convertirlo al tipo original, se obtiene el valor original. En el siguiente ejemplo, a y c contienen el mismo valor, pero b no está especificado. En la práctica será normalmente también el mismo, pero no se especifica en la norma, y puede no ser cierto en máquinas con sistemas de memoria más complejos. A * a = new A(); void * b = reinterpret_cast<void*>(a); A * c = reinterpret_cast<A*>(b);
  • 33. 33 / 160 Conversiones de tipos (casting) int i1 = 5, i2 = 5u, i3 = 5.; int i4 = int(5u), i5 = int(5.); int i6 = (int)5u, i7 = (int)5.; float f1 = i1, f2 = float(i1), f3 = (float)i1; const int j1 = 5; int j2 = j1; enum E { X, Y, Z, T }; E e = X; int ei1 = e; int ei2 = static_cast<int>(e); int i = 1; // E ie1 = i; // Error! E ie2 = static_cast<E>(i); // Aviso! No se comprueba en tiempo de ejecucion! struct S_a { int a; S_a(int v) : a(v) { } }; const S_a s1(5); //S_a * ps1 = &s1; // Error! Intento quitar el const implicitamente! S_a * ps1 = const_cast<S_a*>(&s1); struct S_b { bool x; }; S_a s2(6); //S_b * ps2 = static_cast<S_b*>(&s2); // Error! S_b y S_a no están relacionadas! S_b * ps2 = reinterpret_cast<S_b*>(&s2); // es probable que ps2 sea igual a &s2 S_a * ps3 = reinterpret_cast<S_a*>(ps2); // ps3 ha de ser igual a &s2
  • 35. Complejidad en la programación estructurada 35 / 160
  • 36. 36 / 160 Pensar en objetos ● La programación orientada a objetos es un paradigma diferente de la programación estructurada, y no una simple ampliación del mismo. ● Requiere una forma diferente de pensar. ● Permite trabajar con sistemas más complejos de una forma más sencilla. ● En la programación estructurada, descomponemos el problema en acciones, en verbos. En la programación orientada a objetos, lo descomponemos en objetos, en nombres. ● Al analizar el problema, lo primero que tenemos que ver son las entidades que lo forman. ● Estas entidades poseen un conjunto de propiedades o atributos, y un conjunto de métodos mediante los cuales se puede interaccionar con ellas. ● Las entidades se interrelacionan entre ellas mediante mensajes, respondiendo a ellos mediante la ejecución de ciertas acciones.
  • 37. 37 / 160 Pensar en objetos
  • 38. 38 / 160 Programación orientada a objetos ● Es un paradigma de programación que usa los objetos como elemento base. ● Los objetos están constituidos por propiedades (o variables) y por métodos (o funciones). ● Las propiedades de un objeto almacenan su estado en un instante determinado. ● Los métodos de un objeto permiten interaccionar con él para obtener información, y cambiar su estado. ● La POO está basada en varias técnicas, incluyendo: – Herencia: Permite reutilizar el código mediante la especialización de unos objetos a partir de otros. – Cohesión: Pretende que cada objeto del sistema se refiera a un único proceso o entidad. – Abstracción: Consiste en aislar un componente de su entorno y del resto de elementos, haciendo énfasis en qué hace, en lugar de cómo lo hace. – Polimorfismo: Se refiere a la posibilidad de interactuar con objetos heterogéneos de una forma homogénea, a través del mismo interfaz. – Acoplamiento: Cuanto menor acoplamiento entre unos objetos y otros, más sencillo será de desarrollar y mantener. – Encapsulamiento: Se refiere al ocultamiento del estado interno y a la protección del mismo respecto a modificaciones externas.
  • 39. Un ejemplo de sistema organizado en objetos 39 / 160
  • 40. Un ejemplo de sistema organizado en objetos 40 / 160
  • 41. Un ejemplo de sistema organizado en objetos 41 / 160
  • 43. 43 / 160 Clases vs. Objetos ● Clase: – Es la definición abstracta de un tipo de objeto. – Sólo tiene sentido en tiempo de programación. – Definen el aspecto que tendrán los objetos que se creen durante la ejecución del programa. – Son una especie de molde o plantilla. – Definen qué atributos tendrán los objetos, y las cosas que se pueden hacer con él. ● Objeto o instancia: – Suponen la concreción del concepto de clase en un elemento concreto con características determinadas. – Existen durante la ejecución del programa, e interaccionan entre ellos. Nacen, viven, se comunican y mueren. – El valor concreto de cada atributo es único e independiente para cada objeto.. – Los conceptos de clase y objetos son análogos a los de tipo de datos y variable: definida una clase, podemos crear objetos de esa clase.
  • 44. 44 / 160 Definición de una clase en C++ class Rectangle { public: Rectangle(int h, int w); int getHeight(); int getWidth(); private: int height; int width; }; Rectangle::Rectangle(int h, int w) : height(h), width(w) { } int Rectangle::getHeight() { return height; } int Rectangle::getWidth() { return width; }
  • 45. 45 / 160 Definición de una clase en C++ class Rectangle { public: Ámbito de utilización Rectangle(int h, int w); int getHeight(); int getWidth(); private: int height; int width; }; Rectangle::Rectangle(int h, int w) : height(h), width(w) { } int Rectangle::getHeight() { return height; } int Rectangle::getWidth() { return width; } Definición de métodos Definición de atributos Constructor Implementación de métodos Ámbito de utilización
  • 46. 46 / 160 Constructores ● Son funciones miembro especiales que sirven para inicializar los objetos ● Tienen el mismo nombre que la clase a la que pertenecen. ● No pueden devolver ningún valor. ● No pueden ser heredados. ● Cuando no especifiquemos un constructor para una clase, el compilador crea uno por defecto sin argumentos. ● Pueden definirse diferentes constructores para cada clase, siempre que tengan diferentes parámetros. ● Un constructor copia crea un objeto a partir de otro objeto existente. Si no se especifica ninguno, el compilador también crea uno por defecto. ● Se pueden invocar de forma directa de forma excepcional para inicializar una zona de memoria ya reservada, con un objeto de un tipo dado.
  • 47. 47 / 160 Destructores ● Son funciones miembro especiales que sirven para eliminar un objeto de una determinada clase. ● Tienen el mismo nombre que la clase a la que pertenecen, pero con el símbolo tilde ('~') delante. ● No retornan ningún valor. ● No tienen parámetros. ● No pueden ser heredados. ● Deben ser públicos. ● No pueden ser sobrecargados. ● Si la clase tiene algún método virtual, es conveniente declarar el destructor también como virtual. ● Son llamados automáticamente cuando un objeto deja de existir.
  • 48. 48 / 160 El puntero 'this' ● Cada objeto declarado tiene unas propiedades diferentes. Por tanto, cada objeto mantiene una copia de sus datos, diferente de los datos de otros objetos de la misma clase. ● Sin embargo, todos los objetos de la misma clase comparten la misma copia de sus métodos y funciones, es decir, del código ejecutable. ● El puntero especial this permite acceder a los datos de un objeto concreto, aunque sea desde el código genérico de los métodos definidos en una clase. ● El puntero this está asociado a cada objeto, y apunta a la estructura de datos que está asociada con dicho objeto. ● Aunque la sintaxis de C++ hace que el puntero this no se pase explícitamente como parámetro al llamar a un método del mismo, sí que se está pasando como un primer parámetro oculto al invocar a cualquiera de los métodos de un objeto. ● Al acceder a los métodos y propiedades de un objeto, no es necesario explicitarlo (mediante 'this->'). Opcionalmente se puede poner, pero no es necesario.
  • 49. 49 /4 91 6/ 700 El puntero 'this' class Rectangle { public: Rectangle(int h, int w); int getSize(); private: int height; int width; }; Rectangle::Rectangle(int h, int w) { height = h; width = w; } int Rectangle::getSize() { return height * width; } class Rectangle { public: Rectangle(int h, int w); int getSize(); private: int height; int width; }; Rectangle::Rectangle(int h, int w) { this->height = h; this->width = w; } int Rectangle::getSize() { return this->height * this->width; } Equivalentes
  • 50. 50 / 160 ¿Cómo se almacena una clase en memoria? name layer class Shape { public: Shape(const char* n); inline const char* getName() const { return name; } inline int getLayer() const { return layer; } inline char getColor() const { return color; } protected: const char* name; int layer; char color; }; color padding for alignment
  • 51. 51 /5 11 6/ 700 Definición de una clase en C++ Implementación en C++ class Shape { public: Shape(); ~Shape(); void draw(); double x, y; }; Implementación equivalente en C Typedef struct ShapeT { double x, y; } Shape; void Shape_new(Shape * this); void Shape_delete(Shape * this); void Shape_draw(Shape * this);
  • 52. 52 / 160 Gestión de recursos ● Recursos: Son aquellos elementos que, al ser limitados o tener que ser compartidos por diferentes componentes del sistema, han de ser adquiridos y liberados en determinados momentos: – Memoria – Descriptores de archivos – Hilos, procesos, elementos de bloqueo – Eventos, mensajes, modelos – Etc. ● Resource Acquisition Is Initialization (RAII): Los recursos son adquiridos durante la inicialización de los objetos que los usan o gestionan (cuando no hay posibilidad de que sean usados antes de ser disponibles), y liberados cuando se destruyan los mismos objetos, que se garantiza que sucede incluso cuando hay errores.
  • 54. 54 / 160 Herencia ● Permite crear una clase nueva a partir de una ya existente. ● Esta nueva clase contiene los atributos y métodos de la clase primaria. ● Este mecanismo permite construir una jerarquía de objetos cada vez más especializados. ● La principal ventaja de la herencia es la capacidad para definir atributos y métodos nuevos para la subclase, que luego se aplican a los atributos y métodos heredados. Herencia Simple Herencia Múltiple
  • 55. 55 / 160 Herencia simple class Shape { public: Shape(const char * n) : name(n) { } const char * getName() const { return name; } protected: const char * name; }; class Rectangle : public Shape { public: Rectangle(int h, int w); inline int getHeight() const { return height; } inline int getWidth() const { return width; } private: int height; int width; }; Rectangle::Rectangle(int h, int w) : Shape("Rectangle"), height(h), width(w) { }
  • 56. 56 / 160 ¿Cómo funciona la herencia simple? name layer color padding for alignment radius class Shape { public: Shape(const char * n); inline const char * getName() const { return name; } inline int getLayer() const { return layer; } inline char getColor() const { return color; } virtual draw(int x, int y); protected: const char * name; int layer; char color; }; class Circle : public Shape { public: Circle(int r) : Shape("Circle"), radius(r) { } inline int getRadius() const { return radius; } virtual draw(int x, int y); private: int radius; };
  • 57. 57 /5 71 6/ 700 Implementación de la herencia Implementación en C++ class Shape { public: Shape(); ~Shape(); void draw(); double x, y; }; class Box : public Shape { public: Box(); ~Box(); double area(); double h, w; }; Implementación equivalente en C typedef struct ShapeT { double x, y; } Shape; void Shape_new(Shape * this); void Shape_delete(Shape * this); void Shape_draw(Shape * this);; typedef struct BoxT { struct Shape shape; double h, w; } Box; void Box_new(Box* this); void Box_delete(Box* this); double Box_area(Box * this);
  • 58. 58 / 160 Herencia múltiple class Shape { public: Shape(const char * n) : name(n) { } const char * getName() const { return name; } protected: const char * name; }; class Storage { public: Storage(int type); }; class Rectangle : public Shape, public Storage { public: Rectangle(int h, int w); inline int getHeight() const { return height; } inline int getWidth() const { return width; } private: int height; int width; }; Rectangle::Rectangle(int h, int w) : Shape("Rectangle"), Storage(1), height(h), width(w) { }
  • 59. 59 / 160 name layer color padding for alignment file radius Herencia múltiple class Shape { public: Shape(const char * n); inline const char * getName() const { return name; } inline int getLayer() const { return layer; } inline char getColor() const { return color; } void draw(int x, int y); protected: const char * name; int layer; char color; }; class Storage { public: bool save(int len, const char * buffer); bool load(int maxlen, char * buffer); private: FILE * file; }; class Circle : public Shape, public Storage { public: Circle(int r) : Shape("Circle"), radius(r) { } inline int getRadius() const { return radius; } virtual draw(int x, int y); private: int radius; };
  • 60. 60 / 160 Conversiones de tipos (casting) struct A { A(int i) : x(i) { } int x; }; struct B : public A { B(int i, int j) : A(i), y(j) { } int y; }; struct C { C(int i) : x(i) { } int x; }; A a(1); B b(2, 3); C c(4); A cb = static_cast<A>(b); A & rb = static_cast<A&>(b); A * pb = static_cast<A*>(&b); // A cc = static_cast<A>(c); // Error! // A & rc = static_cast<A&>(c); // Error! // A * pc = static_cast<A*>(&c); // Error! // B ca = static_cast<B>(a); // Error! B & ra = static_cast<B&>(a); // Aviso! No se comprueba en tiempo de ejecucion! B * pa = static_cast<B*>(&a); // Aviso! No se comprueba en tiempo de ejecucion!
  • 61. &circle, &shape, pshape, &cfstorage, &cfshape, pvoidc, &circle.name &circle.layer &circle.color &storage, pstorage, pvoids, &circle.file 61 / 160 Conversión de tipos en herencia múltiple name layer color padding file padding radius Shape Storage Circle padding &circle.radius Memoria Lineal sizeof(Circle) sizeof sizeof(Shape) Circle circle; Storage & storage = static_cast<Storage&>(circle); Storage * pstorage = static_cast<Storage*>(&circle); Shape & shape = static_cast<Shape&>(circle); Shape * pshape = static_cast<Shape*>(&circle); Circle & cfstorage = static_cast<Circle&>(storage); Circle & cfshape = static_cast<Circle&>(shape); void * pvoidc = static_cast<void*>(&circle); void * pvoids = static_cast<void*>(&storage);
  • 62. 62 /6 21 6/ 700 Implementación de la herencia múltiple Implementación en C++ class Shape { public: Shape(); ~Shape(); void draw(); double x, y; }; class Storage { public: bool save(int len, const char * buffer); bool load(int maxlen, char * buffer); private: FILE * file; }; class Box : public Shape, public Storage { public: Box(); ~Box(); double area(); double h, w; }; Implementación equivalente en C typedef struct ShapeT { double x, y; } Shape; void Shape_new(Shape * this); void Shape_delete(Shape * this); void Shape_draw(Shape * this);; typedef struct StorageT { FILE * file; } Storage; int Storage_save(Storage *this, int len, const char * buffer); int Storage_load(Storage *this, int maxlen, char * buffer); typedef struct BoxT { Shape shape; Storage storage; double h, w; } Box; void Box_new(Box* this); void Box_delete(Box* this); double Box_area(Box * this);
  • 63. 63 / 160 La necesidad de funciones virtuales #include <cstdlib> #include <cstdio> class Shape { public: const char * getName() const { return "Shape"; }; }; class Rectangle : public Shape { public: const char * getName() const { return "Rectangle"; } }; class Circle : public Shape { public: const char * getName() const { return "Circle"; } }; class Triangle : public Shape { public: const char * getName() const { return "Triangle"; } }; int main() { Rectangle r1, r2; Circle c1, c2, c3; Triangle t1; Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); return EXIT_SUCCESS; }
  • 64. 64 / 160 La necesidad de funciones virtuales #include <cstdlib> #include <cstdio> class Shape { public: const char * getName() const { return "Shape"; }; }; class Rectangle : public Shape { public: const char * getName() const { return "Rectangle"; } }; class Circle : public Shape { public: const char * getName() const { return "Circle"; } }; class Triangle : public Shape { public: const char * getName() const { return "Triangle"; } }; int main() { Rectangle r1, r2; Circle c1, c2, c3; Triangle t1; Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); return EXIT_SUCCESS; } Shape Shape Shape Shape Shape Shape
  • 65. 65 / 160 Funciones virtuales #include <cstdlib> #include <cstdio> class Shape { public: virtual const char * getName() const = 0; }; class Rectangle : public Shape { public: virtual const char * getName() const { return "Rectangle"; } }; class Circle : public Shape { public: virtual const char * getName() const { return "Circle"; } }; class Triangle : public Shape { public: virtual const char * getName() const { return "Triangle"; } }; int main() { Rectangle r1, r2; Circle c1, c2, c3; Triangle t1; Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); return EXIT_SUCCESS; }
  • 66. 66 / 160 Funciones virtuales Rectangle Circle Triangle Rectangle Circle Circle #include <cstdlib> #include <cstdio> class Shape { public: virtual const char * getName() const = 0; }; class Rectangle : public Shape { public: virtual const char * getName() const { return "Rectangle"; } }; class Circle : public Shape { public: virtual const char * getName() const { return "Circle"; } }; class Triangle : public Shape { public: virtual const char * getName() const { return "Triangle"; } }; int main() { Rectangle r1, r2; Circle c1, c2, c3; Triangle t1; Shape * shapes[] = { &r1, &c1, &t1, &r2, &c2, &c3}; for (int i=0; i<sizeof(shapes)/sizeof(Shape); ++i) printf("%sn", shapes[i]->getName()); return EXIT_SUCCESS; }
  • 67. 67 / 160 ¿Cómo funcionan las funciones virtuales? vptr name layer color alignment class Shape { public: Shape(const char * n); inline const char * getName() const { return name; } inline int getLayer() const { return layer; } inline char getColor() const { return color; } virtual draw(int x, int y); protected: const char * name; int layer; char color; };
  • 68. 68 / 160 ¿Cómo funcionan las funciones virtuales? vptr type_info name layer color alignment draw type_info draw vtable
  • 69. 69 /6 91 6/ 700 Implementación de las funciones virtuales Implementación en C++ class Virt { int a, b; virtual void foo(int); }; void f(Virt *v) { v->foo(x); } Implementación equivalente en C typedef struct VtableT { void *(*foo)(Virt * this, int x); } Vtable; typedef struct VirtT { int a, b; Vtable * vptr; } Virt; void f(Virt *v) { (*(v->vptr.foo))(v, x); }
  • 70. 70 / 160 Herencia múltiple con métodos virtuales vptr name layer color alignment file radius class Shape { public: Shape(const char * n); inline const char * getName() const { return name; } inline int getLayer() const { return layer; } inline char getColor() const { return color; } virtual void draw(int x, int y); protected: const char * name; int layer; char color; }; class Storage { public: bool save(int len, const char * buffer); bool load(int maxlen, char * buffer); private: FILE * file; }; class Circle : public Shape, public Storage { public: Circle(int r) : Shape("Circle"), radius(r) { } inline int getRadius() const { return radius; } virtual draw(int x, int y); private: int radius; };
  • 71. 71 / 160 Funciones virtuales puras. Interfaces class IName { public: virtual const char * getName() const = 0; }; class Shape : public IName { public: Shape(const char * n) : name(n) { } virtual const char * getName() const { return name; } // IName protected: const char * name; }; class Rectangle : public Shape { public: Rectangle(int h, int w); inline int getHeight() const { return height; } inline int getWidth() const { return width; } private: int height; int width; }; Rectangle::Rectangle(int h, int w) : Shape("Rectangle"), height(h), width(w) { }
  • 72. 72 / 160 Funciones virtuales puras. Interfaces class IName { public: virtual const char * getName() const = 0; }; class Shape : public IName { public: Shape(const char * n) : name(n) { } virtual const char * getName() const { return name; } // IName protected: const char * name; }; class Rectangle : public Shape { public: Rectangle(int h, int w); inline int getHeight() const { return height; } inline int getWidth() const { return width; } private: int height; int width; }; Rectangle::Rectangle(int h, int w) : Shape("Rectangle"), height(h), width(w) { } Interfaz Clase base Clase derivada
  • 73. 73 / 160 Herencia virtual Herencia no virtual Herencia virtual
  • 74. 74 / 160 El problema del diamante: Herencia Virtual class Storable { public: Storable(const char*); virtual void read(); virtual void write(); virtual ~Storable(); private: ... } class Transmitter: public Storable { public: void write(); ... } class Receiver: public Storable { public: void read(); ... }; class radio: public Transmitter, public Receiver { public: void read(); ... };
  • 75. 75 / 160 El problema del diamante: Herencia Virtual class Transmitter: public virtual Storable { public: void read(); ... } class Receiver: public virtual Storable { public: void read(); ... } class Radio: public Transmitter, public Receiver { public: void read(); ... }; Radio::Radio () : Storable(10), Transmitter(), Receiver() { }
  • 77. 77 / 160 Modificadores de métodos de clase ● Métodos en línea (inline): El código generado para la función se insertará en el punto donde se invoca a la función, en lugar de invocarlo mediante una llamada. ● Métodos constantes (const): Cuando una función miembro no deba modificar ningún elemento de la clase, es conveniente declararla como constante. Esto impedirá que la función modifique los datos del objeto y permitirá acceder a este método desde objetos declarados como constantes. ● Métodos con un valor de retorno constante: Cuando se devuelvan punteros o referencias a elementos internos que no deban ser modificados, es conveniente devolverlos como valores constantes. ● Miembros estáticos (static): Este tipo de componentes son esencialmente elementos globales, de los que sólo existirá una copia que compartirán todos los objetos de la misma clase. ● Constructores explícitos (explicit): Indica al compilador que no use de forma automática las conversiones implícitas.
  • 78. 78 / 160 El modificador const int main() { int var = 1; const int const_var = 1; int * pnt_to_var = &var; const int * pnt_to_const_var = &var; int * const const_pnt_to_var = &var; var = 2; ccoonnsstt__vvaarr == 22;; //// EERRRROORR *pnt_to_var = 2; **ppnntt__ttoo__ccoonnsstt__vvaarr == 22;; //// EERRRROORR *const_pnt_to_var = 2; pnt_to_var = NULL; pnt_to_const_var = NULL; ccoonnsstt__ppnntt__ttoo__vvaarr == NNUULLLL;; //// EERRRROORR return EXIT_SUCCESS; }
  • 79. 79 / 160 Métodos constantes class A { public: A() : state(0) { } void setState(int new_state) { state = new_state; } int getState() const { return state; } private: int state; }; int main() { A a; a.setState(5); a.getState(); const A b; bb..sseettSSttaattee((55));; //// EErrrroorr b.getState(); return EXIT_SUCCESS; }
  • 80. 80 / 160 Métodos constantes y punteros class A { public: A() : pointer(NULL) { } A(const A & other) : pointer(other.pointer) { } void setPointer(int * new_pointer) { pointer = new_pointer; } void setPointer(int & new_pointer) { pointer = &new_pointer; } int * getPointer() const { return pointer; } private: int * pointer; }; int main() { int val; A a; a.setPointer(&val); a.setPointer(val); a.getPointer(); const A b = a; bb..sseettPPooiinntteerr((&&vvaall));; //// EErrrroorr bb..sseettPPooiinntteerr((vvaall));; //// EErrrroorr b.getPointer(); *b.getPointer() = 5; return EXIT_SUCCESS; }
  • 81. 81 / 160 Métodos constantes y retornos constantes class A { public: A() : pointer(NULL) { } A(const A & other) : pointer(other.pointer) { } void setPointer(int * new_pointer) { pointer = new_pointer; } void setPointer(int & new_pointer) { pointer = &new_pointer; } int * getPointer() const { return pointer; } const int * getConstPointer() const { return pointer; } private: int * pointer; }; int main() { int val; A a; a.setPointer(&val); a.setPointer(val); a.getPointer(); *a.getPointer() = 5; **aa..ggeettCCoonnssttPPooiinntteerr(()) == 55;; //// EErrrroorr const A b = a; bb..sseettPPooiinntteerr((&&vvaall));; //// EErrrroorr bb..sseettPPooiinntteerr((vvaall));; //// EErrrroorr b.getPointer(); *b.getPointer() = 5; **bb..ggeettCCoonnssttPPooiinntteerr(()) == 55;; //// EErrrroorr return EXIT_SUCCESS; }
  • 82. 82 / 160 Métodos constantes class A { public: A() : pointer(NULL) { } A(const A & other) : pointer(other.pointer) { } void setPointer(int * new_pointer) { pointer = new_pointer; } void setPointer(int & new_pointer) { pointer = &new_pointer; } int * getPointer() { return pointer; } const int * getPointer() const { return pointer; } private: int * pointer; }; int main() { int val; A a; a.setPointer(&val); a.setPointer(val); a.getPointer(); *a.getPointer() = 5; const A b = a; bb..sseettPPooiinntteerr((&&vvaall));; //// EErrrroorr bb..sseettPPooiinntteerr((vvaall));; //// EErrrroorr b.getPointer(); **bb..ggeettPPooiinntteerr(()) == 55;; //// EErrrroorr return EXIT_SUCCESS; }
  • 83. 83 / 160 Variables y métodos de clase (static) ● Pertenecen a la clase, y no a los objetos que puedan crearse de ella. ● Sus valores son compartidos por todos los objetos de esa clase. ● No se puede usar el puntero this. No hay ningún objeto que referenciar. ● Van precedidas del modificador static. ● Para referenciar una variable estática, o invocar a un método estático, no es necesario crear un objeto de la clase. class Particle { public: Particle(); Particle(const & Particle p); ~Particle(); static inline int NumParticles() { return num_particles; } static int num_particles; }; int Particle::num_particles = 0; Particle::Particle() { ++num_particles; } Particle::Particle(const & Particle p) { ++num_particles; } Particle::~Particle() { --num_particles; } Particle::NumParticles(); Particle::num_particles();
  • 84. Modificador explicit en conversiones de datos 84 / 160 struct ClaseUno { ClaseUno() { } }; struct ClaseDos { ClaseDos(const ClaseUno &) { } }; void func(ClaseDos) { } int main() { ClaseUno uno; func(uno); // Quiere una clase ClaseDos, pero tiene una ClaseUno } struct ClaseUno { ClaseUno() {} }; struct ClaseDos { explicit ClaseDos(const ClaseUno &) { } }; void func(ClaseDos) { } int main() { ClaseUno uno; // func(uno); //Mal: No se hace una conversion automatica func(ClaseDos(uno)); // Bien: La conversion es realizada explicitamente }
  • 86. 86 / 160 Relaciones entre clases: herencia La clase derivada es semejante a la clase original, pero con algunas propiedades o métodos añadidos o modificados. La clase derivada -o subclase- es una especialización -o extensión- de la clase base -o superclase-. Ejemplo: Una moto, o un coche, son un tipo especial de vehículos.
  • 87. 87 / 160 Relaciones entre clases: herencia class Vehicle { public: int Length; int Width; int Height; int Weight; }; class MotorVehicle : public Vehicle { public: int HorsePower; int MaxSpeed; }; class Car : public MotorVehicle { public: int NumDoors; };
  • 88. 88 / 160 Relaciones entre clases: agregación La clase agregada tiene una relación “débil” con la clase que contiene la agregación. La destrucción de un objeto de la clase contenedora no implica la destrucción de los objetos que están agregados por el mismo. Ejemplo: Yo tengo una relación con mis amigos, pero no les “poseo”.
  • 89. 89 / 160 Relaciones entre clases: agregación class Car { public: int NumDoors; }; class Road { public: static const int MaxNumVehicles = 4; Vehicle * Vehicles[MaxNumVehicles]; };
  • 90. 90 / 160 Relaciones entre clases: composición La composición define una relación “fuerte” entre objetos. El objeto contenedor “posee” los objetos que están contenidos en él, de tal forma que la destrucción del mismo implica la destrucción de todas sus partes. Ejemplo: Una mesa contiene un tablero y varias patas.
  • 91. 91 / 160 Relaciones entre clases: composición class Wheel { int Radius; int Wear; int Pressure; }; class Car { public: static const int NumWheels = 4; Wheel Wheels[NumWheels]; int NumDoors; };
  • 92. 92 / 160 Relaciones entre clases: implementación La implementación de un interfaz equivale a la aceptación de un contrato entre las partes relacionadas, de tal forma que el interfaz define de qué formas puede interaccionar la clase con el resto de objetos. En C++ no existe específicamente la figura del interfaz, y se implementan con clases abstractas en las que todos sus métodos son virtuales. Un interfaz no debe contener atributos. Unos interfaces pueden heredar de otros, y añadir nuevos métodos.
  • 93. 93 / 160 Relaciones entre clases: implementación class IDrivable { virtual void SpeedUp(int value) = 0; virtual void Brake(int value) = 0; virtual void Turn(int value) = 0; }; class Car : public IDrivable { public: virtual void SpeedUp(int value) { ... } virtual void Brake(int value) { ... } virtual void Turn(int value) { ... } int NumDoors; };
  • 94. 94 / 160 Habitualmente se usan todas ellas class Vehicle { public: int Length; int Width; int Height; int Weight; }; class MotorVehicle : public Vehicle { public: int HorsePower; int MaxSpeed; }; class Wheel { int Radius; int Wear; int Pressure; }; class IDrivable { virtual void SpeedUp(int value) = 0; virtual void Brake(int value) = 0; virtual void Turn(int value) = 0; }; class Car : public MotorVehicle, public IDrivable { public: virtual void SpeedUp(int value) { ... } virtual void Brake(int value) { ... } virtual void Turn(int value) { ... } static const int NumWheels = 4; Wheel Wheels[NumWheels]; int NumDoors; }; class Road { public: static const int MaxNumVehicles = 4; Vehicle * Vehicles[MaxNumVehicles]; };
  • 96. 96 / 160 La Programación Genérica ● En su definición más sencilla, es un estilo de programación centrado en los algoritmos, en el que éstos se programan en función de tipos de datos que serán especificados más tarde. Este enfoque permite escribir funciones y estructuras que se diferencian sólo en el conjunto de tipos de datos sobre los que se opera, lo que reduce la duplicación de código. ● En un sentido más específico, describe un paradigma de programación en el que los requisitos fundamentales sobre los tipos se abstraen de ejemplos concretos de algoritmos y estructuras de datos y se formalizan como conceptos, y en el que las funciones se implementan de forma genérica en términos de estos conceptos. ● En C++ se usan templates (o plantillas) para permitir el uso de técnicas de programación genéricas.
  • 97. 97 / 160 Ejemplo de templates en C++ template <typename T> T max(T x, T y) { return x < y ? y : x; } Cuando especializa esa función templatizada, el compilador instancia una versión se esa función, en la que el tipo genérico T es sustituido por el tipo de dato que queramos usar: std::cout << max(3, 7); // el resultado es 7 El compilador genera entonces, de forma automática, una función correspondiente a la sustitución de T por int: int max(int x, int y) { return x < y ? y : x; } La función resultante de la especialización de una función genérica puede ser usada como cualquier otra función dentro del lenguaje. Como se puede ver en el código, los requisitos necesarios para poder usar esta función con un tipo de datos cualquiera son: ● Existencia del operador < para el tipo de dato T ● Existencia de un operador asignación para T
  • 98. 98 / 160 Templates: Cálculo del máximo // Maximo de dos valores enteros inline int const& max (int const& a, int const& b) { return a < b ? b : a; } // Maximo de dos valores de cualquier tipo template <typename T> inline T const& max (T const& a, T const& b) { return a < b ? b : a; } // Maximo de tres valores de cualquier tipo template <typename T> inline T const& max (T const& a, T const& b, T const& c) { return ::max (::max(a,b), c); } int main() { ::max(7, 42, 68); // calls the template for three arguments ::max(7.0, 42.0); // calls max<double> (by argument deduction) ::max('a', 'b'); // calls max<char> (by argument deduction) ::max(7, 42); // calls the nontemplate for two ints ::max<>(7, 42); // calls max<int> (by argument deduction) ::max<double>(7, 42); // calls max<double> (no argument deduction) ::max('a', 42.7); // calls the nontemplate for two ints } Fuente: http://www.josuttis.com/tmplbook/basics/max2.cpp.html
  • 99. 99 / 160 Templates: Singleton template <class T> class Singleton { public: static T* Instance() { if(!m_pInstance) m_pInstance = new T; assert(m_pInstance != NULL); return m_pInstance; } protected: Singleton(); ~Singleton(); private: Singleton(Singleton const&); Singleton& operator=(Singleton const&); static T* m_pInstance; }; template <class T> T* Singleton<T>::m_pInstance = NULL; class Logger { // ... }; int main () { // ... Singleton<Logger>::Instance()->openLogFile("logFile.txt"); // ... Archivo .h Archivo .cpp } Fuente: http://www.yolinux.com/TUTORIALS/C++Singleton.html
  • 100. 100 / 160 Especialización de templates // Template vacio por omision template <bool b> struct StaticAssert {}; // Template especializado en true template <> struct StaticAssert<true> { static void assert() {} }; int f() { // Compila correctamente, existe el miembro assert() StaticAssert<1==1>::assert(); // Error de compilacion, no existe assert() para StaticAssert<false> StaticAssert<1==2>::assert(); }
  • 102. 102 / 160 Los Patrones de Diseño ● Un patrón de diseño es una solución estandarizada a un problema de diseño. ● Para que una solución sea considerada un patrón debe poseer ciertas características: ● Debe haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores. ● Debe ser reutilizable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias. ● Los patrones de diseño pretenden: ● Proporcionar catálogos de elementos reusables en el diseño de sistemas software. ● Evitar la reiteración en la búsqueda de soluciones a problemas ya conocidos y solucionados anteriormente. ● Formalizar un vocabulario común entre diseñadores. ● Estandarizar el modo en que se realiza el diseño. ● Facilitar el aprendizaje de las nuevas generaciones de diseñadores condensando conocimiento ya existente.
  • 103. 103 / 160 Abstract Factory Pattern (estructural) Proporciona una interfaz para crear familias de objetos relacionados o dependientes, sin especificar sus clases concretas. Se utiliza este patrón cuando se necesita: ● Crear una familia de objetos relacionados, diseñada para ser utilizada en conjunto. ● Que un sistema sea independiente de la forma en que sus productos son creados, compuestos o representados. ● Que un sistema sea configurado con una de múltiples familias de productos. ● Proporcionar una biblioteca de clases de productos, y sólo se quiere revelar sus interfaces, no sus implementaciones. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Abstract%20Factory%20Pattern
  • 104. 104 / 160 Abstract Factory Pattern (estructural) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Abstract%20Factory%20Pattern
  • 105. 105 / 160 Adapter Pattern (estructural) Transforma la interfaz de un objeto existente en otra que los clientes puedan utilizar. De este modo, una clase que no puede utilizar la primera, puede hacer uso de ella a través de la segunda. Se utiliza este patrón cuando se necesita: ● Utilizar una clase existente, Usando composición pero su interfaz no coincide con la que se necesita. ● Crear una clase reutilizable que coopera con clases que no tienen interfaces compatibles. ● Utilizar varias subclases existentes, pero como es poco práctico adaptar cada interfaz, se crea un objeto que adapte la interfaz de la clase padre. Usando herencia múltiple Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Adapter%20Pattern
  • 106. 106 / 160 Adapter Pattern (estructural) Usando composición Usando herencia múltiple Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Adapter%20Pattern
  • 107. 107 / 160 Decorator Pattern (estructural) Extiende la funcionalidad de un objeto en forma dinámica, proporcionando una alternativa flexible a la creación de subclases. Se utiliza este patrón cuando se necesita: ● Añadir responsabilidades a objetos individuales dinámica y transparente, es decir, sin afectar a otros objetos. ● Retirar responsabilidades de algunos objetos. ● La extensión por subclases es poco práctica. Por ejemplo, un gran número de extensiones independientes son posibles y produciría una explosión de subclases por cada combinación. También cuando la definición de clase puede estar oculta o no disponible para subclases. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Decorator%20Pattern
  • 108. 108 / 160 Decorator Pattern (estructural) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Decorator%20Pattern
  • 109. 109 / 160 Facade Pattern (estructural) Proporciona una interfaz unificada para un conjunto de interfaces de un sistema, y hace que los subsistemas sean mas facil de usar. Se utiliza este patrón cuando se necesita: ● Minimizar la comunicación y las dependencias entre subsistemas. ● Proporcionar una interfaz sencilla para un subsistema complejo. ● Eliminar dependencias entre clientes y clases de implementación, porque son demasiadas. ● Dividir conjuntos de subsistemas en capas. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Facade%20Pattern
  • 110. 110 / 160 Facade Pattern (estructural) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Facade%20Pattern
  • 111. 111 / 160 Iterator Pattern (de comportamiento) Proporciona una forma de acceder secuencialmente a los elementos de un objeto agregado, sin exponer su representación interna. Se utiliza este patrón cuando se necesita: ● Para acceder al contenido de un objeto agregado sin exponer su representación interna. ● Para apoyar recorridos múltiples sobre objetos agregados. ● Para proporcionar una interfaz uniforme para atravesar diferentes estructuras agregadas (es decir, para apoyar iteración polimórfica). Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Iterator%20Pattern
  • 112. 112 / 160 Iterator Pattern (de comportamiento) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Iterator%20Pattern
  • 113. 113 / 160 Observer Pattern (de comportamiento) Define una dependencia de uno-a-muchos con otros objetos, de forma que cuando un objeto cambia de estado todos sus dependientes son notificados y actualizados automáticamente. Se utiliza este patrón cuando se necesita: ● Cuando una abstracción tiene dos aspectos dependientes. Encapsular éstos en objetos separados permite modificarlos y usarlos de forma independiente. ● Cuando un cambio en un objeto requiere cambiar a los demás, y no se sabe cuáles ni cuántos objetos serán. ● Cuando un objeto debe ser capaz de notificar a otros objetos sin hacer suposiciones acerca de quién son estos objetos. En otras palabras, no se quiere que estos objetos estén estrechamente acoplados. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Observer%20Pattern
  • 114. 114 / 160 Observer Pattern (de comportamiento) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Observer%20Pattern
  • 115. 115 / 160 Singleton Pattern (creacional) Garantiza que una clase tenga únicamente una instancia y proporciona un punto de acceso global a la misma. Se utiliza este patrón cuando se necesita: ● Debe haber exactamente una instancia de una clase, y debe ser accesible a los clientes desde un punto de acceso conocido. ● La instancia única debe ser extensible por medio de subclases, y los clientes deben ser capaces de utilizar esta instancia extendida sin modificar su código. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Singleton%20Pattern
  • 116. 116 / 160 Singleton Pattern (creacional) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Singleton%20Pattern
  • 117. 117 / 160 State Pattern (de comportamiento) Altera el comportamiento de un objeto según el estado interno en que se encuentre. Así, el objeto aparentará cambiar de clase. Se utiliza este patrón cuando se necesita: ● El comportamiento de un objeto depende de su estado, y tiene que cambiar su comportamiento en tiempo de ejecución en función de ese estado. ● Se presentan muchos condicionales en el código. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/State%20Pattern
  • 118. 118 / 160 State Pattern (de comportamiento) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/State%20Pattern
  • 119. 119 / 160 Strategy Pattern (de comportamiento) Define un conjunto de clases que representan comportamientos similares: se trata de hacer lo mismo, pero de diferente manera. Permite que un algoritmo varíe independientemente de los clientes que lo utilizan, y puedan intercambiarlos en tiempo de ejecución. Se utiliza este patrón cuando se necesita: ● Muchas clases relacionadas difieren sólo en su comportamiento. ● Se necesita diferentes variantes de un algoritmo. ● Se presentan muchos condicionales en el código, es posible que sea necesario aplicar este patrón. ● Si un algoritmo utiliza información que no deberían conocer los clientes, la utilización del patrón estrategia evita la exposición de dichas estructuras. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Strategy%20Pattern
  • 120. 120 / 160 Strategy Pattern (de comportamiento) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Strategy%20Pattern
  • 121. 121 / 160 Template Pattern (de comportamiento) Define el esqueleto de un algoritmo, dejando que las subclases redefinan ciertos pasos, pero sin cambiar su estructura. Se utiliza este patrón cuando se necesita: ● Aplicar las partes invariables de un algoritmo una vez y dejar en manos de las subclases la implementación del comportamiento que puede variar. ● Evitar la replicación de código mediante generalización: se factoriza el comportamiento común de varias subclases en una única superclase. ● Controlar las extensiones de las subclases. El Método Plantilla utiliza métodos especiales (métodos de enganche o hooks) en ciertos puntos, siendo los únicos puntos que pueden ser redefinidos y, por tanto, los únicos puntos donde es posible la extensión. Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Template%20Pattern
  • 122. 122 / 160 Template Pattern (de comportamiento) Fuente: http://design-patterns-with-uml.blogspot.com.ar/search/label/Template%20Pattern
  • 124. 124 / 160 Metaprogramación basada en plantillas ● La Metaprogramación basada en plantillas o Template metaprogramming (TMP) es una técnica en la que, mediante el uso de plantillas, el compilador genera un código fuente temporal que es añadido al resto del código del programa antes de que éste sea compilado. ● La salida de estas plantillas incluyen constantes en tiempo de compilación, estructuras de datos y funciones completas. ● El uso de plantillas puede ser interpretado como “ejecución en tiempo de compilación”. ● Históricamente, la TMP fue descubierta accidentalmente durante el proceso de estandarización del lenguaje C++, al darse cuenta de que el sistema de plantillas de C++ es Turing-completo (es decir, que tiene un poder computacional equivalente a la máquina universal de Turing y, por tanto, se puede programar cualquier cosa en él).
  • 125. 125 / 160 TMP: Valores y Funciones #include <cstdlib> #include <iostream> struct NumberTwoHolder { enum { value = 2 }; }; template<int N> struct ValueHolder { enum { value = N }; }; template<int X, int Y> struct Adder { enum { result = X + Y }; }; struct TypeHolder { typedef int value; }; int main() { std::cout << NumberTwoHolder::value << std::endl; // 2 std::cout << ValueHolder<3>::value << std::endl; // 3 std::cout << Adder<3,4>::result << std::endl; // 7 std::cout << sizeof(TypeHolder::value) << std::endl; // 4 return EXIT_SUCCESS; }
  • 126. 126 / 160 TMP: Diferentes líneas de ejecución template<typename X, typename Y> struct SameType { enum { result = 0 }; }; template<typename T> struct SameType<T, T> { enum { result = 1 }; }; if (SameType<SomeThirdPartyType, int>::result) { // ... codigo optimizado, asumiendo que el tipo es un entero } else { // ... codigo defensivo que no hace ninguna suposicion sobre el tipo }
  • 127. 127 / 160 TMP: Recursión template <unsigned n> struct factorial { enum { value = n * factorial<n-1>::value }; }; template <> struct factorial<0> { enum { value = 1 }; }; int main() { // Como los calculos se realizan en tiempo de compilacion, // se puede usar para cosas como el tamaño de los arrays int array[ factorial<7>::value ]; }
  • 128. TMP: Ejemplo: “if” en tiempo de compilación 128 / 160 #include <cstdlib> #include <iostream> template <bool Condition, typename TrueResult, typename FalseResult> class if_; template <typename TrueResult, typename FalseResult> struct if_<true, TrueResult, FalseResult> { typedef TrueResult result; }; template <typename TrueResult, typename FalseResult> struct if_<false, TrueResult, FalseResult> { typedef FalseResult result; }; int main() { typename if_<true, int, void*>::result number(3); typename if_<false, int, void*>::result pointer(&number); typedef typename if_<(sizeof(void *) > sizeof(uint32_t)), uint64_t, uint32_t>::result integral_ptr_t; integral_ptr_t converted_pointer = reinterpret_cast<integral_ptr_t>(pointer); std::cout << sizeof(void *) << std::endl; std::cout << sizeof(uint32_t) << std::endl; std::cout << sizeof(integral_ptr_t) << std::endl; return EXIT_SUCCESS; }
  • 129. 129 / 160 TMP: Ejemplo: Comprobaciones estáticas template<class T, class B> struct Derived_from { static void constraints(T * p) { B * pb = p; pb = pb; } Derived_from() { void(*p)(T*) = constraints; p = p; } }; template<class T1, class T2> struct Can_copy { static void constraints(T1 a, T2 b) { T2 c = a; b = a; c = a; b = a; } Can_copy() { void(*p)(T1,T2) = constraints; } }; template<class T1, class T2 = T1> struct Can_compare { static void constraints(T1 a, T2 b) { a == b; a != b; a < b; } Can_compare() { void(*p)(T1,T2) = constraints; } };
  • 130. 130 / 160 TMP: Ejemplo: Lista de Valores (1) #include <cstdlib> #include <iostream> struct NullNumList {}; template<size_t H, typename T> struct NumList { enum { head = H }; typedef T tail; }; template<typename NL> struct binaryOr; template<size_t NL_H, typename NL_TAIL> struct binaryOr<NumList<NL_H, NL_TAIL> > { enum { value = NL_H | binaryOr<NL_TAIL>::value }; }; template<> struct binaryOr<NullNumList> { enum { value = 0 }; };
  • 131. 131 / 160 TMP: Ejemplo: Lista de Valores (y 2) template<char T> struct MyList; template<> struct MyList<'a'> { Typedef NumList<1, NumList<2, NullNumList> > data; // 1 | 2 = 3 }; template<> struct MyList<'b'> { Typedef NumList<1, NumList<4, NumList<8, NullNumList> > > data; // 1 | 4 | 8 = 13 }; int main() { std::cout << binaryOr<MyList<'a'>::data >::value << std::endl; // 3 std::cout << binaryOr<MyList<'b'>::data >::value << std::endl; // 13 return EXIT_SUCCESS; }
  • 132. C++ como lenguaje multiparadigma
  • 133. 133 / 160 ¿Qué quiere decir multiparadigma? ● C++ no es solamente un lenguaje orientado a objetos, sino que es compatible con muchos estilos diferentes de programación, o paradigmas. La programación orientada a objetos es sólo uno de ellos. ● Ningún paradigma es capaz de resolver todos los problemas de forma sencilla y eficiente, por lo que es muy útil poder elegir el que más conviene para cada tarea. ● Habitualmente se combinan diferentes tipos de paradigmas dentro de los programas.
  • 134. 134 / 160 C++ como ensamblador de alto nivel ● C++ permite programar de una forma muy cercana al propio funcionamiento de la máquina. ● La programación imperativa describe las operaciones en términos del estado de un programa, y de operaciones que cambian dicho estado. Los programas imperativos son un conjunto de instrucciones que le indican al ordenador cómo realizar una tarea. ● El hardware habitual de los ordenadores actuales implementa el concepto de máquina de Turing y, por tanto, está diseñado para ejecutar código escrito en forma imperativa. ● C++ hereda de C un sistema de tipos de datos que se pueden mapear de una forma muy cercana a los tipos nativos de la CPU, y operaciones primitivas que también se pueden mapear de una forma muy directa a instrucciones en código máquina. ● Se pueden incorporar instrucciones directas en ensamblador dentro del programa, lo que permite un control muy exacto del programa resultante, a cambio de perder en claridad y portabilidad. ● Esta forma de programación puede resultar muy críptica y oscura a veces, pero a la hora de hacer desarrollos de bajo nivel, incluidos los componentes que interaccionan con el hardware o aquellos que necesitan un alto nivel de optimización, es imprescindible.
  • 135. 135 / 160 C++ como ensamblador de alto nivel uint8_t mask = 0x3F; mask |= 0x40; uint16_t reg1 = 0x25; uint16_t reg2 = reg1 << 3; if (tp->pending & tp->ewmask) != 0) { do_e(tp); } else { queue->add(tp); }
  • 136. 136 / 160 Programación estructurada en C++ ● Este es el estilo de programación clásico heredado de C. El programa comienza en una función principal, llamada main, que llama a otras funciones, que a su vez llaman a otras. ● El flujo de ejecución del programa está controlado por expresiones estructuradas como for, while, switch o until. ● Las variables son visibles dentro del bloque en el que han sido definidas, y no son accesibles directamente desde fuera de ese bloque. ● Las funciones tienen un único punto de entrada, y una única forma de terminación. ● Este estilo de programación incluye también la estructuración de los datos. Para ello existe un mecanismo, struct, que permite organizar los datos en forma de una única entidad que los englobe, y que puede ser copiada por valor, transferida por valor a otras funciones, etc.
  • 137. 137 / 160 Programación estructurada en C++ void funcC(void) { for (int i = 0; i < MaxI(); ++i) { if (funcB(i)) { doSomething() } } while (funcA()) { whatever(); }; }
  • 138. 138 / 160 Abstracción de datos en C++ ● Consiste agrupar en componentes, de forma unificada, tanto los datos como los métodos que permiten manipularlos. ● Ejemplos clásicos de esta abstracción de tipos de datos son las pilas y las listas. ● En lugar de usar estructuras de datos con funciones separadas para manipular estos datos, las funciones son incorporadas al propio componente que los contiene. En el caso de una pila, estas funciones serían las operaciones push y pop, por ejemplo. ● El sello distintivo de este paradigma es el uso de tipos de datos concretos. Por ello, las funciones virtuales apenas se usan, y los objetos son copiados y asignados libremente. ● En concreto, los operadores de copia y construcción existen para poder dar soporte a este estilo de programación, y Tienen una gran importancia en permitir la creación de nuevos tipos de datos que se comporten casi igual que los tipos nativos, como int o double.
  • 139. 139 / 160 Abstracción de datos en C++ struct Queue { Queue(); void push(int v); int pop(); static const MAX = 29; int data[NAX] }; Queue q; q.push(5); q.push(3); int a = q.pop();
  • 140. 140 / 160 Programación orientada a objetos en C++ ● La programación orientada a objetos en C++ se implementa en base a clases. ● Las propiedades de los objetos se almacenan en estructuras (class o struct). En ellas se almacena de forma estructurada toda la información relativa a un objeto. ● C++ da soporte también a métodos y propiedades de clase (que son, en muchos aspectos, semejantes a las variables y funciones globales). ● Los mensajes entre objetos se implementan en base a métodos o funciones, que se comportan de una forma parecida a las funciones de C, añadiéndoles un primer parámetro oculto que referencia la estructura de datos que contiene las propiedades del objeto, y que pueden llevar información adicional en forma de parámetros. ● Se puede restringir el acceso a las propiedades o a los métodos de una clase mediante los modificadores public, protected y private. ● El paradigma de orientación a objetos hace un uso extensivo de las funciones virtuales y del polimorfismo. ● En C++, los tipos polimórficos son la referencia y el puntero. Hay que tener mucho cuidado con ellos a la hora de copiar o asignar objetos, puesto que la asignación de un objeto derivado a una clase base puede implicar que el objeto sea truncado, copiándose sólo la información perteneciente al tipo base.
  • 141. 141 / 160 Programación orientada a objetos en C++ class IDrivable { virtual void SpeedUp(int value) = 0; virtual void Brake(int value) = 0; virtual void Turn(int value) = 0; }; class Car : public IDrivable { public: virtual void SpeedUp(int value) { ... } virtual void Brake(int value) { ... } virtual void Turn(int value) { ... } int NumDoors; }; IDrivable auto = new Car(); Car.SpeedUp(15);
  • 142. 142 / 160 Programación genérica en C++ ● La programación genérica es la programación con conceptos (concepts) . ● Los algoritmos son abstraidos, para permitirles trabajar sobre cualquier tipo de dato que pueda satisfacer el interfaz usado por el algoritmo. ● En la librería estándar de C++, hay componentes como container, iterator o algorithm que forman una triada para dar soporte a la programación genérica. ● Este paradigma está construido también sobre la abstracción de los datos, pero tomándola en una dirección diferente a la de la programación orientada a objetos. ● El mecanismo de C++ que permite soportar la programación genérica son las plantillas o templates, que es el mecanismo de parametrización de tipos provisto por el lenguaje. ● EL uso de plantillas tiene un precio: las librerías son más difíciles de usar, y los problemas se traducen en mensajes de error confusos. ● Tal y como están definidas en C++98, las plantillas no tienen restricciones, y la comprobación de tipos se realiza al final del proceso de compilación, es decir, después de combinar la plantilla con definición del tipo de datos. ● C++11 incluye los conceptos (concepts) para expresar el comportamiento sintáctico y semántico de los tipos, y para restringir los parámetros de tipo que se pueden usar en una plantilla de C++.
  • 143. 143 / 160 Programación genérica en C++ template <unsigned n> struct factorial { enum { value = n * factorial<n-1>::value }; }; template <> struct factorial<0> { enum { value = 1 }; }; int main() { // Como los calculos se hacen en tiempo de compilacion, // se puede usar para cosas como el tamaño de los arrays int array[ factorial<7>::value ]; }
  • 144. 144 / 160 Programación funcional en C++ ● La esencia de la programación funcional consiste en trabajar con valores, en lugar de hacerlo con identidades. ● La principal diferencia entre un valor y una identidad, es que el valor es constante e inalterable (el número 1 es siempre el mismo), mientras que el valor asociado a una identidad puede cambiar (el contenido de una variable). ● El modificador const provee un método eficiente para el paso de objetos grandes a la hora de trabajar con sus valores, y no con sus identidades. ● Mediante el uso del modificador const, C++ permite tipos de datos inmutables, semejantes a los que se encuentran en la mayor parte de los lenguajes de programación funcionales. ● Sin embargo, trabajar con estos tipos de datos inmutables en C++ es difícil y engorroso. En particular, la necesidad de hacer copias completas de objetos de gran tamaño para cada pequeño cambio, no es eficiente. ● C++11 incorpora una serie de herramientas nuevas para facilitar el estilo de porgramación funcional en C++. La más importante de ellas quizás sean las funciones lambda (también llamadas closures o funciones anónimas). Esta funcionalidad, de todas formas, ya estaba accesible en base al uso de functors, muy poderosos pero menos prácticos de usar. De hecho, entre bastidores, C++ implementa las funciones lambda como functors. ● C++11 también provee estructuras para trabajar con información compartida, de tal forma que se facilite el trabajo eficiente con tipos de datos inmutables.
  • 145. 145 / 160 Programación funcional en C++ #include <iostream> // abstract base class for a ontinuation functor struct continuation { virtual void operator() (unsigned) const = 0; }; // accumulating continuation functor struct accum_cont: public continuation { private: unsigned accumulator_; const continuation &enclosing_; public: accum_cont(unsigned accumulator, const continuation &enclosing) : accumulator_(accumulator), enclosing_(enclosing) { }; virtual void operator() (unsigned n) const { enclosing_(accumulator_ * n); }; }; void fact_cps (unsigned n, const continuation &c) { if (n == 0) c(1); else fact_cps(n - 1, accum_cont(n, c)); } int main () { // continuation which displays argument // when called struct disp_cont: public continuation { virtual void operator() (unsigned n) const { std::cout << n << std::endl; }; } dc; // continuation which multiplies argument by 2 // and displays it when called struct mult_cont: public continuation { virtual void operator() (unsigned n) const { std::cout << n * 2 << std::endl; }; } mc; fact_cps(4, dc); // prints 24 fact_cps(5, mc); // prints 240 return 0; } Factorial Functor Fuente: http://stackoverflow.com/questions/1981400/functional-programming-in-c
  • 147. 147 / 160 Programación eficiente en C++ ● Lo que se haga en tiempo de compilación (o de ensamblado, o enlazado) tiene menor coste que lo que se tenga que hacer en ejecución (run-time). ● Que el coste mínimo de alguna característica de C++ sea bajo, no implica que la implementación real de un compilador concreto sea la más optimizada. ● Las optimizaciones de los compiladores mejoran con el tiempo, y pueden dejar obsoletas algunas recomendaciones (como el uso de register e inline). ● Verifica el coste real de la compilación del código en un compilador determinado. ● Características de C++ que no tienen por qué tener un coste adicional: ● Variables static const inicializadas (en vez de #define del preprocesador) ● Ubicación arbitraria de las declaraciones ● Referencias (en lugar de punteros) ● Espacios de nombres ● Operadores new/delete (en vez del uso de malloc/calloc/free) ● Sobrecarga de funciones ● Características de C++ con un coste adicional bajo: ● Inicialización/Conversión/Terminación de variables ● Posicionamiento inline del código ● Herencia múltiple ● Uso de templates o plantillas ● Características de C++ con un coste adicional alto: ● Run-Time Type Identification (RTTI) ● Uso de excepciones (EH, Exception Handling)
  • 148. Los compiladores y los tipos de datos en C++ ● Los compiladores tienen cierta libertad para elegir el tamaño de los tipos de datos comunes ● sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) ● char por lo menos de tamaño suficiente para el conjunto de caracteres básico ● short al menos de 16 bits ● long al menos de 32 bits ● C++ permite realizar operaciones entre variables de diferente tamaño, o combinando con y sin signo. 148 / 160 unsigned char a = 200; int b = -20; a = a + b; ● Los compiladores generalmente cambian cada tipo a uno de más bits que incluye todos los valores posibles del original. ● La conversión de tipos se hace frecuentemente de forma transparente. ● Las reglas de conversión de tipos son complejas, tienen en cuenta la eficiencia, y dependen del compilador usado. ● C++ hereda de C el uso de enteros y punteros como booleanos, produciéndose una conversión transparente de tipos. ● Los números en coma flotante dependen del compilador y la arquitectura. ● Uso de modificadores que afectan al almacenamiento y acceso a la memoria, y a las optimizaciones a aplicar: const, volatile.
  • 149. 149 / 160 La gestión de la memoria en C++ ● Existen tres tipos principales de memoria en C++: ● Memoria global (variables estáticas, tienen asignado un espacio en la memoria al enlazar, y viven durante toda la ejecución del programa). ● Memoria dinámica o 'heap' (es asignada dinámicamente con las funciones malloc/free o con los operadores new/delete). ● Memoria local (variables automáticas, se almacenan en la pila, o 'stack') ● Normalmente, el stack crece en en sentido, y el heap en otro, pero el heap puede estar fragmentado, ya que no es una pila ● En la mayoría de las plataformas, al llamar a una función, se reserva una porción de memoria en el stack (llamada 'stack frame') para guardar: ● La dirección de retorno. ● Los parámetros que se le pasan a la función. ● Las variables de la función que sólo viven mientras se ejecuta esta. ● Ni C ni C++ ponen ninguna restricción de acceso a la memoria. Ni se comprueba automáticamente que éste se efectúe dentro de los límites de los arrays, ni que los punteros para acceder a la memoria tienen sentido. ● La gestión de la memoria es decidida por el compilador, que ajusta el tamaño de los tipos de datos a lo que más le convenga para adecuarse a sus criterios de optimización, y que también suele dejar huecos vacíos entre las zonas de memoria usadas ('padding'), para optimizar su acceso. A menudo los compiladores tienen opciones para configurar esto ('pack').
  • 150. 150 / 160 Estructura de la memoria en C y C++ Fuente: http://www.bogotobogo.com/cplusplus/assembly.php
  • 151. 151 / 160 El modelo de memoria en C++ ● El modelo de memoria de C++ es la especificación de cuándo y por qué se lee o se escribe en la memoria real en la ejecución de un programa en C++. ● Antes de C++11, el modelo de memoria de C++ era el mismo que el de C: ● Sólo se especifica el comportamiento de las operaciones de memoria observables por el programa actual. ● No se dice nada acerca de los accesos concurrentes a la memoria cuando varios procesos, subprocesos o tareas acceden a la misma (no existe la noción de memoria compartida, de procesos compartidos ni de hilos de ejecución). ● No se ofrece ninguna forma de especificar un oorrddeenn ddee aacccceessoo aa mmeemmoorriiaa (las optimizaciones del compilador incluyen el movimiento de código, y los procesadores modernos pueden reordenar los accesos). ● Por tanto, antes de C++11 sólo se tiene en cuenta la existencia de un solo proceso, con un único hilo de ejecución, y no se debe depender de un orden específico de acceso a variables en la memoria. ● Puntos importantes a la hora de tener en cuenta la memoria: ● Atomicidad: ¿Qué instrucciones tienen efectos indivisibles? ● Visibilidad: ¿Cuándo son visibles los efectos de un hilo para otro? ● Orden: ¿Bajo qué condiciones los efectos de las operaciones pueden aparecer fuera de orden para otro hilo?
  • 152. Papel de los registros al trabajar con la memoria 152 / 160 Fuente: http://www.bogotobogo.com/cplusplus/assembly.php
  • 153. Papel de los registros al trabajar con la memoria 153 / 160 i = 17; j = 20; j += i; ● Leer i de la memoria y guardarlo en un registro ● Leer j de la memoria y guardarlo en otro registro ● Sumar los dos valores de los registros usados ● Almacenar el resultado en la memoria asignada a j Fuente: http://www.bogotobogo.com/cplusplus/assembly.php
  • 154. 154 / 160 Estándares de programación en C++ ● Motor Industry Software Reliability Association (MISRA C++): Forman un subconjunto seguro del lenguaje C++ para el desarrollo de los sistemas críticos de seguridad en aplicaciones embebidas. Funciona en base a una serie de restricciones sobre el uso del lenguaje. La norma se basa en estándares de codificación establecidos como MISRA C, Joint Strike Fighter Air Vehicle C++ coding standard (JSF++) de Lockheed Martin y High-Integrity C++ coding standard (HICPP) de PRQA. ● Joint Strike Fighter Air Vehicle C++ (JSF++ AV++): Desarrollado por Lockheed Martin para ayudar a desarrollar código que se ajuste a los principios de seguridad de software crítico. En esencia, se propone que los programas están escritos en un subconjunto "más seguro" de C++. ● High Integrity C++ (HICPP): Presentado por primera vez en 2003 por Programming Research, la norma adopta el criterio de que se deben aplicar restricciones sobre el lenguaje ISO C++ con el fin de limitar la flexibilidad que éste permite. Este enfoque tiene el efecto de minimizar los problemas creados por la diversidad de compiladores, los diferentes estilos de programación y los aspectos peligrosos y confusos del lenguaje. ● En términos generales, la eficacia de un estándar depende mucho de lo que se pueda automatizar la detección de sus infracciones. La inspección de código manual ha demostrado ser ineficaz, costosa, lenta y propensa a errores humanos.
  • 155. 155 / 160 Tipos habituales de normas Tipo: Claridad del código Descripción: Se trata de escribir código claro, legible y poco confuso, evitando construcciones que, siendo perfectamente válidas, puedan hacer el código difícil de leer. Ejemplo: Relativas a la instrucción goto (6-6-1, 6-6-2), terminación de bucles for (6-5-6) Consejo: Sea flexible, ya que la claridad es una cuestión muy subjetiva. Fomente la coherencia entre las y los diferentes desarrolladores. Tipo: Simplicidad del código Descripción: Mantener el código lo más simple posible, para minimizar los errores y hacer más sencillo el análisis. Permite ayudar además a reducir el coste de los tests. Ejemplo: uso de continue (6-6-3), eliminación de código no usado (0-1-1, 0-1-2) Consejo: Sea flexible, pero ten en cuenta que el incumplimiento de estas normas puede afectar a los costes de las pruebas. Tipo: Previsibilidad en la ejecución del código Descripción: Hacer previsible la ejecución del software en todas las circunstancias, eliminando las fuentes de ambigüedad . Esto además ayuda a la portabilidad. Ejemplo: No recursividad (7-5-4), no memoria dinámica (18-4-1), no tipos dinámicos en el constructor (12-1-1), división de enteros (1-0-3), una única definición (3-2-2, 3-2-3, 3-2-4) Consejo: Evite el incumplimiento de las normas relativas a la previsibilidad del código.
  • 156. Tipo: Programación Defensiva Descripción: Cuanto más protegido esté el software ante situaciones inesperadas, por improbables que sean, mejor. Esto mejora además la mantenibilidad del software. Ejemplo: sentencias switch (6-4-3), no modificación de contadores en los bucles for (6-5- 3), no dar acceso a variables internas (9-3-2), tener en cuenta los errores (0-3-2) Consejo: Sea moderadamente flexible, pero justifique bien las excepciones. 156 / 160 Tipos de normas Tipo: Conformidad a normas Descripción: Siempre que sea posible, hay que intentar adecuarse a normas reconocidas. Cumplir estas normas , además, ayuda a mejorar la portabilidad. Ejemplo: Uso de formatos estándar de coma flotante: ANSI/IEEE (0-4-3), compiladores con interfaz común (1-0-2), set de caracteres (2-2-1), secuencias de escape (2-13-1) Consejo: Sea flexible, pero tenga en cuenta los posibles costes de transición en el futuro. Tipo: Proceso de desarrollo del software Descripción: Se refieren, no tanto al propio código, sino al propio proceso mediante el cual se desarrolla éste. Ejemplo: Uso de mecanismos de análisis estático y dinámico (0-3-1) Consejo: Evite incumplir estas normas, ya que seguirlas proporciona el mayor retorno de la inversión
  • 157. 157 / 160 Las normas MISRA ● MISRA significa "Motor Industry Software Reliability Association". ● MISRA-C:1998 tenía 127 normas, de las cuales 93 eran requisitos y 34 eran recomendaciones; las reglas estaban numeradas secuencialemente desde el 1 al 127. ● MISRA-C:2004 contiene 142 normas, de las cuales 122 son requisitos y 20 recomendaciones. Se dividen en 21 categorías temáticas, desde "Entorno" hasta "Fallos en tiempo de ejecución" . ● MISRA-C:2012 contiene 143 normas (el cumplimiento de las cuales es analizable mediante el análisis estático del programa) y 16 directivas (cuyo cumplimiento está más abierto a la interpretación , o se refiere a cuestiones de proceso o de procedimiento), clasificadas por una parte como "obligatorias", "necesarias" o "recomendables". ● MISRA-C++:2008, como era de esperar, incluye un solapamiento importante con MISRA C. Sin embargo, el estándar MISRA C++ incluye 228 normas, aproximadamente un 50% más que el estándar MISRA C, ya que comprende además normas relativas a las funciones virtuales , manejo de excepciones , espacios de nombres, parámetros de referencia, acceso a los datos de la clase encapsuladas, y otras facetas específicas del lenguaje C++.
  • 159. 159 / 160 Algunos enlaces ● http://c.conclase.net/curso/ ● http://es.cppreference.com/w/cpp ● http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html ● http://arco.esi.uclm.es/~david.villa/pensar_en_C++/ ● https://bitbucket.org/crysol_org/pensarenc/overview ● http://www.learncpp.com/cpp-tutorial/ ● http://www.cplusplus.com/doc/tutorial/ ● http://www.zator.com/Cpp/ ● http://www.doc.ic.ac.uk/~wjk/C++Intro/CourseStructure.html ● http://www.youtube.com/playlist?list=PL4A486BBFC5AD733B ● http://mazyod.com/category/software-engineering/ ● http://www.cdsonline1.co.uk/EmailImages/mae/MAE09_speaker_presentations/MAE2009.ppt ● http://assembly.ynh.io/ ( https://github.com/ynh/cpp-to-assembly ) ● http://msdn.microsoft.com/en-us/magazine/jj553512.aspx ● http://www.open-std.org/jtc1/sc22/wg21/docs/ESC_San_Jose_98_401_paper.pdf ● http://design-patterns-with-uml.blogspot.com.ar ● http://en.wikipedia.org/wiki/Software_design_patterns ● http://www.eventhelix.com/realtimemantra/patterns/
  • 160. Licencia de este documento Copyright © 2014, Miriam Ruiz This work is licensed under the Creative Commons Attribution-Share Alike 3.0 (CC-by-sa 3.0) license. You can use, copy, modify, merge, remix, distribute, display, perform, sublicense and/or sale it freely under the conditions defined in that license. See http://creativecommons.org/licenses/by-sa/3.0/