Serie C++: Programación básica

Registro de aprendizaje de programación básica de C++



prefacio

Enlace de video de aprendizaje: El ingenio del programador de Dark Horse | Tutorial de C++


1. Modelo de partición de memoria


2. Cita


3. Mejora de funciones


4. Clases y Objetos


4.1 Embalaje


4.2 Inicialización y limpieza de objetos


4.2.3 Cuándo llamar al constructor de copias

En C++, generalmente hay tres situaciones en las que se llama al constructor de copia:
usar un objeto ya creado para inicializar un nuevo objeto;
pasar valor al parámetro de función;
devolver un objeto local por valor;
ejemplo:

#include <iostream>
using namespace std;

class Person
{
    
    
public:
    //无参(默认)构造函数
    Person()
    {
    
    
        cout << "无参构造函数!" << endl;
    }
    //有参构造函数
    Person(int a)
    {
    
    
        age = a;
        cout << "有参构造函数!" << endl;
    }
    //拷贝构造函数
    Person(const Person &p)
    {
    
    
        age = p.age;
        cout << "拷贝构造函数!" << endl;
    }
    //析构函数
    ~Person()
    {
    
    
        cout << "析构函数!" << endl;
    }

public:
    int age;
};

void test01()
{
    
    
    Person p1(18);
    //如果不写拷贝构造,编译器会自动添加拷贝构造,并且做浅拷贝操作
    Person p2(p1);

    cout << "p2的年龄为: " << p2.age << endl;
}

void test02()
{
    
    
    //如果用户提供有参构造,编译器不会提供默认构造,会提供拷贝构造
    Person p1;     //此时如果用户自己没有提供默认构造,会出错
    Person p2(10); //用户提供的有参
    Person p3(p2); //此时如果用户没有提供拷贝构造,编译器会提供

    //如果用户提供拷贝构造,编译器不会提供其他构造函数
    Person p4;     //此时如果用户自己没有提供默认构造,会出错
    Person p5(10); //此时如果用户自己没有提供有参,会出错
    Person p6(p5); //用户自己提供拷贝构造
}

int main()
{
    
    

    // test01();
    test02();

    system("pause");

    return 0;
}
注意:以值传递的方式返回局部对象   此局部等于栈,会自动释放;

4.2.4 Reglas de llamada de constructores

#include <iostream>
using namespace std;

class Person
{
    
    
public:
    //无参(默认)构造函数
    Person()
    {
    
    
        cout << "无参构造函数!" << endl;
    }
    //有参构造函数
    Person(int age, int height)
    {
    
    

        cout << "有参构造函数!" << endl;

        m_age = age;
        m_height = new int(height);
    }
    //拷贝构造函数
    Person(const Person &p)
    {
    
    
        cout << "拷贝构造函数!" << endl;
        //如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题
        m_age = p.m_age;
        // m_height = p.m_height; //编译器默认的拷贝函数
        //用深拷贝解决浅拷贝重复释放堆区的问题
        m_height = new int(*p.m_height);
    }

    //析构函数
    ~Person()
    {
    
    
        cout << "析构函数!" << endl;
        if (m_height != NULL)
        {
    
    
            delete m_height;
            m_height = NULL;//防止野指针出现
        }
    }

public:
    int m_age;
    int *m_height;
};

void test01()
{
    
    
    Person p1(18, 180);

    Person p2(p1);

    cout << "p1的年龄: " << p1.m_age << " 身高: " << *p1.m_height << endl;

    cout << "p2的年龄: " << p2.m_age << " 身高: " << *p2.m_height << endl;
}

int main()
{
    
    

    test01();

    system("pause");

    return 0;
}

4.3 Modelo de objetos C++ y este puntero


4.3.1 Las variables miembro y las funciones miembro se almacenan por separado

En C++, las variables miembro y las funciones miembro de una clase se almacenan por separado sin interferir entre sí, y solo las variables miembro no estáticas de una clase pertenecen al objeto de clase; ejemplo de código
:

#include <iostream>
using namespace std;
//成员变量 和 成员函数 分开存储的 互不干扰
class Person
{
    
    
public:
	int m_A;		//非静态成员变量  属于类的对象上
	static int m_B; //静态成员变量  不属于类对象上

	void func() //非静态成员函数 不属于类对象上
	{
    
    
	}
	static void func2(){
    
    } //非静态成员函数 不属于类对象上
};
int Person::m_B = 100;

