You are on page 1of 7

Creación de objetos Operador new Ahora que ya sabemos cómo definir las clases de objetos que podremos usar

en nuestras aplicaciones ha llegado el momento de explicar cómo crear objetos de una determinada clase. Algo de ello ya se introdujo en el Tema 4: Aspectos Léxicos cuando se comentó la utilidad del operador new, que precisamente es crear objetos y cuya sintaxis es:

new <nombreTipo>(<parametros>) Este operador crea un nuevo objeto del tipo cuyo nombre se le indica y llama durante su proceso de creación al constructor del mismo apropiado según los valores que se le pasen en <parametros>, devolviendo una referencia al objeto recién creado. Hay que resaltar el hecho de que new no devuelve el propio objeto creado, sino una referencia a la dirección de memoria dinámica donde en realidad se ha creado. El antes comentado constructor de un objeto no es más que un método definido en la definición de su tipo que tiene el mismo nombre que la clase a la que pertenece el objeto y no tiene valor de retorno. Como new siempre devuelve una referencia a la dirección de memoria donde se cree el objeto y los constructores sólo pueden usarse como operandos de new, no tiene sentido que un constructor devuelva objetos, por lo que no tiene sentido incluir en su definición un campo <tipoDevuelto> y el compilador considera erróneo hacerlo (aunque se indique void) El constructor recibe ese nombre debido a que su código suele usarse precisamente para construir el objeto, para inicializar sus miembros. Por ejemplo, a nuestra clase de ejemplo Persona le podríamos añadir un constructor dejándola así:

class Persona { string Nombre; // Campo de cada objeto Persona que almacena su nombre int Edad; // Campo de cada objeto Persona que almacena su edad string NIF; // Campo de cada objeto Persona que almacena su NIF void Cumpleaños() // Incrementa en uno la edad del objeto Persona { Edad++; }

cuando creemos el objeto el compilador podrá inteligentemente determinar cuál de los constructores ha de ejecutarse en función de los valores que le pasemos al new. "12344321-A") Nótese que la forma en que se pasan parámetros al constructor consiste en indicar los valores que se ha de dar a cada uno de los parámetros indicados en la definición del mismo separándolos por comas. } } Como se ve en el código. aunque para diferenciar a unos de otros es obligatorio que se diferencien en el número u orden de los parámetros que aceptan. el constructor toma como parámetros los valores con los que deseemos inicializar el objeto a crear. "12344321-A"). si se definió de tipo int habrá que pasarle un entero y. int edad. Gracias a él.muestra cómo crear una variable de tipo Persona llamada p y cómo almacenar en ella la dirección del objeto que devolvería la anterior aplicación del operador new: Persona p. // Almacenamos en p el objeto creado con new A partir de este momento la variable p contendrá una referencia a un objeto de clase Persona que representará a una persona llamada José de 22 años y NIF . produciéndose un error al compilar si no se hace así. podemos crear un objeto Persona de nombre José. en general. Obviamente. Una vez creado un objeto lo más normal es almacenar la dirección devuelta por new en una variable del tipo apropiado para el objeto creado. string nif) // Constructor { Nombre = nombre.Persona (string nombre. El siguiente ejemplo -que como es lógico irá dentro de la definición de algún método. 22. ya que el nombre de todos ellos ha de coincidir con el nombre de la clase de la que son miembros. de 22 años de edad y NIF 12344321-A así: new Persona("José". Edad = edad. a todo parámetro habrá que pasarle un valor de su mismo tipo (o de alguno convertible al mismo). // Creamos variable p p = new Persona("Jose". En realidad un objeto puede tener múltiples constructores. si un parámetro se definió como de tipo stringhabrá que pasarle una cadena. NIF = nif. 22. De ese modo.

como si se hubiese definido de esta forma: <nombreTipo>(){} Gracias a este constructor introducido automáticamente por el compilador. una sintaxis más general para la definición de variables es la siguiente: <tipoDato> <nombreVariable> = <valorInicial>. y en caso de que no definamos ninguno el compilador creará uno por nosotros sin parámetros ni instrucciones. siempre será posible crear uno nuevo usando el operador new así: Coche c = new Coche(). De hecho. Como lo más normal suele ser crear variables donde almacenar referencias a objetos que creemos. 22. Es decir. y si no se incluye la variable declarada pasará a almacenar una referencia nula (contendrá el literal null) Constructor por defecto No es obligatorio definir un constructor para cada clase. las instrucciones anteriores pueden compactarse en una sola así: Persona p = new Persona("José". O lo que prácticamente es lo mismo y suele ser la forma comúnmente usada para decirlo: la variable p representa a una persona llamada José de 22 años y NIF 12344321-A. si tenemos una clase en la que hayamos definido algún constructor con parámetros pero ninguno sin parámetros no será válido crear objetos de la misma llamando al . "12344321-A"). si Coche es una clase en cuya definición no se ha incluido ningún constructor. La parte = <valorInicial> de esta sintaxis es en realidad opcional. //Crea coche c llamando al constructor por defecto de Coche Hay que tener en cuenta una cosa: el constructor por defecto es sólo incluido por el compilador si no hemos definido ningún otro constructor.12344321-A. Por tanto.

