Las clases son un concepto extendido de estructuras de datos: al igual que las estructuras de datos, pueden contener miembros de datos, pero también pueden contener funciones como miembros.

    Un objeto es una instanciación de una clase. En términos de variables, una clase sería el tipo y un objeto sería la variable.

    Las clases se definen utilizando la clase de palabra clave o la estructura de palabra clave, con la siguiente sintaxis:

    class nom_classe { access_specifier_1: member1; access_specifier_2: member2; ...} object_names;

    Donde class_name es un identificador válido para la clase, object_name es una lista opcional de nombres para los objetos de esta clase. El cuerpo de la declaración puede contener miembros, que pueden ser declaraciones de datos o de funciones, y posiblemente especificadores de acceso.

    Las clases tienen el mismo formato que las estructuras de datos de texto plano, excepto que también pueden incluir funciones y tienen estas cosas nuevas llamadas especificadores de acceso. Un especificador de acceso es una de las tres palabras clave: privado, público o protegido. Estos prescriptores modifican los derechos de acceso de los miembros que los siguen:

    • Los miembros privados de una clase sólo son accesibles desde otros miembros de la misma clase (o sus «amigos».
    • los miembros protegidos son accesibles desde otros miembros de la misma clase (o sus «amigos»), pero también desde miembros de sus clases derivadas.
    • Por último, los miembros públicos son accesibles desde cualquier lugar donde el objeto sea visible.

    Por defecto, todos los miembros de una clase declarada con la clase keyword tienen acceso privado para todos sus miembros. Por lo tanto, cualquier miembro declarado antes que cualquier otro especificador de acceso tiene automáticamente acceso privado. Por ejemplo:

    clase Rectángulo { int ancho, alto; Público: void set_values (int, int); int zona (void);} rect;

    Declara una clase (es decir, un tipo) llamada Rectángulo y un objeto (es decir, una variable) de esta clase, llamado rectángulo. Esta clase contiene cuatro miembros: dos miembros de datos del tipo int (ancho y alto de miembro) con acceso privado (porque privado es el nivel de acceso por defecto) y dos funciones de miembro con acceso público: los set_values y las funciones de área, sólo han incluido su declaración, pero no su definición.

    Note la diferencia entre el nombre de la clase y el nombre del objeto: en el ejemplo anterior, Rectangle era el nombre de la clase (es decir, el tipo), mientras que Rectangle era un objeto del tipo Rectangle. Es la misma relación interna y un tener en la siguiente declaración:

    int a;

    donde int es el nombre del tipo (la clase) y tiene el nombre de la variable (el objeto.

    Después de las sentencias Rectangle y rect, se puede acceder a uno de los miembros públicos del objeto rectángulo como si fueran funciones normales o variables normales, simplemente insertando un punto (.) entre el nombre del objeto y el nombre del miembro. Esto sigue la misma sintaxis que para acceder a los miembros de estructuras de datos simples. Por ejemplo:

    rect.set_values (3,4);myarea = rect.area ();

    Los únicos miembros rectos a los que no se puede acceder desde fuera de la clase son la anchura y la altura, ya que tienen acceso privado y sólo otros miembros de la misma clase pueden referirse a ellos.

    Aquí está el ejemplo completo de la clase Rectángulo:

    // ejemplo de clase#incluye <iostream>usando namespace std;class Rectangle { int width, height; Public: void set_values (int, int, int); int area () {return width * height * height * height;}};void Rectangle :: set_values (int x, int y) { width = x; height = y;}int hand () { Rectangle rectangle; rectangle.set_values (3,4); cout << "area:" <<<<< rect.area (); return 0;}

    Resultado de la ejecución:

    area: 12Modificar y ejecutar

    Este ejemplo reintroduce el operador del osciloscopio (:::, dos puntos), como se ha visto en los capítulos anteriores en relación con los namespaces.

    Aquí, se utiliza en la definición de la función set_values para definir un miembro de una clase fuera de la propia clase.

    Tenga en cuenta que la definición del área de función de los miembros se ha incluido directamente en la definición de la clase Rectángulo debido a su extrema simplicidad. Por el contrario, set_values simplemente se declara con su prototipo en la clase, pero su definición no le pertenece. En esta definición externa, el operador de pentagrama (::: : : 🙂 se utiliza para especificar que la función que se está definiendo es un miembro de la clase Rectángulo y no una función regular no miembro.

    El operador de personal (::::::) especifica la clase a la que pertenece el miembro que se está definiendo actualmente, asignando exactamente las mismas propiedades de personal que si esta definición de función estuviera directamente incluida en la definición de clase. Por ejemplo, la función set_values del ejemplo anterior tiene acceso a las variables width y height, que son miembros privados de la clase Rectangle y por lo tanto sólo son accesibles desde otros miembros de la clase, como ésta.

    La única diferencia entre definir completamente una función de miembro en la definición de clase o simplemente incluir su declaración en la función y luego definirla fuera de la clase es que, en el primer caso, la función es considerada automáticamente como una función de miembro en línea por el compilador, mientras que en el segundo caso, es una función normal de miembro de clase (no en línea. Esto no causa ninguna diferencia en el comportamiento, sino sólo en las posibles optimizaciones del compilador.

    La anchura y la altura de los miembros tienen acceso privado (recuerde que si no se especifica nada más, todos los miembros de una clase definida con la palabra clave de la clase tienen acceso privado. Al declararlos privados, no se permite el acceso desde fuera de la clase. Esto tiene sentido, porque ya hemos definido una función miembro para definir los valores de estos miembros en el objeto: la función miembro set_values. Por lo tanto, el resto del programa no necesita tener acceso directo a él. Tal vez en un ejemplo tan simple, es difícil ver cuán útil puede ser restringir el acceso a estas variables, pero en el caso de proyectos más grandes, puede ser muy importante que los valores no puedan ser cambiados inesperadamente.

    La propiedad más importante de una clase es que es un tipo. Por lo tanto, podemos declarar varios objetos. Por ejemplo, con el ejemplo anterior de la clase Rectángulo, podríamos haber declarado el objeto rectángulo además del objeto rectángulo:

    // Ejemplo: una clase, dos objetos#incluyen <iostream>usando namespace std; clase Rectangle { int width, height; Public: void set_values (int, int, int); int area () {return width * height;}};void Rectangle :: set_values (int x, int y) { width = x; height = y;}int hand () { Rectangle rect, rectb; rectb.set_values (3,4); rectb.set_values (5,6); coste <<<< "rect area:" <<<<< rect.area () << endl; coste <<<< "rectb area:" <<<<<<< rectb.area () <<<< endl; return 0;}

    Resultado de la ejecución:

    superficie de la parcela: 12 rectos: 30
    

    En este caso particular, la clase (tipo de objeto) es Rectángulo, con dos instancias (objetos): rect y rectángulo. Cada uno de ellos tiene sus propias variables y funciones de miembro.

    También lea Estructura de un programa en C++Note

    que la llamada al área rectal () no da el mismo resultado que la llamada al área rectal (. Esto se debe a que cada objeto de la clase Rectángulo tiene sus propias variables de anchura y altura, porque también tienen, en cierto modo, sus propios set_value y miembros de función de área que actúan sobre las propias variables de miembro del objeto.

    Las clases permiten programar utilizando paradigmas orientados a objetos: los datos y las funciones son miembros del objeto, lo que reduce la necesidad de transmitir y transportar gestores u otras variables de estado como argumentos de función, ya que forman parte del objeto cuyo miembro es llamado.

    Tenga en cuenta que no se han transmitido argumentos en las llamadas al área rectal o al área rectal. Estas funciones de miembro utilizan directamente los datos de miembro de sus respectivos objetos rectos y rectos.

    Los fabricantes

    ¿Qué pasaría en el ejemplo anterior si llamáramos al área funcional de miembros antes de llamar a set_values? Un resultado indeterminado, porque nunca se ha asignado un valor a la anchura y a la altura de las barras.

    Para evitar esto, una clase puede incluir una función especial llamada su constructor, que se llama automáticamente cada vez que se crea un nuevo objeto de esta clase, permitiendo a la clase inicializar variables de miembro o asignar almacenamiento.

    Esta función de constructor se declara como una función de miembro regular, pero con un nombre que corresponde al nombre de la clase y sin ningún tipo de retorno; ni siquiera cero.

    La clase Rectángulo de arriba puede ser fácilmente mejorada implementando un constructor:

    // Ejemplo: constructor de clase#incluye <iostream>usando namespace std;class Rectangle { int width, height; Public: Rectangle (int, int, int); int area () {return (width * height);};Rectangle :: Rectangle (int a, int b) { width = a; height = b;}int hand () { Rectangle rectangle (3,4); Rectangle rectb (5,6); cost <<<<<< rect rectángulo.área () <<<<<<<<< "área rectal:" <<<<<<< área rectal () <<< endl; retorno 0;}

    Resultado de la ejecución:

    superficie de la parcela: 12 rectos: 30

    Los resultados de este ejemplo son idénticos a los del ejemplo anterior. Pero ahora, la clase Rectángulo no tiene una función miembro set_values, sino un constructor que realiza una acción similar: inicializa los valores de anchura y altura con los argumentos que se le transmiten.

    Observe cómo se pasan estos argumentos al constructor cuando se crean los objetos de esta clase:

    Rectángulo rectángulo (3,4); Rectángulo rectángulo (5,6);

    No se puede llamar explícitamente a los fabricantes como si se tratara de funciones regulares de los miembros. Sólo se ejecutan una vez, cuando se crea un nuevo objeto de esta clase.

    Tenga en cuenta que ni la declaración de prototipo del fabricante (en la clase) ni la última definición del fabricante tienen un valor de retorno; ni siquiera son nulos: los fabricantes nunca devuelven valores, simplemente inicializan el objeto.

    Sobrecarga de los fabricantes

    Como cualquier otra función, un fabricante también puede ser sobrecargado con diferentes versiones tomando diferentes parámetros: con un número diferente de parámetros y/o parámetros de diferentes tipos. El compilador llamará automáticamente a aquel cuyos parámetros coincidan con los argumentos:

    // Sobrecarga de clase#incluye <iostream>usando namespace std;class Rectangle { int width, height; Public: Rectangle (); Rectangle (int, int); int area (void) {return (width * height);}};Rectangle :Rectángulo () { ancho = 5; alto = 5;}Rectángulo :: Rectángulo (int a, int b) { ancho = a; alto = b;}manecilla () { Rectángulo rectángulo (3,4); Rectángulo rectángulo; coste <<<< "área rectángulo:" <<<< recto.área () <<<<<<<<< "área rectal:" <<<<<<< área rectal () <<< endl; retorno 0;}

    Resultado de la ejecución:

    tamaño de parcela: 12 rectos superficie: 25

    En el ejemplo anterior, se construyen dos objetos de la clase Rectángulo: rectángulo y rectángulo. rectángulo se construye con dos argumentos, como en el ejemplo anterior.

    Pero este ejemplo también introduce un constructor de tipos especial: el constructor predeterminado. El constructor por defecto es el constructor que no toma ningún parámetro. Es especial porque se llama cuando se declara un objeto pero no se inicializa con un argumento. En el ejemplo anterior, el constructor predeterminado se llama rectb.

    Tenga en cuenta que rectb ni siquiera está construido con un conjunto vacío de paréntesis – de hecho, los paréntesis vacíos no pueden ser usados para llamar al constructor por defecto:

    Rectángulo rectángulo; // ok, constructor por defecto llamado Rectángulo rectángulo (); // oops, constructor por defecto NO llamado

    De hecho, el conjunto de paréntesis vacíos haría de rectc una declaración de función en lugar de una declaración de objeto: sería una función que no toma ningún argumento y devuelve un valor de tipo Rectángulo.

    Inicialización uniforme

    La forma de llamar a los fabricantes poniendo sus argumentos entre paréntesis, como se ha indicado anteriormente, se llama la forma funcional. Pero también se puede llamar a los fabricantes con otras sintaxis:

    Primero, los fabricantes con un solo parámetro pueden ser llamados usando la sintaxis de inicialización de la variable (un signo igual seguido por el argumento):

    class_name object_name = valor_de_inicialización;

    Más recientemente, C++ ha introducido la posibilidad de llamar a los fabricantes utilizando una inicialización uniforme, que es esencialmente la misma que la forma funcional, pero utilizando llaves ({}) en lugar de paréntesis (()):

    class_name object_name {valor, valor, valor, valor, valor,…}}

    Esta última sintaxis puede incluir un signo igual antes de los frenos.

    He aquí un ejemplo con cuatro maneras de construir objetos de una clase de la que el constructor toma sólo un parámetro:

    // clases e inicialización uniforme#incluye <iostream>usando namespace std;class Circle {doble radio; Público: Circle (doble r) {radius = r; } doble circunferencia () {return 2*radius*3.14159265;}};inside () { Circle foo (10.0); // functional form Circle bar = 20.0; // assignment init. Baz circle {30.0}; // uniform init. Circle qux = {40,0}; // as POD cost <<< "foo circumference:" <<<<<< foo.circum () <<]\ n'; return 0;}}

    Resultado de la ejecución:

    circunferencia del pie: 62.8319

    Una de las ventajas de la inicialización uniforme sobre la forma funcional es que, a diferencia de los corchetes, los corchetes no se pueden confundir con las declaraciones de función y, por lo tanto, se pueden utilizar para llamar explícitamente a los fabricantes por defecto:

    Rectángulo rectángulo; // constructor por defecto llamado Rectángulo rectángulo (); // declaración de función (constructor por defecto NO llamado)Rectángulo rectángulo {}; // constructor por defecto llamado

    La elección de la sintaxis para llamar a los constructores es en gran medida una cuestión de estilo. La mayor parte del código existente utiliza actualmente una forma funcional, y algunas guías de estilo más recientes sugieren elegir una inicialización uniforme por encima de las otras, aunque también tiene posibles trampas relacionadas con su preferencia, initializer_list.

    También readLe Polimorfismo en C++Inicialización de

    barras en constructores

    Cuando se utiliza un fabricante para inicializar otros miembros, estos otros miembros pueden ser inicializados directamente, sin utilizar las declaraciones contenidas en su cuerpo. Esto se hace insertando, antes del cuerpo del fabricante, un signo de dos puntos (:::) y una lista de inicializaciones para los miembros de la clase. Por ejemplo, considere una clase con la siguiente declaración:

    clase Rectángulo { int ancho, alto; Público: Rectángulo (int, int, int); int área () {ancho de retorno*alto ;}};

    El constructor de esta clase podría definirse, como de costumbre, de la siguiente manera:

    Rectángulo:: Rectángulo (int x, int y) {ancho = x; altura = y; }

    Pero también podría definirse usando la inicialización de miembros como:

    Rectángulo:: Rectángulo (int x, int y): ancho (x) {altura = y; }

    O incluso:

    Rectángulo:: Rectángulo (int x, int y): anchura (x), altura (y) {}

    Tenga en cuenta que en este último caso, el fabricante sólo inicializa sus barras, de ahí su cuerpo funcional vacío.

    Para los miembros de tipos fundamentales, independientemente de la definición de la ruta por encima del constructor, porque no están inicializados por defecto, pero para los objetos miembros (aquellos cuyo tipo es una clase), si no están inicializados después de los dos puntos, se construyen por defecto.

    La construcción por defecto de todos los miembros de una clase puede o no ser siempre práctica: en algunos casos, es un desperdicio (cuando el miembro es reiniciado en el constructor), pero en otros casos, la construcción por defecto ni siquiera es posible (cuando la clase no tiene un constructor por defecto. En este caso, los miembros deben estar inicializados en la lista de inicialización de miembros. Por ejemplo:

    // Inicialización del miembro#incluye <iostream>usando namespace std;class Circle { doble radio; Público: Circle (doble r): radio (r) {} doble zona () {radio de retorno*rayon*3.14159265;}}};clase Cilindro { Cilindro base; doble altura; Público: Cilindro (doble r, doble h): base (r), altura (h) {} doble volumen () {retorno base.area () * altura;}};int principal () { Cilindro foo (10,20); coste <<<<< "volumen foo:" <<<<< < < < < n'; retorno 0,}}.

    Resultado de la ejecución:

    el volumen de foo: 6283.19

    En este ejemplo, la clase Cilindro tiene un objeto miembro cuyo tipo es otra clase (el tipo básico es Círculo. Dado que los objetos de la clase Circle sólo se pueden construir con un parámetro, el constructor del cilindro debe llamar al constructor de la base. La única manera de hacerlo es hacerlo en la lista de inicialización de miembros.

    Estas inicializaciones también pueden utilizar una sintaxis de inicialización uniforme, utilizando {} llaves en lugar de () paréntesis:

    Cilindro:: Cilindro (doble r, doble h): base {r}, altura {h} {} {}.

    Punteros a la clase

    Los objetos también pueden ser apuntados por punteros: una vez declarados, una clase se convierte en un tipo válido. Por lo tanto, se puede utilizar como un tipo apuntado por un puntero. Por ejemplo:

    Rectángulo * rectángulo

    es un puntero a un objeto de la clase Rectángulo.

    Al igual que en las estructuras de datos simples, se puede acceder a los miembros de un objeto directamente desde un puntero mediante el operador de flechas (->. He aquí un ejemplo con algunas combinaciones posibles:

    // ejemplo de puntero en clases#include <iostream>usando namespace std;class Rectangle { int width, height; Public: Rectangle (int x, int y): width (x), height (y) {} int zone (void) {return width * height; }}; int main() { Rectangle obj (3, 4); Rectangle * foo, * bar, * baz; foo = & obj; bar = new rectangle (5, 6); baz = new Rectangle[2] {{2,5}, {3,6}}; cost <<<< "The obj zone:" <<<.área () <<<<<<<<<<<< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < <area () <<<<<'n'; cost <<< "Baz zone[1]:" <<<<<'baz[1] .area () <<<'n'; delete bar; delete [] baz; return 0;}}

    La mayoría de estos términos se han introducido en los capítulos anteriores. En particular, el capítulo sobre tablas presentaba el operador offset ([]) y el capítulo sobre estructuras de datos simples presentaba el operador de flechas (->.

    Clases definidas con estructura y unión

    Las clases se pueden definir no sólo con la clase de palabra clave, sino también con la estructura y la unión de las palabras clave.

    La palabra clave struct, generalmente utilizada para declarar estructuras de datos simples, también se puede utilizar para declarar clases con funciones de miembro, con la misma sintaxis que para la palabra clave class. La única diferencia entre las dos es que los miembros de las clases declaradas con la palabra clave struct tienen acceso público por defecto, mientras que los miembros de las clases declaradas con la palabra clave class tienen acceso privado por defecto. Para todos los demás fines, las dos palabras clave son equivalentes en este contexto.

    Por el contrario, el concepto de sindicatos difiere del de clases declaradas con estructura y clase, porque los sindicatos almacenan sólo un miembro de los datos a la vez, pero también son clases y, por lo tanto, también pueden desempeñar funciones de miembros. El acceso por defecto en las clases sindicales es público.

    Otros consejos interesantes:

    1. Las clases en C# Al definir una clase, se define un plan para un tipo de datos. Esto no define realmente ningún dato, pero sí define lo que significa la denominación de clase. Es decir, lo que es….
    2. Polimorfismo en C++ Antes de profundizar en este capítulo, es necesario tener una buena comprensión de los indicadores y la herencia de clase. Si no está realmente seguro de lo que significa una de las siguientes expresiones, debería……
    3. La Sintaxis Básica de C # C # C # C # es un lenguaje de programación orientado a objetos. En la metodología de programación orientada a objetos, un programa consiste en diferentes objetos que interactúan entre sí a través de acciones. Las acciones que uno……
    4. Estructuras de datos en C++ Una estructura de datos es un grupo de elementos de datos agrupados bajo el mismo nombre. Estos elementos de datos, llamados miembros, pueden tener diferentes tipos y longitudes. Se pueden declarar las estructuras de datos……