void test01()
{
    
    
	Person p;
	//空对象占用内存空间为:0 4 1    答:1
	// C++编译器会给每一个空对象也分配一个字节的空间,为了区分空对象占内存的位置
	//每个空对象也应该有一个独一无二的内存地址
	cout << "size of p:" << sizeof(p) << endl;
}
void test02()
{
    
    
	//只要不属于空对象,定义是啥类型就是几个字节
	Person p;
	cout << "size of p:" << sizeof(p) << endl;
}

int main()
{
    
    
	// test01();
	test02();
	system("pause");
	return 0;
}

Nota: si el interior de una clase está vacío, el byte que ocupa en ese momento no es 0, sino que debería ser 1, porque el compilador de C++ asignará automáticamente un byte de almacenamiento al objeto vacío para distinguir la ubicación de almacenamiento; error:
en Después de definir la variable miembro estática, cuando quiero generarla, m_Bdescubrí que no se puede llamar a la clase;
la razón: después de escribir, me indica que no hay derecho de acceso. Recordé que cuando creé una clase vacía basada en el video al principio, no le agregué atributos públicos. Después de agregarlo, puedo publicusar dos formas de acceder a él;

4.3.2 El concepto de este puntero

A través de 4.3.1, sabemos que las variables miembro y las funciones miembro se almacenan por separado en C++, y cada función miembro no estática solo generará una instancia de función, lo que significa que varios objetos del mismo tipo compartirán una pieza de código.
Entonces, la pregunta es: ¿cómo distingue este código qué objeto se llama a sí mismo?
C++ resuelve los problemas anteriores proporcionando un puntero de objeto especial, el puntero this. El puntero this apunta al objeto al que pertenece la función miembro llamada, y el puntero this es un puntero implícito en cada función miembro no estática. No es necesario definirlo, se puede utilizar directamente.
El propósito del puntero this:
* Cuando el parámetro formal y la variable miembro tienen el mismo nombre, el puntero this se puede usar para distinguirlo
En la función miembro no estática de la clase para devolver el objeto en sí, puede usar return este

ejemplo de Código:

#include <iostream>
using namespace std;

class Person
{
    
    
private:
	/* data */
public:
	Person(int age)
	{
    
    
		// this指针,指向所调用的成员函数变量,所属的对象 防止重名
		this->age = age;
	}

	Person &Personaddage(Person &p) //如果不带引用,则变为上几节学的拷贝函数,将会创建一个新的存储空间赋值
	{
    
    
		this->age += this->age;
		return *this; //表示本体*this
	}

	int age; //演示出现重名现象,正常可以用下面形式定义成员变量
			 // int m_Age;
};
// 1、解决名称冲突
void test01()
{
    
    
	Person p1(18);
	cout << "p1的年龄是:" << p1.age << endl;
}

// 2、返回对象本身用*this
void test02()
{
    
    
	Person p1(10);
	Person p2(10);
	//链式编程思想   与cout类似,可以无限堆加
	p2.Personaddage(p1).Personaddage(p1);

	cout << "p2的年龄是:" << p2.age << endl;
}

int main()
{
    
    

	test01();
	test02();

	system("pause");
	return 0;
}

Nota: Al devolverse a sí mismo, debe prestar atención al método de uso de la referencia.Si se devuelve por valor, se creará un nuevo objeto, que se convierte en una función de copia;

4.3.3 Función miembro de acceso de puntero nulo

Los punteros nulos en C ++ también pueden llamar a funciones miembro, pero también presten atención a si se usa este puntero

Si se usa este puntero, debe evaluarse para garantizar la solidez del código.

#include <iostream>
using namespace std;

//空指针访问成员函数

class Person
{
    
    
private:
	/* data */
public:
	void showPersonName()
	{
    
    
		cout << "this is class name" << endl;
	}
	void ShowPersonAge()
	{
    
    
		// cout << "age=" <<m_Age << endl;
		//一般默认的this->m_Age  此时指针地址若是空,对于一个空的类储存单元访问其m_Age属性  属于无中生有
		//可以加
		if (this == NULL)
		{
    
    
			return;
		}
		cout << "age=" << this->m_Age << endl;
	}
	int m_Age;
};
void test01()
{
    
    
	Person *p = NULL;
	//空指针,可以调用成员函数
	p->ShowPersonAge();
	//
	p->showPersonName();
}
int main()
{
    
    
	test01();
	system("pause");
	return 0;
}

