(c++) Clases y objetos Parte 1

Tabla de contenido

1. Comprensión preliminar de orientado a procesos y orientado a objetos.

2. Introducción de clases

3. Definición de clase

4. Calificadores de acceso a clases y encapsulación.

5. Alcance de la clase

6. Creación de instancias de clases.

7. Cálculo del tamaño del objeto de clase.

8. Este puntero de función miembro de clase.


  • El lenguaje C está orientado a procesos , centrándose en el proceso , analizando los pasos para resolver el problema y resolviendo el problema paso a paso mediante llamadas a funciones.
  • C ++ se basa en la orientación a objetos , centrándose en los objetos , dividiendo una cosa en diferentes objetos y confiando en la interacción entre objetos para completar. ¿Por qué C++ se basa en un lenguaje orientado a objetos? Porque C++ no sólo puede estar orientado a objetos, sino también a procesos, lo que se considera un híbrido. En segundo lugar, C++ debe ser compatible con el lenguaje C.
Pocos conocimientos: Java es un lenguaje puramente orientado a objetos.

         Solo se pueden definir variables en la estructura del lenguaje C. En C++ , no solo se pueden definir variables sino también funciones en la estructura. Por ejemplo: en una pila implementada en lenguaje C , solo se pueden definir variables en la estructura ; ahora implementada en C++ , encontrará que las funciones también se pueden definir en la estructura .
  • Pila de implementación del lenguaje c:
declaración:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDateType;

typedef struct Stack
{
	STDateType* arr;
	int top;
	int capacity;
}ST;

void StackInit(ST* ps);//初始化

void StackDestory(ST* ps);//销毁

void StackPush(ST* ps, STDateType x);//压栈

void StackPop(ST* ps);//出栈

STDateType StackTop(ST* ps);//取栈顶元素

bool StackEmpty(ST* ps);//判断栈是否为空

int StackSize(ST* ps);//获取栈元素个数

lograr:
#include"Stack.h"

void StackInit(ST* ps)//初始化
{
	assert(ps);
	ps->arr = NULL;
	ps->top = 0;
	ps->capacity = 0;

}

