Tabla de contenido
1. Comprensión preliminar de orientado a procesos y orientado a objetos.
4. Calificadores de acceso a clases y encapsulación.
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.
- Pila de implementación del lenguaje c:
#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);//获取栈元素个数
#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
Consejo rápido: el nombre de la clase también representa el tipo. ejemplo:
- 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:
- 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 .
- 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 .
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 objeto contiene varios miembros de la clase.
- 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:
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;
}
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 .
- 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.
// 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
- 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.