4.3.4 función miembro modificada const

Función constante:

Después de agregar const después de la función miembro, llamamos a esta función una función constante. El
atributo miembro no se puede modificar en la función constante. Después de agregar la palabra clave mutable a la declaración del atributo miembro, el objeto constante
aún se puede modificar en la función constante. :

Agregar const antes de declarar un objeto significa que el objeto es un objeto constante.
Un objeto constante solo puede llamar a una función constante.

#include <iostream>
using namespace std;

// const修饰的成员函数、成员变量
// 常函数
class Person
{
    
    
private:
public:
	// this指针的本质是一个指针常量,指针的指向是不可以修改的  但是指针指向的内存保存的数据可以修改
	// 只有一个this->m_A时等于Person * const this 如果想让指针指向的值也不可以修改,需要声明常函数  -----> const Person * const this;
	// ()后面的const相当于const Person * const this 第一个const  在成员函数后面加上const 相当于修饰this指针的指向,让指针指向的值也不可以修改
	void showPerson() const
	{
    
    
		this->m_B = 100;
		// this->m_A = 100;
		// this = NULL; //指针不能修改指针的指向   Person * const this
	}
	void func()
	{
    
    
	}

	Person()
	{
    
    
	}

	int m_A;
	mutable int m_B; //特殊变量,在const修饰的常函数之中也可也修改值的变量  加关键字 mutable
};

void test01()
{
    
    
	Person p;
	p.showPerson();
}
//常对象
void test02()
{
    
    
	const Person p; //在对象前面加个常 变成常对象  创建常对象时 应该在类里创建构造函数否则会报错
	// p.m_A = 100;//常对象不可以修改
	p.m_B = 100;	// m_B是特殊值,在常对象下可以修改
	p.showPerson(); //常对象只能调用常函数
					// p.func();//不兼容的类型限定符
}
int main()
{
    
    
	test01();
	test02();
	system("pause");
	return 0;
}

Nota: este puntero en cada función miembro;
la constante de puntero esencial de este puntero no se puede modificar, pero el valor señalado se puede modificar

4.4 Tomomoto

En la vida, su hogar tiene una sala de estar (Pública) y un dormitorio (Privado)

Todos los invitados en la sala de estar pueden ingresar, pero su habitación es privada, lo que significa que solo usted puede ingresar

Pero también puedes dejar entrar a tus buenas amigas y amigos homosexuales.

En el programa, algunas funciones especiales o clases fuera de la clase también desean acceder a algunos atributos privados, por lo que debe usar la tecnología de amigos.

El propósito de un amigo es permitir que una función o clase acceda a miembros privados de otra clase.

La palabra clave del amigo es amigo.

Tres realizaciones de amigos

  • Funciones globales como amigos
  • clase como amigo
  • función de miembro como amigo

4.4.1 Funciones globales como amigos

#include <iostream>
using namespace std;
//全局函数做友元

//建筑物
class Building
{
    
    
	// goodGay是Building的友元,因此可以访问其私有成员
	friend void goodGay(Building *building);

public:
	Building()
	{
    
    
		m_BedRoom = "卧室";
		m_SettingRoom = "客厅";
	}

private:
	string m_BedRoom;

public:
	string m_SettingRoom;
};
//创建一个全局函数
void goodGay(Building *building) //指针应该传一个地址
{
    
    

	cout << "好基友全局函数正在访问:" << building->m_SettingRoom << endl;
	cout << "好基友全局函数正在访问:" << building->m_BedRoom << endl;
}
void test01()
{
    
    
	Building building;
	goodGay(&building);
}

void test02()
{
    
    
}

int main()
{
    
    
	test01();
	test02();
	system("pause");
	return 0;
}

4.4.2 Clases como amigos

#include <iostream>
using namespace std;
//类做友元
class Building; //声明一下

class goodGay
{
    
    
private:
public:
	goodGay();
	void vsisit();
	Building *building;
};

//建筑物
class Building
{
    
    
	//告诉编译器 goodGay类是Building类的友元   前者可以访问后者的私有内容
	friend class goodGay;

public:
	Building();

private:
	string m_BedRoom;

public:
	string m_SettingRoom;
};
Building::Building()
{
    
    
	this->m_BedRoom = "卧室";
	this->m_SettingRoom = "客厅";
}
goodGay::goodGay()
{
    
    
	building = new Building; //   注意-------------------类里使用指针一定要分配一个新的内存
}
void goodGay::vsisit()
{
    
    
	cout << "好基友全局函数正在访问:" << building->m_SettingRoom << endl;
	cout << "好基友全局函数正在访问:" << building->m_BedRoom << endl;
}