void StackDestory(ST* ps)//销毁
{
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

void StackPush(ST* ps, STDateType x)//压栈
{
	assert(ps);
	if (ps->top == ps->capacity) //扩容
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDateType* tmp = (STDateType*)realloc(ps->arr, sizeof(STDateType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			exit(-1);
		}

		ps->arr = tmp;
		ps->capacity = newCapacity;
	}

	ps->arr[ps->top] = x;//尾插
	ps->top++;
}

void StackPop(ST* ps)//出栈
{
	assert(ps);
	assert(!StackEmpty(ps));
	ps->top--;
}

STDateType StackTop(ST* ps)//取栈顶元素
{
	assert(ps);
	assert(!StackEmpty(ps));//ps->top != 0
	
	return ps->arr[ps->top - 1];
}

bool StackEmpty(ST* ps)//判断栈是否为空
{
	assert(ps);

	return ps->top == 0;

}

int StackSize(ST* ps)//获取栈元素个数
{
	assert(ps);

	return ps->top;
}

  • Pila de implementación de C++:
typedef int DataType;
struct Stack
{
   void Init(size_t capacity)
   {
      _array = (DataType*)malloc(sizeof(DataType) * capacity);
      if (nullptr == _array)
      {
         perror("malloc申请空间失败");
          return;
      }
      _capacity = capacity;
      _size = 0;
    }

    void Push(const DataType& data)
    {
        // 扩容
        _array[_size] = data;
        ++_size;
    }

    DataType Top()
    {
        return _array[_size - 1];
     }

     void Destroy()
     {
         if (_array)
         {
             free(_array);
             _array = nullptr;
             _capacity = 0;
             _size = 0;
         }
     }

     DataType* _array;
     size_t _capacity;
     size_t _size;
};

Poco conocimiento: se prefiere reemplazar la definición de la estructura anterior por clase en C++


class className
{
    // 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号
  • clase es la palabra clave que define la clase , ClassName es el nombre de la clase y {} es el cuerpo principal de la clase. Tenga en cuenta que el punto y coma no se puede omitir al final de la definición de clase.

  • El contenido del cuerpo de la clase se llama miembros de la clase: las variables de la clase se llaman atributos o variables miembro de la clase ; las funciones de la clase se llaman métodos o funciones miembro de la clase
Dos formas de definir clases:
1. La declaración y la definición se colocan en el cuerpo de la clase. Nota: si la función miembro está definida en la clase , el compilador puede tratarla como una función en línea .

2. La declaración de clase se coloca en el archivo .h y la definición de la función miembro se coloca en el archivo .cpp . Nota: el nombre de la clase debe agregarse antes del nombre de la función miembro:

Consejo rápido: el nombre de la clase también representa el tipo. ejemplo:


4.1 Calificadores de acceso
La forma en que C ++ logra la encapsulación: use clases para combinar las propiedades y métodos del objeto para hacerlo más perfecto.
Proporcionar selectivamente su interfaz a usuarios externos .

 

[Descripción del calificador de acceso]
  • Se puede acceder directamente a los miembros modificados por público fuera de la clase

  • No se puede acceder directamente a los miembros modificados protegidos y privados fuera de la clase ( protegidos y privados son similares aquí )

  • El alcance del acceso comienza cuando ocurre este calificador de acceso y termina cuando ocurre el siguiente calificador de acceso.

  • Si no hay ningún calificador de acceso posterior, el alcance termina en }, que es el final de la clase.

  • Los derechos de acceso predeterminados de la clase son privados y la estructura es pública ( porque la estructura debe ser compatible con C)

Nota: Los calificadores de acceso solo son útiles en el momento de la compilación. Cuando los datos se asignan a la memoria, no hay diferencia en los calificadores de acceso.

consejos:

¿Cuál es la diferencia entre estructura y clase en C++ ?
  •          C ++ debe ser compatible con el lenguaje C , por lo que la estructura en C ++ se puede usar como estructura. Además, struct en C++ también se puede utilizar para definir clases. Es lo mismo que una clase que define una clase, la diferencia es que el permiso de acceso predeterminado de una clase definida por struct es público y el permiso de acceso predeterminado de una clase definida por clase es privado .
Las tres características principales de la orientación a objetos : encapsulación , herencia y polimorfismo .
En la etapa de clases y objetos, estudiamos principalmente las características de encapsulación de las clases, entonces, ¿qué es la encapsulación?
  • Encapsulación: combine orgánicamente datos y métodos de operación de datos, oculte las propiedades y los detalles de implementación del objeto y solo exponga la interfaz para interactuar con el objeto.
  • La encapsulación es esencialmente una gestión que facilita a los usuarios el uso de clases . Por ejemplo: para un dispositivo complejo como una computadora, lo único que se proporciona al usuario es el botón de encendido/apagado, la entrada del teclado, el monitor, el conector USB , etc., lo que le permite interactuar con la computadora y completar las tareas diarias . Pero, de hecho, el verdadero trabajo de la computadora son algunos componentes de hardware como la CPU , la tarjeta gráfica y la memoria.
  • Para los usuarios de computadoras, no hay necesidad de preocuparse por los componentes centrales internos, como cómo están dispuestos los circuitos en la placa base, cómo está diseñada internamente la CPU , etc. Los usuarios solo necesitan saber cómo encender la computadora y cómo Interactuar con el ordenador a través del teclado y el ratón . Por lo tanto, cuando los fabricantes yde computadoras para que los usuarios puedan interactuar con la computadora .
  • Para implementar la encapsulación en el lenguaje C ++ , los datos y los métodos para operar datos se pueden combinar orgánicamente a través de clases, y los derechos de acceso se pueden usar para ocultar los detalles de implementación interna de los objetos y controlar qué métodos se pueden usar directamente fuera de la clase .

Una clase define un nuevo ámbito y todos los miembros de la clase están dentro del ámbito de la clase . Al definir miembros fuera de una clase, debe utilizar el operador de alcance :: para indicar a qué ámbito de clase pertenece el miembro.
class Person
{
public:
     void PrintPersonInfo();
private:
  char _name[20];
  char _gender[3];
  int  _age;
};

// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
   cout << _name << " "<< _gender << " " << _age << endl;
}


El proceso de creación de un objeto a partir de un tipo de clase se llama creación de instancias de la clase.
1. Una clase describe un objeto . Es algo así como un modelo . Limita los miembros de la clase. Definir una clase no asigna espacio de memoria real para almacenarla;
2. Una clase puede crear instancias de varios objetos, que ocupan espacio físico real y almacenan variables miembro de la clase .
3. Haz una analogía. Crear instancias de objetos de una clase es como usar dibujos de diseño arquitectónico para construir una casa en la realidad. Una clase es como un dibujo de diseño . Solo diseña lo que se necesita, pero no hay un edificio físico. De manera similar, una clase es solo un diseño que es instanciados Los objetos pueden realmente almacenar datos y ocupar espacio físico.


     7.1 Adivinar el método de almacenamiento de objetos de clase
  • El objeto contiene varios miembros de la clase.

