Programación Orientada a Objetos en C

Sección de Acceso Rápido de Subtemas de Este Capítulo:

Funciones y Clases Amigas| Sobrecarga de Funciones| Sobrecarga de Operadores| Operadores que se pueden Sobrecargar| Sobrecarga de Operadores Binarios| Sobrecarga de Operadores Unitarios| Sobrecarga de Operadores de Asignación| Templates (Plantilas)| Templates en Funciones| Templates en Clases| Clases de Derivación| Derivación Privada| Derivación Protegida| Herencia Multiple| Ambigüedades a Herencia Multiple|

Funciones y clases Amigas

Una función amiga es una función no miembro de una clase que puede tener acceso a los miembros privados de dicha clase. Estas funciones se declaran situando su prototipo de función dentro de la clase y mediante la palabra reservada friend. Asi, en la propia clase se determina qué funciones son amigas de ella.

class Cosa {

friend void cargar_dato( Cosa &, int); // función amiga

private:

int dato;

public:

Cosa (int d) { dato=d ; }

void prinf() { cout << "Dato = " << dato; }

}

void cargar_dato (Cosa & t, int d) { t.dato=x; }

void carga_otro_dato(Cosa &, int );

void main(void)

{

Cosa objeto1(0);

Cosa *ap_objeto;

ap_objeto = new cosa (1);

cargar_dato(objeto1, 2);

objeto1.print();

ap_objeto->print();

cargar_otro_dato(objeto1, 3);

}

void caga_otro_dato(Cosa & c, int y)

{

c.dato = y; // ERROR. NO ES FUNCION AMIGA

}

Además de las funciones amigas, se pueden tener clases completas como amigas de otra clase. En este caso, todas las funciones de la clase declarada como amiga pueden accesar las partes privadas de la otra clase. También se utiliza la palabra friend para declarar una clase como amiga de otra. Obviamente, la clase amiga debe estar declarada.

class nodo_bin {

friend arbol_bin ;

int inf;

nodo_bin *hizq, *hder, *padre;

public:

nodo_bin(T dato) { inf=dato; hizq=hder=padre=NULL; bal=0; }

nodo_bin *Leer_hizq() { return hizq; }

nodo_bin *Leer_hder() { return hder; }

}

class arbol_bin {

nodo_bin *raiz;

public:

arbol_bin() { raiz=NULL; };

nodo_bin Raiz() {return raiz; }

T info(nodo_bin *nodo) { return nodo->Leer_inf(); }

// nodo_bin * Left(nodo_bin *nodo) { return nodo->Leer_hizq(); }

nodo_bin * Left(nodo_bin *nodo) { return nodo->hizq; }

//nodo_bin * Right(nodo_bin *nodo) { return nodo->Leer_hder(); }

nodo_bin * Right(nodo_bin *nodo) { return nodo->hder; }

};



Top de la Pagina

Sobrecarga de Funciones

El término sobrecarga se refiere al uso de un mismo nombre para múltiples significados de un operador o función. En C++ es posible dar el mismo nombre a varias funciones, la decisión de ejecutar una u otra la realiza el compilador de acuerdo al tipo y/o número de argumentos. Los prototipos de estas funciones especifican sus tipos de retorno y argumentos para cada función en particular.

#include

int cuadrado (int i) { return i*i; }

float cuadrado (float d) { return d*d; }

long cuadrado (long l) { return l*l; }

void main(void)

{ int x;

long y;

float z;

x = cuadrado(5);

y = cuadrado(50000);

z = cuadrado(3.1416);

}

Las funciones sobrecargadas pueden ser miembros de alguna clase o no. Si una función sobrecargada no es miembro de alguna clase, su ámbito es todo el programa.

#include

void Visualizar(char *string) { cout << string ; }

void Visualizar(long valor) { cout << valor ; }

void Visualizar(double valor) { cout << valot ; }

void main(void)

{ Visualizar("\n Este es un \"string\" ");

Visualizar(1234567890);

Visualizar(3.141592);

}

Funciones miembro sobrecargadas

El principal uso de la sobrecarga es con las funciones miembro de una clase. Cuando más de una función miembro con igual nombre se declara en una clase, se dice que el nombre de la función está sobrecargado en esa clase. El ámbito del nombre sobrecargado es el de la clase. Es importante recordar que, los constructores, como funciones miembros de una clase, son susceptibles de sobrecargarse.