void test01()
{
    
    
	goodGay gg;
	gg.vsisit();
}

void test02()
{
    
    
}

int main()
{
    
    
	test01();
	test02();
	system("pause");
	return 0;
}

Aviso:类内使用指针一定要在构造函数中用new分配一个新的内存

4.4.3 Los miembros funcionan como amigos

#include <iostream>
using namespace std;
//成员函数做友元
class Building;
class goodGay
{
    
    
private:
	/* data */
public:
	goodGay();
	void visit01(); //让visit01函数可以访问Building中的私有成员
	void visit02(); //让visit02函数不可以访问Building中的私有成员
	Building *building;
};

//指针指向所指对象的各种东西时用 -> 。
//类指向类下面的各种东西时,要用:: 。
//对象指向对象下面的各种东西时用 . 。

class Building
{
    
    
	friend void goodGay::visit01(); //不带goodGay::作用域的话代表是全局函数

private:
	string m_BedRoom;

public:
	Building();
	string m_SetRoom;
};
//类外实现成员函数  记得使用this->
Building::Building()
{
    
    
	this->m_BedRoom = "卧室";
	this->m_SetRoom = "客厅";
}
goodGay::goodGay()
{
    
    
	building = new Building; //创建一个Building类型的对象堆区,并且用building存储
}
void goodGay::visit01()
{
    
    
	cout << "visit01正在访问 " << building->m_SetRoom << endl;
	cout << "visit01正在访问 " << building->m_BedRoom << endl;
}

void goodGay::visit02()
{
    
    
	cout << "visit02正在访问 " << building->m_SetRoom << endl;
	// cout << "visit02正在访问 " << building->m_BedRoom << endl;
}

void test01()
{
    
    
	goodGay gg;
	gg.visit01();
	gg.visit02();
}

void test02()
{
    
    
}

int main()
{
    
    
	test01();
	test02();
	system("pause");
	return 0;
}
/*
成员函数做友元易错点:
1.因为Goodgay类需要声明Building类变量,所以Building类必须Goodgay类之前声明(前向声明);
2.因为Building的定义中需要将Goodgay类的成员函数声明成友元成员函数,所以Building类必须Goodgay类之后定义;
3.因为Goodgay中的构造函数需要调用Building的构造函数,所以Goodgay类中构造函数的实现必须在Building类的定义之后;
总结:
1. Building类在Goodgay类前面声明,后面定义;
2. Goodgay类定义“类内”时不实现 构造函数 和 需要friend的成员函数;
3. Goodgay在Building类定义后,“类外”实现构造函数 和 需要friend的成员函数;
 */

Puntos propensos a errores para las funciones miembro como amigos:
1. Debido a que la clase Goodgay necesita declarar las variables de la clase Building, la clase Building debe declararse antes que la clase Goodgay (declaración directa) 2.
Debido a que la definición del Building debe declarar las funciones miembro de la clase Goodgay como función miembro Friend, por lo que la clase Building debe definirse después de la clase Goodgay
3. Debido a que el constructor en Goodgay necesita llamar al constructor Building, la implementación del constructor en la clase Goodgay debe ser posterior la definición de la clase Edificio;

Resumir:

  1. La clase Building se declara antes que la clase Goodgay y se define después;
  2. La clase Goodgay no implementa constructores ni funciones miembro que requieran amigos al definir "en clase";
  3. Después de la definición de la clase Building, Goodgay implementa las funciones de constructor y miembro que requieren amigos "fuera de la clase";

4.5 Sobrecarga del operador


Concepto de sobrecarga de operadores: redefine los operadores existentes y dales otra función para adaptarse a diferentes tipos de datos

4.5.1 Sobrecarga del operador Plus

Función: realizar la operación de agregar dos tipos de datos personalizados

#include <iostream>
using namespace std;
// 重载之后的+只是简写, 还是得按照参数列表传值
// 加号运算符重载
// 1、成员函数重载 +号   本质运算是 Person p3 = p1.operator+(p2);
// 2、全局函数重载 +号   本质运算是 person p3 = p1.operator+(p1,p2)