Defecto: Las variables miembro en cada objeto son diferentes, pero se llama a la misma función, si se almacena de esta manera, cuando uno
Cuando una clase crea varios objetos, se guardará una copia del código en cada objeto y el mismo código se guarda varias veces, lo que desperdicia espacio.

  • Solo se guarda una copia del código y la dirección donde se almacena el código se guarda en el objeto.

  • Solo se guardan las variables miembro y las funciones miembro se almacenan en la sección de código público.
                

 

 Los compiladores generalmente adoptan el tercer método de almacenamiento: probar

7.2 Tamaño de la clase

El tamaño de una clase es en realidad la suma de las " variables miembro " de la clase. Las funciones miembro no ingresan a la clase, por lo que no ocupan el tamaño del espacio de clase. Las variables miembro siguen reglas de alineación de memoria. Además, paga Atención al tamaño de las clases vacías. Las clases vacías son especiales. El compilador le da a la clase vacía un byte para identificar de forma única los objetos de esta clase.

 Respecto a la alineación de la memoria:

1. El primer miembro está en la dirección desplazada 0 de la estructura.
2. Otras variables miembro deben alinearse con direcciones que sean múltiplos enteros de un determinado número (número de alineación).
Nota: Número de alineación = el menor entre el número de alineación predeterminado del compilador y el tamaño del miembro.
El número predeterminado de alineaciones en VS es 8
3. El tamaño total de la estructura es: un múltiplo entero del número máximo de alineación (el mayor de todos los tipos de variables y el parámetro de alineación predeterminado más pequeño).
4. Si una estructura está anidada y la estructura anidada está alineada con un múltiplo entero de su propio número de alineación máximo, el tamaño total de la estructura es un número entero de todos los números de alineación máximos (incluido el número de alineación de las estructuras anidadas) veces.

También puede observar la alineación de la memoria de esta estructura .


class Date
{
public:
	void Init(int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}
	void Print()
	{
		cout << _year << "." << _month << "." << _day << endl;
	}

private:
	int _year;  //声明
	int _month;
	int _day;
};

int main()
{
	Date d1, d2;

	d1.Init(2023, 9, 1);
	d1.Print();

	d2.Init(2023, 9, 2);
	d2.Print();
	return 0;
}

Para la clase anterior, existe la siguiente pregunta:
Hay dos funciones miembro, Init e Print , en la clase Date . No hay distinción entre diferentes objetos en el cuerpo de la función. Entonces, cuando d1 llama a la función Init , ¿cómo sabe la función que debe establecer el objeto d1 en lugar del objeto d2 ?

C++ resuelve este problema introduciendo este puntero, es decir: el compilador de C++ agrega un parámetro de puntero oculto a cada " función miembro no estática " , permitiendo que el puntero apunte al objeto actual ( el objeto que llama a la función cuando la función se está ejecutando ) .Se accede a todas las operaciones sobre "variables miembro" a través de este puntero. Es solo que todas las operaciones son transparentes para el usuario, es decir, el usuario no necesita pasarlas, el compilador las completa automáticamente .

 Características de este puntero
  •  El tipo de este puntero: tipo de clase * const , es decir, en funciones miembro, a este puntero no se le puede asignar un valor.
  •  Sólo se puede utilizar dentro de una " función miembro "
  • Este puntero es esencialmente un parámetro formal de una " función miembro " . Cuando un objeto llama a una función miembro, la dirección del objeto se pasa como un parámetro real a este parámetro formal. Por lo tanto, este puntero no se almacena en el objeto .
  • Este puntero es el primer parámetro de puntero implícito de la " función miembro " . Generalmente, el compilador lo pasa a través del registro ecx y no es necesario que lo pase el usuario.
ejemplo:
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void Print()
	{
		cout << this << endl;
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();  
	return 0;
}

Respuesta: Se ejecuta normalmente porque la función está en el área de código público, aunque el puntero llama a esta función, el puntero no se descomprime.

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
		//cout << this->_a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->PrintA();   
	return 0;
}

Respuesta: El bloqueo de la ejecución se debe a un problema de puntero nulo y se desreferencia al puntero nulo

¿Dónde se almacena este puntero?
  • La ubicación de almacenamiento de esto es en el área de la pila, porque este puntero es un parámetro formal y los parámetros formales generalmente se almacenan en el área de la pila.
  • Pero este puntero también se puede optimizar: vs se coloca en un registro, por lo que la ubicación de almacenamiento específica depende del compilador.

Nota: El contenido conceptual proviene de Bit Technology.

Supongo que te gusta

Origin blog.csdn.net/m0_73969113/article/details/132476178
Recomendado
Clasificación