class figura {

char *tipo;

float Area;

int color;

public:

char * LeeAtributo() { return tipo; }

float LeeAtributo() { return Area; }

int LeeAtributo () { return color; }

void PonAtributo(int c) { color = c ; }

void PonAtributo(float A, int c) { Area= A; color=c ; }

}

Funciones amigas sobrecargadas

La sobrecarga de funciones amigas es similar a la de funciones miembro con la diferencia de que es necesaria la palabra reservada friend al igual que en la declaración de cualquier función amiga.

class figura {

char *tipo;

float Area;

int color;

public:

char * LeeAtributo() { return tipo; }

float LeeAtributo() { return Area; }

int LeeAtributo () { return color; }

friend PonAtributo(int);

friend PonAtributo(float, int );

};

void PonAtributo(int c) { color = c ; }

void PonAtributo(float A, int c) { Area= A; color=c ; }

Las funciones sobrecargadas necesitan diferir por lo menos en uno de los siguientes puntos:

- Deben recibir un número diferente de argumentos.

- Al menos uno de los argumentos debe ser diferente en cuanto a su tipo.

La única función miembro que no se puede sobrecargar es el destructor, debido a las reglas con que éstos se forman.

La sobrecarga de funciones evita la difícil tarea de dar nombres diferentes a operaciones similares. Las operaciones similares pueden tener un mismo nombre sin que haya conflictos, siempre y cuando se defina apropiadamente la sobrecarga de las funciones correspondientes.



Top de la Pagina

Sobrecarga de Operadores

La sobrecarga de operadores, de modo similar que la sobrecarga de funciones, permite al programador dar nuevos significados a los símbolos de los operadores ya existentes en C++ para tipos de datos abstractos (tipos de datos definidos por el programador).

El resultado puede ser la creación de un código más fácil de leer y depurar, con la desventaja de que si no se utiliza con el cuidado suficiente pueden producirse graves problemas a sus programas.

La sobrecarga es una de las características más importantes de C++ y de la programación orientada a objetos. Con ella se puede redefinir el lenguaje C++ y proporciona a los programadores una herramienta que les facilitará manipular los tipos definidos por el usuario y nuevos tipos de datos abstractos de igual forma como se hace con los tipos incorporados al lenguaje.

Así por ejemplo, se pueden utilizar expresiones tales como:

objeto_1 = objeto_1 + objeto_2;

objeto_1 = objeto_1 * objeto_2;



Top de la Pagina

Operadores que se pueden Sobrecargar

Unarios ++ , --

Binarios / , % , () , [] , new , delete , += , -= , *= , /= , | , ^ , || , && , < , <= , > , >= , << , >> ,

|= , ^= , &= , <<= , >>= , == , = , -> , = , %= , ´ , ->*

Unarios o Binarios + , - , * , &

No está por demás mencionar que un operador unitario actúa sobre un sólo objeto y un operador binario sobre dos objetos.

Operadores que no se pueden sobrecargar . , .* , :: , ?: , sizeof

La sobrecarga de un operador es una función incorporada a C++ que permite al programador sustituir alguno de los operadores ya existentes por una función definida por el usuario. Las funciones operadoras sobrecargadas se eligen por el compilador utilizando el mismo mecanismo que se utiliza para elegir entre diferentes funciones sobrecargadas. Cuando se encuentra un operador no intrínseco, el compilador busca una función operador busca una función operador que tenga parámetros que correspondan con los operandos que se encuentran. Las funciones operador tienen la misma prioridad que las operaciones intrínsecas que utilizan el mismo operador. Por ejemplo: wl operador * siempre tiene mayor prioridad que el operador +.

 

Restricciones en los operadores sobrecargados

1.- Sólo se pueden sobrecargar operadores definidos en C++.

2.- La sobrecarga de operadores sólo funciona con objetos del alguna clase.

3.- No se puede cambiar la preferencia o asociatividad de los operadores definidos en C++.

4.- No se puede hacer funcionar a un operador binario como unitario ni viceversa.

5.- No se puede sobre cargar un operador que funcione exclusivamente con apuntadores.

6.- Es responsabilidad del programador definir correctamente el significado de las funciones sobrecargadas.

7.- No se pueden derivar operadores sobrecargados complejos de otros más simples. Por ej: Si se definen operator* y operator= y se desea realizar a*=b, es necesario