class Person
{
    
    
private:
	/* data */
public:
	// Person operator+(Person &p)// P为值传递,无法改变实参,&p为引用传递,可以改变实参
	// {
    
    
	// 	Person temp;
	// 	temp.m_A = this->m_A + p.m_A;
	// 	temp.m_B = this->m_B + p.m_B;
	// 	return temp;
	// }

	int m_A;
	int m_B;
};
// 2、全局函数重载 +号
Person operator+(Person &p1, Person &p2) // P为值传递,无法改变实参,&p为引用传递,可以改变实参
{
    
    
	Person temp;
	temp.m_A = p1.m_A + p2.m_A;
	temp.m_B = p1.m_B + p2.m_B;
	return temp;
}
//函数重载
Person operator+(Person &p1, int num)
{
    
    
	Person temp;
	temp.m_A = p1.m_A + num;
	temp.m_B = p1.m_B + num;
	return temp;
}
void test01()
{
    
    
	//这里其实写的有点麻烦 不如用括号法加上构造函数来赋值
	Person p1;
	p1.m_A = 10;
	p1.m_B = 10;
	Person p2;
	p2.m_A = 10;
	p2.m_B = 10;
	Person p3;
	p3 = p1 + p2;
	Person p4;
	p4 = p1 + 25;
	cout << "p3.m_A=" << p3.m_A << endl;
	cout << "p3.m_B=" << p3.m_B << endl;
	cout << "p4.m_A=" << p4.m_A << endl;
	cout << "p4.m_B=" << p4.m_B << endl;
}

int main()
{
    
    
	test01();
	system("pause");
	return 0;
}

Resumen 1: el + después de la sobrecarga es solo una abreviatura, en principio, aún debe pasar el valor de acuerdo con la lista de parámetros

4.5.2 Sobrecarga del operador de turno a la izquierda

Rol: puede generar tipos de datos personalizados.
Al sobrecargar el operador de desplazamiento a la izquierda, permita que el compilador sepa cómo operar de manera similar a cout<<peste tipo de operador.

#include <iostream>
using namespace std;

class Person
{
    
    
	friend ostream &operator<<(ostream &out, Person &p);

private:
	int m_A;
	int m_B;

public:
	Person(int a, int b);
	// p<<cout 成员函数实现不了重载左移运算符   本质上  p.operator<<(cout)   简化表示其实是 p<< cout  并不是我们想要的cout << p;
	// void operator<<(Person &p) {}
	// int m_A;
	// int m_B;
};

Person::Person(int a, int b)
{
    
    
	this->m_A = a;
	this->m_B = b;
}
//只能使用全局函数重载左移运算符
//本质 operator<<(cout,p)  简化为cout << p 注意: void operator<<(ostream &out, Person &p)仅仅实现一次  cout<<p   联想上几次课this返回对象本身实现的链式编程,一定要加引用& 否则会创建一个新的的对象
ostream &operator<<(ostream &out, Person &p) //可以把引用&cout换为&out  因为引用本身就有起别名的功能
{
    
    
	out << "a:" << p.m_A << " b:" << p.m_B;
	return out;
}
void test()
{
    
    
	Person p1(10, 20);
	cout << p1 << " hello world " << endl;//链式编程
}
int main()
{
    
    
	test();
	system("pause");
	return 0;
}

Nota: las funciones miembro no pueden realizar la sobrecarga del operador de desplazamiento a la izquierda, solo las funciones globales pueden realizar la sobrecarga del operador de desplazamiento a la izquierda
Nota: cout pertenece al flujo de salida ostream, el representante de la programación en cadena es cout
Nota: la programación en cadena debe agregarse antes de que la función devuelva &, de lo contrario, se creará un nuevo objeto

4.5.3 Sobrecarga del operador de incremento

Función: Realice sus propias operaciones de pre-incremento y post-incremento de datos plásticos sobrecargando el operador de incremento

#include <iostream>
using namespace std;
//重载递增运算符
//自定义整型
class MyInteger
{
    
    
	friend ostream &operator<<(ostream &cout, const MyInteger &myint);

private:
	int m_Num;

public:
	MyInteger();
	~MyInteger();
	//重载前置++运算符
	MyInteger &operator++() //返回引用是因为不想重新生成一个新的对象,链式编程思想,只对一个对象做重复操作
	{
    
    
		m_Num++;
		return *this; //*this解引用表示自身
	}
	//重载后置++运算符
	//此时不加引用,返回一个值是因为已经建立新对象temp,且如果返回一个引用则会使得temp变为局部对象变量,局部对象变量会再当前函数结束后自动释放掉
	MyInteger operator++(int) // int代表占位参数,可以用于区分前置和后置递增
	{
    
    
		// 1.先记录当时结果
		MyInteger temp = *this;
		// 2.后进行递增
		m_Num++;
		// 3.最后再返回记录的结果
		return temp;
	}
};

