Clases y objetos [4] miembros estáticos, objetos const, amigos

introducción

A través de los tres artículos anteriores, creo que todos tienen una comprensión básica de las clases y los objetos.
Clase y objeto 1 (conocimiento inicial)
clase y objeto 2 (función miembro por defecto)
clase y objeto 3 (lista de inicialización)
, pero no es difícil encontrar algunas lagunas y muchos puntos que se pueden mejorar en algunos de los ejemplos anteriores:

Por ejemplo, a veces necesitamos algunas variables globales para administrar las propiedades de muchos objetos, pero la creación de variables globales afecta la encapsulación de clases;
sabemos que el tipo de este puntero es T* constque a veces necesitamos asignar valores a otros objetos, como const- objetos de clase modificados, durante operaciones como la impresión. La transferencia de este puntero causará el problema de la amplificación de privilegios;
a veces necesitamos acceder a miembros privados fuera de la clase, lo que obviamente no está permitido en circunstancias normales.

En este artículo, continuaremos complementando el conocimiento de clases y objetos:

miembro estático

Sabemos que los objetos de clase se almacenan en el área de la pila, podemos calcular el tamaño de una clase simple:

class A
{
    
    
private:
	char _a;
	int _b;
	int _c;
};
int main()
{
    
    
	A a;
	cout << sizeof(a) << endl;
	return 0;
}

inserte la descripción de la imagen aquí
De acuerdo con la alineación de la memoria, no es difícil calcular que el tamaño de esta clase A es de 12 bytes.
Estas tres variables miembro _a, _b y _c son atributos que pertenecen a un objeto y se definen cuando se instancia la clase. Por supuesto, no se puede acceder a él fuera de la clase, ni tiene propiedades globales.

variable miembro estática

Pero la variable estática se almacena en el área estática, aunque está encapsulada en la clase (solo declarada en el tipo de clase), no pertenece a un objeto.
Para un tipo de clase, el miembro estático solo se declara en la clase y se define fuera de la clase. La palabra clave estática no se agrega al definir, y no ocupa el espacio de este tipo de objeto :

class A
{
    
    
private:
	char _a;
	int _b;
	int _c;
	static int a;
};
int A::a = 10;

int main()
{
    
    
	A a;
	cout << sizeof(a) << endl;
	return 0;
}

inserte la descripción de la imagen aquí
Esta variable miembro estática es similar a una variable global encapsulada en una clase. Aunque no se puede acceder a ella fuera de la clase, puede desempeñar un papel similar al de una variable global en la clase para reflejar las propiedades de muchos objetos de este tipo de clase.

función miembro estática

Una función miembro decorada con estática se denomina función miembro estática:

Una función miembro estática se diferencia de una función miembro general en que no tiene un puntero this implícito para pasar parámetros, por lo que no puede acceder a variables miembro privadas. Pero puede acceder a las variables miembro estáticas normalmente :

class A
{
    
    
public:
	static void fun()
	{
    
    
		//_a++; 错误代码:非静态成员引用必须与特定对象相对
		cout << a++ << endl;
	}
private:
	char _a;
	int _b;
	static int a;
};
int A::a = 10;

Al acceder a una función miembro estática, puede 对象名.函数调用acceder a ella o 类类型名::函数调usarla :

class A
{
    
    
public:
	static void fun()
	{
    
    
		//_a++; 错误代码:非静态成员引用必须与特定对象相对
		cout << a++ << endl;
	}
private:
	char _a;
	int _b;
	static int a;
};
int A::a = 10;

int main()
{
    
    
	A a;
	a.fun();
	A::fun();
	return 0;
}

inserte la descripción de la imagen aquí
Como se mencionó anteriormente, llamar a una función miembro en realidad es llamar a la función miembro en lugar de a un objeto. Aquí hay una premisa, es decir, cuando se llama a una función miembro, debe haber un cuerpo de objeto que ya se haya definido, por lo que, por supuesto, es posible que las funciones miembro generales pasen implícitamente este puntero para acceder a variables miembro privadas;

Pero para la función de miembro estático, cuando llamamos a la función de miembro estático, no existe la premisa de que el objeto haya sido instanciado (se puede llamar por el nombre del tipo). Por lo tanto, no puede pasar implícitamente este parámetro y, naturalmente, no puede acceder a las variables de miembros privados. Aunque la variable miembro estática se declara en la clase, no se define con la creación de instancias, por lo que naturalmente se puede acceder a ella en la función después de definirla externamente.

objeto constante

En el pasado, simplemente implementamos algunas funciones miembro, como la función de agregar fecha a la clase de fecha y la función de impresión. Para objetos de clase normales, por supuesto, es adecuado:

class Date
{
    
    
public:
	Date(int year = 2023, int month = 2, int day = 10)
		: _year(year)
		, _month(month)
		, _day(day)
	{
    
    }
	int GetMonthDay(int year, int month);
	Date& AddDate(int day);
	void print();
private:
	int _year;
	int _month;
	int _day;
};
void Date::print()
{
    
    
	cout << _year << " " << _month << " " << _day << endl;
}