sobrecargar el operador *=.

Mecanismo de sobrecarga de operadores

El formato general de la sobrecarga de un operador es:

tipo nombre_clase :: operator <op> (lista_de_args) { . . . }

tipo es tipo de valor devuelto por la operación especificada (función operador). <op> es el operador que se está sobrecargando.

Las funciones operador deben ser miembros o amigas de la clase que se está utilizando.



Top de la Pagina

Sobrecarga de Operadores Unitarios

Ejemplo:

class vector {

double x, y;

public:

vector (double xi, double yi) { x=xi; y=y1; }

void Visualizar() { cout << "Vector x= " << x << " y = " y; }

doble operator++()

{x++; y++;}

};

void main(void)

{ vector v1(10.5, 20.6);

v1.Visualizar();

v1++;

v1.Visualizar();

}

Con v++; se llama la función operator++() que incrementa los datos del objeto vector v1 en 1.

Sobrecarga de los operadores ++ y -- en forma prefija y posfija. La versión posfija de los operadores ++ y -- sobrecargados dentro de una clase recibe un argumento int, mientras que la versión prefija no.

Ejemplo:

class vector {

int x, y;

public:

vector() {x=0; y=0; }

vector& operator++() { x+=2; y+=2; return *this; } //prefija

vector& operator++(int) { x++; y++; return *this; } //posfija

ImprimeVector() { cout << "v " << x << " " << y << endl; }

} ;

void main(void)

{

vector v1;

v1++; // Se ejecuta el método operator++(int)

v1.ImpVector();

++v1; // Se ejecuta el método operator++()

v1.ImpVector();

v1=v1.operator++(); //Equivale a ++v1;

v1.ImpVector();

v1=v1.operator++(1); //Equivale a v1++;

v1.ImpVector();

}

Sobrecarga de operadores unitarios que no son miembros de alguna clase

class vector {

Int x, y;

public:

vector() {x=0; y=0; }

void Incrementa(int incr) { x+=incr; y+=incr; }

ImprimeVector() { cout << "v " << x << " " << y << endl; }

} ;

//posfija

vector& operator++(vector& vaux, int ) { vaux.Incrementa(1); return vaux; }

//prefija

vector& operator++(vector& vaux) { vaux.Incrementa(2); return vaux; }

 

void main(void)

{

vector v1;

v1++; // Se ejecuta la función operator++(int)

v1.ImpVector();

++v1; // Se ejecuta la función operator++()

v1.ImpVector();

v1=operator++(v1); // Equivale a ++v1;

v1.ImpVector();

v1=operator++(v1, 0); //Equivale a v1++;

v1.ImpVector(); }



Top de la Pagina

Sobrecarga de Operadores Binarios

Los operadores binarios se pueden sobrecargar tan fácilmente como los operadores unitarios.

Ejemplo:

class vector {

int x, y;

public:

vector(int xi = 0, yi = 0) {x = xi; y = yi; }

ImprimeVector() { cout << "v " << x << " " << y << endl; }

vector operator+(vector v) { vector vaux; vaux.x= x + v.x; vaux.y = y + v.y; return vaux; }

vector& operator-(vector& v) { vector *vaux= new vector; vaux->x= x - v.x; vaux->y = y - v.y;

return *vaux; }

};

void main(void)

{

vector v1, v2(2,3), v3(4,6);

v1 = v2 + v3; //Se ejecuta el método operator+(vector v)

v1.ImpVector();

v1 = v2 - v3; //Se ejecuta el método operator-(vector &v)

v1.ImpVector();

}



Top de la Pagina

Sobrecarga del Operador de Asignación

class vector {

int x, y;

public:

vector() {x=0; y=0; }

vector(int xi = 0, yi = 0) {x = xi; y = yi; }

vector& operator=(vector& v) {x=v.x; y=v.y; return *this; }

void Incrementa(int incr) { x+=incr; y+=incr; }

ImprimeVector() { cout << "v " << x << " " << y << endl; }

} ;

void main(void)

{

vector v1, v2(2,3), v3(4,6);

v1 = v2 ; //Se ejecuta el método operator=(vector v&)

v1.ImpVector();

v1 = v3; //Se ejecuta el método operator=(vector &v)

v1.ImpVector();

}