MyInteger::MyInteger()
{
    
    
	this->m_Num = 0;
}

MyInteger::~MyInteger()
{
    
    
}
//重载左移<<运算符
// ostream &operator<<(ostream &cout, MyInteger myint)//后置的时候不能进行链式运算
ostream &operator<<(ostream &cout, const MyInteger &myint)
{
    
    
	cout << myint.m_Num;
	return cout;
}

void test01()
{
    
    
	MyInteger myint;
	cout << ++(++myint) << endl; //直接加入操作符会提示并不存在,原因是myint是我们自定义的整型数据
	cout << myint << endl;
}
// C++中产生的临时对象是不可修改的,即默认为const的
//非const引用只能绑定到与该引用同类型的对象,但是非常量对象可以绑定到const引用上,
//因此可以去掉左移重载参数的类的引用符,即ostream &operator<<(ostream &cout, MyInt myint)
//或者加上const变为常量引用,即ostream &operator<<(ostream &cout, const MyInt &myint)
//注意该两种方法一定要记得把最上面的友元修改为相同的形式,否则会报错
void test02()
{
    
    
	MyInteger myint1;

	cout << myint1++ << endl;
	cout << myint1 << endl;
}
int main()
{
    
    

	test01();
	test02();
	system("pause");
	return 0;
}

Nota: El operador previo debe citarse y el operador posterior debe devolver un valor.
Nota: La clave para distinguir entre la sobrecarga previa al operador y la sobrecarga posterior al operador es el marcador de posición int.
Nota: Informe de error posterior al incremento , principio y dos soluciones:

Los objetos temporales generados en C++ no se pueden modificar, es decir,
las referencias no constantes que son constantes de forma predeterminada solo se pueden vincular a objetos del mismo tipo que la referencia, pero los objetos no constantes se pueden vincular a referencias constantes, por lo que el desplazamiento a la
izquierda se puede eliminar El carácter de referencia de la clase que lleva el parámetro, es decir, ostream &operator<<(ostream &cout, MyInt myint)
o agregar const para convertirse en una referencia constante, es decir, ostream &operator<<(ostream &cout, const MyInt &myint)
Tenga en cuenta que estos dos métodos deben recordarse Modifique el amigo superior al mismo formulario, de lo contrario se informará un error

Nota: El tercer método resuelve el informe de error de operación posterior al incremento, no necesita modificar la función sobrecargada del operador de desplazamiento a la izquierda y utiliza la operación posterior al incremento. myint1++;cout<<myint1<<out;Este método solo puede generar el valor después de la operación posterior al incremento del operador, y no puede dar salida myint1al problema de valor
Legado: aunque esta sección implementa la sobrecarga de preoperadores y postoperadores, e incrementa los parámetros enteros personalizados, según la idea de la programación en cadena, solo se completa la operación de preincremento y el la operación de incremento posterior se ha completado. La operación no se ha implementado. Si tiene la capacidad, debe reconstruir el operador de incremento posterior en esta sección;
extender la sobrecarga de la operación de decremento

#include <iostream>
using namespace std;
//重载递增运算符
//自定义整型
class MyInteger
{
    
    
	friend ostream &operator<<(ostream &cout, const MyInteger &myint);

private:
	int m_Num;

public:
	MyInteger();
	~MyInteger();
	//重载前置++运算符
	MyInteger &operator++()
	{
    
    
		m_Num++;
		return *this; //*this解引用表示自身
	}
	//重载后置++运算符
	MyInteger operator++(int) // int代表占位参数,可以用于区分前置和后置递增
	{
    
    
		// 1.先记录当时结果
		MyInteger temp = *this;
		// 2.后进行递增
		m_Num++;
		// 3.最后再返回记录的结果
		return temp;
	}

	//重载前置--运算符
	MyInteger operator--()
	{
    
    
		m_Num--;
		return *this;
	}

	//重载后置--运算符 int 相当于占位符
	MyInteger operator--(int)
	{
    
    
		//先记录当前这个数
		MyInteger temp;
		//进行--操作
		m_Num--;
		//返回开始记录的那个数
		return temp;
	}
};