int main()
{
    
    
	Date d1;
	d1.print();
	return 0;
}

inserte la descripción de la imagen aquí
Pero cuando creamos una instancia de un objeto de clase de tipo Fecha const, este objeto const no puede llamar a la función de impresión para imprimir la fecha:

int main()
{
    
    
	Date d1;
	d1.print();
	const Date d2;
	//d2.print();  错误代码:不能将“this”指针从“const Date”转换为“Date&“
	return 0;
}

Debido a que el tipo de este puntero es Date* const, cuando se pasa un objeto const a este puntero que se puede cambiar, se producirá el problema de la amplificación de privilegios, que por supuesto no está permitido.
Ante este tipo de problema, necesitamos agregar modificación const al puntero this para que su tipo sea const Date* const. Pero el puntero this se pasa implícitamente como parámetro, por lo que no podemos pasar un puntero const de la forma anterior.

C++ proporciona una forma de modificar este puntero con const, es decir, agregar const después de la lista de parámetros :

class Date
{
    
    
public:
	Date(int year = 2023, int month = 2, int day = 10)
		: _year(year)
		, _month(month)
		, _day(day)
	{
    
    }
	int GetMonthDay(int year, int month);
	Date& AddDate(int day);
	void print() const;
private:
	int _year;
	int _month;
	int _day;
};
void Date::print() const
{
    
    
	cout << _year << " " << _month << " " << _day << endl;
}

int main()
{
    
    
	Date d1;
	d1.print();  //权限缩小
	const Date d2(2023, 5, 19);
	d2.print();  //权限平移
	return 0;
}

inserte la descripción de la imagen aquí
De esta forma, se puede realizar el parámetro this del objeto const.

tomomoto

A veces necesitamos acceder a funciones de miembros privados fuera de la clase. Los amigos brindan una forma de romper la encapsulación y brindan comodidad .
Sin embargo, el uso excesivo de amigos definitivamente destruirá el paquete, ¡así que no es adecuado usar más!

funcion amigo

La función amigo puede usar la palabra clave amigo para hacer una función declarada externamente como una función amigo de la clase . De esta forma, esta función de amigo puede acceder a los miembros privados de la clase:

class A
{
    
    
	friend void func1(A&);
private:
	int _a;
};
void func1(A& a)
{
    
    
	cout << a._a << endl;
}

hay que tener en cuenta es:

  1. Las funciones amigas pueden acceder a los miembros privados y protegidos de la clase, pero no a las funciones miembro de la clase (no hay un puntero this para pasar parámetros) ;
  2. Las funciones de amigo no se pueden modificar con const;
  3. Una función puede ser una función amiga de múltiples clases;
  4. El principio de llamar a una función amiga es el mismo que el de una función normal ;
  5. Las funciones amigas se pueden declarar en cualquier parte de la definición de la clase , no restringidas por calificadores de acceso a la clase;
  6. En cualquier lugar dentro de la clase , agregue el modificador amigo para declarar la función externa (el amigo está antes del valor de retorno de la declaración de la función).

(La aplicación de una función de amigo se presentará en el próximo artículo)

clase amiga

Al igual que una función amiga, la palabra clave amigo también puede declarar una clase externa como clase amiga de una clase determinada. Todas las funciones miembro de una clase amiga pueden ser funciones amigas de otra clase y pueden acceder a las funciones de otra clase. miembros

class A
{
    
    
	friend void func1(A&);
	friend class B;
private:
	int _a;
};
void func1(A& a)
{
    
    
	cout << a._a << endl;
}

class B
{
    
    
public:
	void func1(A& a)
	{
    
    
		cout << a._a << endl;
	}
private:
	int _b;
};

hay que tener en cuenta es:

  1. La relación de amistad no es intercambiable :
    por ejemplo, la clase A y la clase B mencionadas anteriormente declaran la clase B como su clase amiga en la clase A, luego puede acceder directamente a las variables miembro privadas de la clase A en la clase B, pero desea acceder a las variables miembro privadas de la clase A en la clase A El acceso a las variables miembro privadas de la clase B no funciona.
  2. La relación de amistad no se puede transmitir :
    si C es amigo de B y B es amigo de A, no se puede decir que C es amigo de A.
  3. La relación de amistad no se puede heredar : la presentaremos en detalle más adelante.

Resumir

En este punto, se ha introducido todo el conocimiento básico sobre clases y objetos,
a continuación, usaremos el conocimiento previo para implementar una clase de fecha como ejemplo. Creo que todos tendrán una mejor comprensión de las clases y los objetos, bienvenidos a seguir prestando atención.

Si cree que no presenté una parte determinada claramente o que hay un problema con una parte determinada, puede plantearlo en el área de comentarios.

Si este artículo es útil para usted, espero que se conecte con un solo clic.

Espero progresar junto con usted.

Supongo que te gusta

Origin blog.csdn.net/weixin_73450183/article/details/130773832
Recomendado
Clasificación