Sobrecarga del operador de llamada a función ( ) y el operador subíndice [ ] La llamada a función se considera como un operador binario. La función operador correspondiente es operator() y puede ser definida por el usuario para una clase (y cualquier clase derivada) sólo mediante una función miembro no estática.

El operador [ ] se utiliza normalmente como índice.

Ejemplo:

class string {

char *sPtr;

int length;

public:

String(const String &); // Constructor

String &operator() (int, int); //regresa un substring

char &operator[](int); //regresa una referencia a char

};

String::String(const char *s) { length=strlen(s); sPtr= new char[length+1]; strcpy(sPtr, s); }

char * String::operator()(int c) { return(strchr(sPtr, c)); }

char & String::operator[](int i) { return sPtr[i]; }

void main(void)

{

String s1("Hola Mundo!");

cout <};



Top de la Pagina

TEMPLATES (PLANTILLAS)

C++ tiene una característica llamada template que permite crear tipos parametrizados o declarar una familia completa de clases o funciones en lugar de sólo una.

Clases Genéricas

El propósito de la genericidad es definir una clase o una función sin especificar el tipo de uno o más de sus miembros (parámetros). A una clase de este tipo se le llama clase contenedora. La genericidad se puede emular utilizando herencia y polimorfismo, A continuación veremos un

Ejemplo.

 

 

#include

#include

#include

class ObjetoGenerico {

public:

virtual void Dibuja() {};

};

class Circulo : public ObjetoGenerico {

int x, y, r;

public:

Circulo(int xi=100, int yi=100, int ri=100) { x=xi ; y=yi; r=ri;}

void Dibuja() { circle(x, y, r); }

};

class Elipse : public ObjetoGenerico {

int x, y, rx, ry;

public:

Elipse(int xi=100, int yi=100, int rxi=60, int ryi=80) { x=xi; y=yi; rx=rxi; ry=ryi; }

void Dibuja() { ellipse(x, y, 0, 360, rx, ry) ; }

};

class Rectangulo : public ObjetoGenerico {

int xizq, yarriba, ancho, alto;

public:

Rectangulo(int xi=10, int yi=10, int an=40, int al=60) { xizq=xi; yarriba=yi;ancho=an; alto=al; }

void Dibuja() { rectangle(xizq, yarriba, xizq+ancho, yarriba+alto); }

};

class Nodo {

ObjetoGenerico *figura;

Nodo *sig;

public:

Nodo(ObjetoGenerico *fig) { figura=fig; }

Nodo * RecuperaSiguiente() { return sig; }

void PonerSiguiente(Nodo *nodosig) { sig=nodosig; }

void Muestra(){ figura->Dibuja(); }

};

class Lista {

Nodo *cabeza;

public:

Lista(){ cabeza=new Nodo(NULL); cabeza->PonerSiguiente(NULL); }

void Insertar (ObjetoGenerico *fig);

void Desplegar();

};

void Lista::Insertar(ObjetoGenerico *fig)

{

Nodo *aux;

for(aux=cabeza; aux->RecuperaSiguiente()!=NULL; aux=aux->RecuperaSiguiente());

Nodo *nuevo = new Nodo(fig);

nuevo->PonerSiguiente(NULL);

aux->PonerSiguiente(nuevo);

}

void Lista::Desplegar()

{ Nodo *aux;

for(aux=cabeza->RecuperaSiguiente(); aux!=NULL; aux=aux->RecuperaSiguiente())

aux->Muestra();

}

void main()

{

int graphdriver = DETECT, graphmode;

initgraph(&graphdriver, &graphmode, "..\\bgi");

Lista ListaFig;

Circulo *c1 = new Circulo(50,50,80);

ListaFig.Insertar(c1);

Elipse *e1 = new Elipse;

ListaFig.Insertar(e1);

Rectangulo *r1 = new Rectangulo(30,50);

ListaFig.Insertar(r1);

ListaFig.Desplegar();

closegraph();

}



Top de la Pagina

Templates en Funciones

Los templates nos proporcionan una solución elegante que nos evita escribir varias veces el mismo código para una función. Especifica un conjunto infinito de funciones sobrecargadas, pero permitiendo realizar la verificación de los tipos efectuados por C++.

Formato:

template declaración o definición de funciones

Los paramétros puden ser de dos categorías: tipos y constantes.

Los tipos se representan poneindo el prefijo class. Sin el prefijo, se trata de cómo constante.

Ejemplos:

template <class T>

template <int LongArray, int LongElem>