MyInteger::MyInteger()
{
    
    
	this->m_Num = 3;
}

MyInteger::~MyInteger()
{
    
    
}
//重载左移<<运算符

ostream &operator<<(ostream &cout, const MyInteger &myint)
{
    
    
	cout << myint.m_Num;
	return cout;
}

void test01()
{
    
    
	MyInteger myint;
	cout << ++(++myint) << endl;
	cout << myint << endl;
}

void test02()
{
    
    
	MyInteger myint;

	cout << myint++ << endl;
	cout << myint << endl;
}
void test03()
{
    
    
	MyInteger myint;

	cout << myint--<<endl;
	cout << myint << endl;
}
void test04()
{
    
    
	MyInteger myint;

	cout << --myint << endl;
	cout << myint << endl;
}
int main()
{
    
    

	test01();
	test02();
	test03();
	test04();
	system("pause");
	return 0;
}

4.5.4 Sobrecarga de operadores de asignación

El compilador de c++ agrega al menos 4 funciones a una clase

Constructor predeterminado (sin parámetro, el cuerpo de la función está vacío)
destructor predeterminado (sin parámetro, el cuerpo de la función está vacío)
constructor de copia predeterminado, copia el valor del
operador de asignación de atributo =, copia el valor del atributo
si hay El atributo apunta al área de montón, y el problema de copia profunda y superficial también ocurrirá al realizar la operación de asignación

#include <iostream>
using namespace std;

//赋值运算符重载
class Person
{
    
    
private:
public:
	Person(int age);
	~Person();
	Person &operator=(Person &p)
	{
    
    
		//编译器提供的浅拷贝 m_Age=P.m_Age;

		//应该先判断是否有属性在堆区,如果有应该先释放干净,然后再进行深拷贝
		if (m_Age != NULL)
		{
    
    
			delete m_Age;
			m_Age = NULL;
		}
		//深拷贝
		this->m_Age = new int(*p.m_Age);
		//返回对象本身
		return *this; //链式编程思想
	}
	int *m_Age;
};

Person::Person(int age)
{
    
    
	this->m_Age = new int(age); //堆区  由程序员手动开启,由程序员手动释放  因此需要加个析构韩硕
}

Person::~Person()
{
    
    
	if (m_Age != NULL)
	{
    
    
		delete m_Age;
		m_Age = NULL;
	}
}

void test01()
{
    
    
	Person p1(18);
	Person p2(28);
	Person p3(38);
	p3 = p2 = p1; //赋值操作
	cout << "p1岁数:" << *p1.m_Age << endl;
	cout << "p2岁数:" << *p2.m_Age << endl;
	cout << "p3岁数:" << *p3.m_Age << endl;
}

int main()
{
    
    
	test01();

	system("pause");
	return 0;
}


//是指针的值,存储的是地址。所以本质上拷贝过去的值是一个地址值。这也导致了,两个不同的指针,指向同一块儿内存。看上去像是改变了'值',实际上只是挪了以下指针的指向而已。但是原本类里开辟的区域,它的值可以一直存在的,该多少还是多少。因此,这根本不算值拷贝

Nota: Debido a que el segundo juicio es para juzgar si la dirección en p2 está vacía en lugar de juzgar la memoria en el área del montón, las dos direcciones de puntero apuntan a la misma memoria, por lo que habrá un error de ejecución de refactorización. Solución: use copia profunda para
resolver problemas con copias superficiales

4.5.5 Sobrecarga de operadores relacionales

Rol: sobrecargar los dos operadores relacionales igual a ==y no igual a !=, utilizados para operaciones de comparación de objetos de tipo personalizado

#include <iostream>
using namespace std;

//重载   关系运算符
class Person
{
    
    
private:
public:
	Person(string name, int age)
	{
    
    
		m_Name = name;
		m_Age = age;
	}
	bool operator==(Person &p)
	{
    
    
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
    
    
			return true;
		}
		else
			return false;
	}
	bool operator!=(Person &p)
	{
    
    
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
    
    
			return false;
		}
		else
			return true;
	}
	string m_Name;
	int m_Age;
};