constructor sin parámetros. Por ejemplo. con la última versión de la clase de ejemplo Persona es inválido hacer: Persona p = new Persona(). Generalmente. Introducción Mientras un programa esta corriendo todas las variables se guardan en memoria. Proporcionan mucha utilidad al programador para accesar y manipular datos de maneras que no es posible en otros lenguajes. una variable y su localidad asociada contienen valores. cuando declaras: int count = 5. Cuando se utilizan incorrectamente. El valor "5" se guarda en memoria y puede ser accesado usando la variable "count". pues el compilador no lo habrá definido automáticamente. cada una tiene su dirección o localidad única. Un apuntador es un tipo especial de variable que contiene una dirección de memoria en lugar del valor de un dato. // ERROR: // El único constructor de Persona // toma 3 parámetros Introducción a los apuntadores Los apuntadores son variables que guardan direcciones en C y C++. Por ejemplo. Tambien son utiles para pasarle parametros a las funciones de tal modo que les permiten modificar y regresar valores a la rutina que las llama. son también fuente tanto de fallas en el programa como de frustración para el programador :P. Tal como un dato es modificado cuando .

/* pt2 contiene la dirección de la variable k */ pt3 = values. Declaración e inicialización Declarar e inicializar apuntadores es bastante fácil. /* pt3 contiene la dirección del primer elemento de values */ pt3 = &values[0]. La referencia se hace con el operador unario "*". int *pt1. /* Declara un apuntador flotante */ j = 1. int total. Los apuntadores son un tema dificil. int l. /* Declara un apuntador entero */ float values[100]. Generalmente. /* pt1 contiene la dirección de la variable j */ pt2 = &k. float results[100]. Hay ejemplos de los tipos de operaciones ya discutidas abajo. ptr = &count /* Guarda la dirección de count en ptr */ /* El operador unario & regresa la dirección de una variable */ Para obtener el valor que esta guardado en la localidad de memoria del apuntador es necesario referenciar el apuntador.una variable normal es usada. int *ptr. el valor de la dirección guardado en el apuntador cambia cuando este es manipulado. pt1 = &j. k = 2. /* Declara un apuntador entero */ int *pt2. No te preocupes si todavía no queda todo claro. int k. } . /* El valor de la direccipon guardada en ptr es asignada a total */ La mejor manera de aprender a usar apuntadores es con ejemplos. int main() { int j. float *pt3. /* Declara un apuntador flotante */ float *pt4. /* Esto es equivalente a la afirmación de arriba */ return 0. la dirección guardada en el apuntador es la dirección de alguna otra variable. total = *ptr.

El apuntador guarda una dirección de memoria. /* El segundo elemento de values tiene pay (de hecho pi)*/ pt3 += 25. pt3 = &values[0]. La referencia permite que los datos en esa dirección de memoria sean modificados. Esto quiere decir que esta instrucción le suma 2 al contenido de la dirección de memoria guardada en el apuntador pt1. ahora */ for (ii = 0. pt1 contiene la dirección de j. /* pt3 ahora contiene la dirección del segundo elemento de values */ *pt3 = 3. ii++) { *pt3++ = 37. /* esto pone todo el arreglo en 37. /* asigna el contenido de la memoria apuntada por pt1 */ /* al contenido de la memoria apuntada por pt2 */ k = *pt2. /*pt3 apunta al primer elemento de values. en el programa main.22222 */ pt3 = values.0. Los apuntadores pueden ser incrementados. El efecto del código de arriba es sumar 2 a j.Referencia de apuntadores/ Asignación de valores La referencia permite manipular los datos contenidos en la dirección de memoria guardada en el apuntador. *pt2 = *pt1. Recordando el apuntador flotante "pt3" y el arreglo flotante "values" declarados en el programa main de arriba. /* el elemento 27 de values ahora es 2. Así.1415927. Esto le añade dos al valor "apuntado por" pt1. ii < 100. /* pt3 ahora apunta al elemento 27 de values */ *pt3 = 2. El operador unario "*" se usa para la referencia. decrementados y manipulados usando expresiones matemáticas. La variable "j" fue inicializada en 1.22222. /* La dirección del primer elemento de "values" se guarda en pt3*/ pt3++. Por ejemplo: *pt1 =*pt1 + 2.0 */ } . El contenido de las direcciones guardadas en un apuntador pueden ser asignadas a otro apuntador o variable. /* asigna el contenido del apuntador pt2 por dos a k */ Aritmética de apuntadores Parte del poder de los apuntadores viene de la habilidad de realizar operaciones matemáticas sobre los mismos apuntadores.

} . /* pt4 contiene la dirección del primer elemento de results */ for (ii=0. /* Los contenidos de las direcciones de pt3 se le asignan a los contenidos de las direcciones de pt4 */ pt4++. pt3++. /* pt3 contiene la dirección del primer elemento de values */ pt4 = &results[0]. ii < 100.pt3 = &values[0]. ii++) { *pt4 = *pt3.