template <class TipoElem, long Longitud, class TipoComparador>

Ejemplo:

#include

template T min(T a, T b) { return a < b ? a: b; }

void main()

{ int ia=1, ib=5; cout << "Menor: " << min(ia, ib) << endl;

char la=‘a’, lb=‘n’; cout << "Menor: " << min(la, lb) << endl;

float fa=88.4, fb=19.9; cout << "Menor: " << min(fa, fb) << endl;

}



Top de la Pagina

Templates en Clases

Nos permiten definir clases genéricas que pueden manipular varios tipos de datos. Son útiles para implementar contenedores que son clasesque contienen objetos de un tipo dado: las clases contenedores permiten administrar listas ligadas de objetos, tablas cuyo tamaño puede variar dinámicamente, conjuntos, etc.

Ejemplo:

#include

template class stackvector {

T *data;

int tope;

unsigned int size;

public:

stackvector (unsigned int tam);

T pop();

void push(T value);

};

template stackvector :: stackvector(unsigned int tam): size(tam)

{ data = new T[size]; tope = size +1; }

template void stackvector :: push(T val)

{ if ( tope == 1) cout << "Pila llena";

else data[--tope]=val;

}

template void stackvector :: pop()

{ if (tope == (size+1) return -1;

else return data[tope +1];

}

 

void main()

{

stackvector st(5);

st.push(5);

st.push(3);

st.push(2);

for(i=0; i<3; i++) cout << " " << st.pop();

stackvector st(6);

st.push(3.1416);

st.push(1.7178);

st.push(0.0001);

st.push(12345.123);

for(i=0; i<3; i++) cout << " "<< st.pop();

}

Ejemplo:

class alfa {

public:

double suma; //funciones púlicas

};

class beta: public alfa {

public:

int n; //funciones públicas

};



Top de la Pagina

Clases de Derivación

Derivación públca (public clase base)

Todos los miembros public y protected de la clase base son accesibles en la clase derivada, mientras que los miembros private de la clase base son inaccesibles en la clase derivada.

class Base {

public:

void f();

int a, b;

private:

float c, d;

};

class Derivada: public Base {

public:

void g();

};

void main()

{ Derivada d;

d.a=50;

d.b=100;

d.f();

d.c=100; //Error: miembro privado de la clase base

}

 



Top de la Pagina

Derivación Privada (private clase base)

Todos los miembros de la clase base se comportan como miembros privados de la clase derivada. En este caso, los miembros public y protected de la clase base no son accesibles mas que por las funciones miembro de la clase derivada. Los miembros privados de la clase base siguen siendo incaccesibles desde la clase derivada.

class Base {

public:

void f1();

void f2();

int a, b;

private:

float c, d;

};

class Derivada: private Base {

public:

Base::f1(); //acceso autorizado de modo explícito

Base::a;

};

void main()

{ Derivada d;

d.a =50; //Válido

d.b=100; //Error, acceso prohibido

d.f1(); // Válido

d.f2(); //Error, acceso prohibido

d.c=100, //Error, miembro privado de la clase

}



Top de la Pagina

Derivación Protegida (public clase base)

Se utiliza de modo similar a la derivación private. Todos los miembros public y protected de la clase base se comportan como miembros protected en la clase derivada. Estos miembros no son pues, accesibles al programa exterior, pero las clases que se deriven a continuación podrán acceder normalmente a estos miembros.

class Derivada: protected Base {

public:

// ...

};

Ventajas e inconvenientes de la derivación privada y protegida Las derivaciones private y protected son útiles cuando se desea asegurar que solamente la interfase de nuestra clase derivada pueda ser utilizada por el programa principal y/o por las otras clases derivadas de ésta. Como inveconvenientes, la utilización de las derivaciones private y protected complican el árbol de herencia, volviéndose más compleja la determinación de derecho de acceso. a los miembros de cada clase, a partir de la simple lectura de su programa.

Es aconsejable usar estos dos tipos de derivación en que puedan existir razones de peso para su uso. Cuando no se utiliza un especificador de acceso, C++ considera por defecto una derivación privada.

class Derivada: Base { //La derivación es privada por defecto

public:

// ...

};

Jerarquia de Clases

class ObjetoGenerico {

public:

virtual void Dibuja() {};

};

class Circulo : public ObjetoGenerico {

int x, y, r;

public:

Circulo(int xi=100, int yi=100, int ri=100) { x=xi ; y=yi; r=ri;}

void Dibuja() { circle(x, y, r); }

};

class Elipse : public ObjetoGenerico {

int x, y, rx, ry;

public:

Elipse(int xi=100, int yi=100, int rxi=60, int ryi=80) { x=xi; y=yi; rx=rxi; ry=ryi; }

void Dibuja() { ellipse(x, y, 0, 360, rx, ry) ; }

};

class Rectangulo : public ObjetoGenerico {

int xizq, yarriba, ancho, alto;

public:

Rectangulo(int xi=10, int yi=10, int an=40, int al=60) { xizq=xi; yarriba=yi; ancho=an; alto=al; }

void Dibuja() { rectangle(xizq, yarriba, xizq+ancho, yarriba+alto); }

};



Top de la Pagina

Herencia Múltiple

La herencia múltiple es la propiedad con la cual una clase derivada puede tener más de una clase base o padre. También se conoce como derivación de clase con clase base múltiple.

class ObjetoGenerico {

public:

virtual void Dibuja() {};

};

class PropiedadesGenerales {

protected:

char etiqueta[32];

public:

char TipoFigura[32];

void PonerTipoFigura(int tipo) {

if(tipo == 1) strcpy((char *)TipoFigura, (const char *)"Circulo");

if(tipo == 2) strcpy((char *)TipoFigura, (const char *)"Elipse");

if(tipo == 3) strcpy((char *)TipoFigura, (const char *)"Rectángulo");

}

};

class Circulo : public ObjetoGenerico, public PropiedadesGenerales {

int x, y, r;

public:

Circulo(int xi=100, int yi=100, int ri=100, char *etiq) { x=xi ; y=yi; r=ri;

strcpy((char *)etiqueta, (const char *)etiq); }

void Dibuja() { circle(x, y, r); }

};

void main()

{

Circulo *c1 = new Circulo(50,50,80, "MiCirculo");

c1->PonerTipoFigura(1);

}



Top de la Pagina

Ambigüedades en herencia múltiple

Una de las ambigüedades más comunes se da cuando dos clases base tienen funciones con el mismo nombre, y sin embargo, una clase derivada de ambas no tiene una función con ese nombre. Para resolver la ambigüedad se usa el operador de ámbito.

class A {

public:

void mostrar() { cout << "\n Clase A"; }

};

class B {

public:

void mostrar() { cout << "\n Clase B"; }

};

clase C : public A, public B

{ };

void main()

{

C obietoC; // Se crea un objeto de la clase C

objetoC.mostrar( ) // Error. Se tiene ambigüedad

objetoC.A::mostrar( ); // Correcto

objetoC.B::mostrar( ); // Correcto }

Constructores y destructores en herencia múltiple

Durante la construcción de un objeto perteneciente a una clase derivada , se llaman sucesivamente los constructores de sus clases base en el orden de sus declaraciones. Al final se llama el constructor de la clase derivada.

class A {

protected:

int x;

void f(int i) { x = i ; }

public:

A(int a = 1) { x = a ; }

};

class B {

protected:

int y;

void g(int i) { y = i ; }

public:

B(int b = 1) { x = b ; }

};

class C: public A, public B {

protected:

int z;

void h(int i) { cout << x << " " << y << " " << z ; }

public:

C(int c = 1) ;

};

C::C(int c) : A( 2 * a ) , B( 3 * a)

{ x = c ; }

void main()

{

C ObjetoC(5) ;

ObjetoC.h() ; }



Top de la Pagina


Examen!

Si has Estudiado Bien el Capitulo Click Aqui para hacer el Examen 8


Glosario del Tutorial

¿No Entiendes Bien Algún Concepto?... Consultalo!


Busqueda en el Tutorial

¿Deseas Encontrar Algo Especifico?...Encuentralo!



Este tutorial desarrolla al 100% sus Aplicaciones con un Navegador en 800x600

OPCIÓN ALTERNA:
Introducción@Elementos de C@Apuntadores y Arreglos@Estructuras y Uniones@Bibliografía

Archivos y Gráficos@POO1@POO2@POO3@Creditos@Presentación Principal@Menú Principal


Todos los Derechos Reservados por El Instituto Tecnológico de Querétaro Mexico. "La tierra será como sean los Hombres"

Ultima Actualización: México Noviembre de 1999