void test01()
{
    
    
	Person p1("Tom", 19);

	Person p2("Tom", 18);
	if (p1 == p2)
	{
    
    
		cout << "equivalent" << endl;
	}
	else
	{
    
    
		cout << "not equivalent!!!" << endl;
	}
	if (p1 != p2)
	{
    
    
		cout << "not equivalent" << endl;
	}
	else
	{
    
    
		cout << "equivalent!!!" << endl;
	}
}
int main()
{
    
    
	test01();
	system("pause");
	return 0;
}

4.5.6 Sobrecarga del operador de llamada de función

El operador de llamada de función () se denomina funtor porque el método utilizado después de la sobrecarga es muy similar a una función de llamada de función
: el funtor es más flexible y cambiable. Aquí se usa para implementar una
extensión de clase de impresión: las funciones anónimas usan la sobrecarga directamente después de la operador de llamada de función (sin declaración)

#include <iostream>
using namespace std;

//重载  函数调用运算符 ()
//打印输出的一个类
class MYPrint
{
    
    
private:
	/* data */
public:
	void operator()(string test)
	{
    
    
		cout << test << endl; // test不加双引号,直接输出string test
	}
};

void test01()
{
    
    
	MYPrint myPrint;
	myPrint("hello world!"); //仿函数
}
//仿函数非常灵活,没有固定的写法
//加法类
class MYAdd
{
    
    
private:
	/* data */
public:
	int operator()(int a, int b)
	{
    
    
		return a + b;
	}
};
void test02()
{
    
    
	MYAdd myadd;//myadd算作起名了
	int sum = myadd(100, 100);
	cout << sum << endl;
	//匿名函数对象
	cout << MYAdd()(100, 100) << endl;
	//特点当前行执行完立即被释放
}
int main()
{
    
    
	test01();
	test02();

	system("pause");
	return 0;
}

4.6 Herencia

La herencia es una de las tres características principales de la orientación a objetos
. Existen relaciones especiales entre algunas clases y clases. Al definir estas clases, los miembros del nivel inferior no solo tienen las características comunes del nivel superior, sino que también tienen sus propias características.
En este momento, podemos considerar el uso de técnicas de herencia para reducir la duplicación de código.

4.6.1 Sintaxis básica de herencia

Los beneficios de la herencia: reduce la duplicación de código.
La herencia usa la sintaxis: class 子类 : 继承方式 父类
las subclases también se denominan clases derivadas,
las clases principales también se denominan clases base
. Las subclases contienen dos partes:
una parte se hereda de la clase principal de diferentes maneras y la otra parte es esa. es diferente de la clase principal agregada.
La parte heredada de la clase principal muestra los elementos comunes de la subclase, mientras que la parte recién agregada refleja la personalidad de la subclase.

#include <iostream>
using namespace std;
//继承实现
//公共页面
class BasePage
{
    
    
public:
	void header()
	{
    
    
		cout << "首页、公开课、登录、注册...(公共头部)" << endl;
	}

	void footer()
	{
    
    
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
    
    
		cout << "Java,Python,C++...(公共分类列表)" << endl;
	}
};
//继承的好处:减少重复代码
//继承使用语法: class 子类 : 继承方式 父类
//子类 也称为 派生类
//父类 也称为 基类
// Java页面
class Java : public BasePage //此处继承方式是public 公共继承方式
{
    
    
public:
	void content()
	{
    
    
		cout << "JAVA学科视频" << endl;
	}
};
// Python页面
class Python : public BasePage
{
    
    
public:
	void content()
	{
    
    
		cout << "Python学科视频" << endl;
	}
};
// C++页面
class CPP : public BasePage
{
    
    
public:
	void content()
	{
    
    
		cout << "C++学科视频" << endl;
	}
};

void test01()
{
    
    
	// Java页面
	cout << "Java下载视频页面如下: " << endl;
	Java ja;
	ja.header();
	ja.footer();
	ja.left();
	ja.content();
	cout << "--------------------" << endl;

	// Python页面
	cout << "Python下载视频页面如下: " << endl;
	Python py;
	py.header();
	py.footer();
	py.left();
	py.content();
	cout << "--------------------" << endl;

	// C++页面
	cout << "C++下载视频页面如下: " << endl;
	CPP cp;
	cp.header();
	cp.footer();
	cp.left();
	cp.content();
}

int main()
{
    
    

	test01();

	system("pause");

	return 0;
}



Resumir

Esta serie se utiliza para registrar notas durante el aprendizaje habitual de C++;

Supongo que te gusta

Origin blog.csdn.net/TianHW103/article/details/127684289
Recomendado
Clasificación