Las clases, esencialmente, definen los nuevos tipos que se utilizarán en el código C++. Y los tipos C++ no sólo interactúan con el código por medio de construcciones y asignaciones. También interactúan a través de los operadores. Por ejemplo, hagamos la siguiente operación sobre los tipos fundamentales:
int a, b, c;a = b + c;
Aquí se aplican diferentes variables de tipo fundamental (int) al operador de adición y luego al operador de asignación. Para un tipo aritmético fundamental, el significado de tales operaciones es generalmente obvio e inequívoco, pero puede no serlo para algunos tipos de clase. Por ejemplo:
struct maclasse { cadena de productos; precio flotante;} a, b, c;a = b + c;
Aquí, el resultado de la operación de adición en b y c no es obvio. De hecho, este código por sí solo causaría un error de compilación, porque el tipo maclass no tiene un comportamiento definido para las adiciones. Sin embargo, C++ permite que la mayoría de los operadores estén sobrecargados para que su comportamiento pueda ser definido para casi cualquier tipo, incluyendo clases. Aquí hay una lista de todos los operadores que pueden ser sobrecargados:
Operadores sobrecargables
+ – * / = + = – = * = / = <> <> = ==! = = ++ – % & ^ ! ~ ~ & = ^ = ^ = | = | = | = && || % = [ ] (), ->* -> nuevo borrar nuevo[] borrar[]
Los operadores están sobrecargados de funciones de operador, que son funciones estándar con nombres especiales: su nombre comienza con la palabra clave de operador seguida del signo de operador sobrecargado. La sintaxis es la siguiente:
tipo signo de operador (parámetros) {/ * *.... cuerpo.... * /}
Por ejemplo, los vectores cartesianos son conjuntos de dos coordenadas: x e y. La operación de sumar dos vectores cartesianos se define como la suma de las dos coordenadas x juntas y las dos coordenadas y juntas. Por ejemplo, sumando los vectores cartesianos (3.1) y (1.2) juntos daría (3 + 1.1 + 2) = (4.3. Esto podría implementarse en C++ con el siguiente código:
// ejemplo de sobrecarga de operadores#incluye <iostream>usando namespace std;class CVector {public:int x,y;CVector () {};CVector (int a,int b) : x(a), y(b) {}CVector operator + (const CVector&);};CVector CVector CVector::operator+ (const CVector& param) {CVector temp;temp.x = x + param.x;temp.y = y + param.y;return temp;}int main () {CVector foo (3,1);CVector bar (1,2);CVector result;result;result = foo + bar;cout <<<<<<<< < < ',' <<< result.y <<< < \n';return 0;}}.
Resultado de la ejecución: 4, 3
En caso de confusión sobre tantas apariencias de CVector, considere que algunas de ellas se refieren al nombre de la clase CVector (es decir, tipo) y otras son funciones con este nombre (es decir, fabricantes, que deben tener el mismo nombre que la clase. Por ejemplo:
CVector (int, int) : x(a), y(b) {} // CVector (constructor)CVector operator+ (const CVector&) function; // function returns CVector
El operador CVector class + function sustituye al operador addition (+) para este tipo. Una vez declarada, esta función puede ser llamada implícitamente usando el operador o explícitamente usando su nombre funcional:
c = a + b;c = a.operator+ (b);
Las dos expresiones son equivalentes.
Las sobrecargas del operador son sólo funciones regulares que pueden tener cualquier comportamiento; de hecho, no es necesario que la operación realizada por esta sobrecarga tenga relación con el significado matemático o habitual del operador, aunque esto es muy recomendable. Por ejemplo, una clase que sobrecarga al operador + para restar o al operador == para rellenar el objeto con ceros es perfectamente válida, aunque el uso de dicha clase puede ser difícil.
El parámetro esperado para una sobrecarga de la función de miembro para operaciones como el operador + es naturalmente el operando situado a la derecha del operador.
Esto es común a todos los operadores binarios (aquellos con un operando a su izquierda y otro a su derecha. Pero los operadores pueden adoptar diversas formas. Aquí tiene una tabla con un resumen de los parámetros necesarios para cada uno de los diferentes operadores que pueden ser sobrecargados (por favor, sustituya @ por el operador en cada caso):
ExpresiónOperadorFunción de miembroFunción de no miembro@a+ – * y ! ~ +++ -A::operator@()operator@(A)a@+++ -A::operator@(int)operator@(A,int)a@b+ – * / % ^ & | | | == != A::operador@(B)operador@(A,B)a@b= += -= -= *= /= %= ^= &= |= <>> []A::operador@(B)-a(b,c…<= >)()A::operador()(B,C….)-a-a->b->A:=>C<= >uando
a es un objeto de clase A, b es un objeto de clase B y c es un objeto de clase C.
TYPE es cualquier tipo (los operadores anulan la conversión a TYPE.
También lea El polimorfismo en C++Nota
que algunos operadores pueden ser sobrecargados en dos formas: como una función miembro o como una función no miembro: el primer caso fue usado en el ejemplo anterior para el operador +
.
Pero algunos operadores también pueden estar sobrecargados como funciones no miembros; en este caso, la función de operador toma como primer argumento un objeto de la clase apropiada.
#include <iostream>using namespace std;class CVector {public:int x,y;CVector () {}CVector (int a, int b) : x(a), y(b) {}};CVector operator+ (const CVector& lhs, const CVector& rhs) {CVector temp;temp;temp.
=>x<= >
= lhs.x + rhs.x;temp.y = lhs.y + rhs.y;return temp;}int main () {CVector foo (3,1);CVector bar (1,2);CVector result;result;result = foo + bar;cost <<<<<< ',' <<<< result.y < < ñ';return 0;}}.
Resultado de la ejecución: 4, 3
La palabra clave esta
La palabra clave representa un puntero al objeto cuya función de miembro se está ejecutando actualmente. Se utiliza en la función de miembro de una clase para referirse al propio objeto.
Uno de sus usos puede ser comprobar si un parámetro transmitido a una función miembro es el objeto mismo. Por ejemplo:
// ejemplo de esto#incluye <iostream>usando namespace std;class Dummy {public:bool isitme (Dummy& param);};bool Dummy::
=>i<= >
sitme (Dummy& param){si (¶m == this) return true;else return false;}int main () {Dummy a;Dummy* b = &a;if ( b->isitme(a) <<< "yes, &a is bgn";return 0;};}
Resultado de la ejecución: sí, &a es b
También se utiliza frecuentemente en el operador = funciones miembro que devuelven objetos por referencia. Después de los ejemplos sobre el vector cartesiano vistos arriba, su operador = función podría haber sido definida como:
CVector& CVector::operator= (const CVector& param){x=param.x;y=param.y;return *this;}
De hecho, esta función es muy similar al código que el compilador genera implícitamente para esta clase para el operador =.
Miembros estáticos
Una clase puede contener miembros, datos o funciones estáticas.
Un miembro de datos estáticos de una clase también se denomina «variable de clase», porque sólo hay una variable común para todos los objetos de la misma clase que comparten el mismo valor: es decir, su valor no es diferente de un objeto de la misma clase.
Por ejemplo, se puede utilizar para una variable de una clase que puede contener un contador con el número de objetos de esa clase actualmente asignados, como en el ejemplo siguiente:
// Los miembros estáticos en las clases#incluyen <iostream>usando namespace std;class Dummy {public:static int n;Dummy () {n++; };};int Dummy::n=0;int main () {Dummy a;Dummy b[5];cout <<<< a.
=>n<= >
<<<<<'<'n';Dummy * c = nuevo Dummy;cost <<<<<<<'n <<'delete c;return 0;}}
=>
<= >
De hecho, los miembros estáticos tienen las mismas propiedades que las variables no miembros, pero se benefician de un alcance de clase.
=>
Por esta razón, y para evitar que sean declarados varias veces, no pueden ser inicializados directamente en la clase, sino que deben ser inicializados en algún lugar fuera de la clase. Como en el ejemplo anterior:
int Dummy ::: n = 0;
Como es un valor de variable común a todos los objetos de la misma clase, puede ser llamado miembro de cualquier objeto de esa clase o incluso directamente por el nombre de la clase (por supuesto, esto sólo es válido para los miembros estáticos):
cost <<<<< a.n;cost <<<< Dummy :: n;
Estas dos llamadas anteriores se refieren a la misma variable: la variable estática n en la clase Dummy compartida por todos los objetos de esta clase.
De nuevo, esto parece una variable no miembro, pero con un nombre que requiere acceso como miembro de una clase (u objeto.
Las clases también pueden tener funciones de miembro estáticas. Éstos representan lo mismo: miembros de una clase que son comunes a todos los objetos de esa clase, actuando exactamente como funciones no miembros pero accesibles como miembros de la clase. Como se asemejan a funciones no miembros, no pueden acceder a los miembros no estáticos de la clase (ni a las variables de los miembros ni a las funciones de los miembros. Tampoco pueden usar esta palabra clave.
Funciones constantes de los miembros
Cuando un objeto de una clase se clasifica como un objeto constante, se denomina objeto constante:
const MyClass myobject;
El acceso a sus miembros de datos fuera de la clase está limitado a sólo lectura, como si todos sus miembros de datos fueran constantes para los que acceden desde fuera de la clase. Tenga en cuenta, sin embargo, que el fabricante siempre es llamado y se le permite inicializar y modificar estos datos miembros:
#include <iostream>using namespace std;class MaClasse {public:int x;MaClasse(int val) : x(val) {}int get() {return x;}};int main() {const MaClasse foo(10);// foo.x = 20; // no es válido: x no puede modificarse <<< foo.x << < < `n'; // ok: data member x can be readreturn 0;}.
Resultado de la ejecución: 10
También lea Operadores en C++++Las
funciones de miembro de un objeto const sólo pueden ser llamadas si ellas mismas son especificadas como miembros de la const; En el ejemplo anterior, get member (que no está especificado como const) no puede ser llamado desde foo. Para especificar que un miembro es un miembro de la const, la palabra clave const debe seguir la función de prototipo, después del paréntesis de cierre para sus parámetros:
int get () const {retorno x;}
Tenga en cuenta que la const se puede utilizar para calificar el tipo devuelto por una función de miembro. Esto no es lo mismo que el que especifica un miembro como una const, ambos son independientes y están ubicados en diferentes lugares en el prototipo de la función:
int get () const {return x;} // member function constconst int & get () {return x;} // member function returning a constant &const int & get () const {return x;} // member function returning a const &const int & get () const {return x;} // member function returning a const &const
Las funciones de miembro especificadas como constantes no pueden cambiar los miembros de datos no estáticos o llamar a otras funciones de miembro no constantes. los miembros constantes no deben cambiar el estado de un objeto.
Los objetos Const se limitan a acceder sólo a las funciones de miembro marcadas como const, pero los objetos no-const no están restringidos y por lo tanto pueden acceder tanto a las funciones de miembro const como a las de miembro no-const.
Puedes pensar que de todos modos raramente declararás objetos const, y así marcarás a todos los miembros que no modifiquen el objeto como una const no vale la pena, pero los objetos const son en realidad muy comunes. La mayoría de las funciones que toman clases como parámetros las toman realmente por referencia const, y por lo tanto, estas funciones sólo pueden acceder a sus miembros const:
// Const objects#include <iostream>using namespace std;class MeClasse {int x;public:MaClasse(int val) : x(val) {}const int& get() const {return x;}};void print (const MaClasse& arg) {cout <<<<< arg.
get() <<<<<<<<‘\N’n’;}int main() {MaClasse foo (10);print(foo);return 0;}
Resultado de la ejecución: 10
Si en este ejemplo get no se especifica como miembro de la const, la llamada a arg.get () en la función de impresión no sería posible, ya que los objetos const sólo tienen acceso a las funciones de miembro de la const.
Las funciones de miembro pueden sobrecargarse en su constancia: una clase puede tener dos funciones de miembro con firmas idénticas, excepto que una es const y la otra no: en este caso, la versión const se llama sólo cuando el propio objeto es const, y la versión no-const se llama cuando el propio objeto es no-const.
#include <iostream>using namespace std;class MaClasse {int x;public:MaClasse(int val) : x(val) {}const int& get() const {return x;}int& get() {return x;}int main() {MaClasse foo (10);const MaClasse bar (20);foo.get() = 15; // ok: get() devuelve int&// bar.get() = 25; // no válido: get() devuelve const int&cout <<<<<< foo.get() <<<'cout <<<<<<<'cout';bar.get() <<<'\n';return 0;}
Otros consejos interesantes:
- 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….
- Las clases en C++ 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……
- 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……
- 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……
- 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……