C++ Series: Core Programming

C++ core programming learning record



foreword

Learning Video Link: Dark Horse Programmer's Ingenuity | C++ Tutorial


1. Memory partition model


2. Citation


3. Function improvement


4. Classes and Objects


4.1 Packaging


4.2 Object initialization and cleanup


4.2.3 When to call the copy constructor

In C++, there are usually three situations when the copy constructor is called:
use an already created object to initialize a new object;
pass value to the function parameter;
return a local object by value;
example:

#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 Constructor calling rules

#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 C++ object model and this pointer


4.3.1 Member variables and member functions are stored separately

In C++, member variables and member functions in a class are stored separately without interfering with each other, and only non-static member variables in a class belong to the class object; code example
:

#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;
}

Note: If the interior of a class is empty, the byte it occupies at this time is not 0, but should be 1, because the C++ compiler will automatically allocate a storage byte to the empty object to distinguish the storage location; error:
in After defining the static member variable, when I want to output it, m_BI found that the class cannot be called;
the reason: after typing, it prompts that there is no access right. I remembered that when I created an empty class based on the video at the beginning, I didn’t add public attributes to it. After adding it, I publiccan use two way to access it;

4.3.2 The concept of this pointer

Through 4.3.1, we know that member variables and member functions are stored separately in C++, and each non-static member function will only generate a function instance, which means that multiple objects of the same type will share a piece of code.
So the question is: how does this piece of code distinguish which object calls itself?
C++ solves the above problems by providing a special object pointer, the this pointer. The this pointer points to the object to which the called member function belongs, and the this pointer is a pointer implicit in each non-static member function. It does not need to be defined, it can be used directly.
The purpose of the this pointer:
* When the formal parameter and the member variable have the same name, the this pointer can be used to distinguish it
In the non-static member function of the class to return the object itself, you can use return this

Code example:

#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;
}

Note: When returning itself, you should pay attention to the method of using the reference. If it is returned by value, a new object will be created, which is converted into a copy function;

4.3.3 Null pointer access member function

Null pointers in C++ can also call member functions, but also pay attention to whether the this pointer is used

If this pointer is used, it needs to be judged to ensure the robustness of the code

#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 const modified member function

Constant function:

After adding const after the member function, we call this function a constant function. The
member attribute cannot be modified in the constant function. After the keyword mutable is added to the member attribute declaration, the constant object
can still be modified in the constant function :

Adding const before declaring an object means that the object is a constant object.
A constant object can only call a constant function.

#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;
}

Note: the this pointer in each member function;
the essential pointer constant of this pointer cannot be modified but the pointed value can be modified

4.4 Tomomoto

In life, your home has a living room (Public) and a bedroom (Private)

All guests in the living room can enter, but your bedroom is private, which means only you can enter

But, you can also allow your good girlfriends and gay friends to enter.

In the program, some private attributes also want to be accessed by some special functions or classes outside the class, so you need to use the technology of friends

The purpose of a friend is to allow a function or class to access private members of another class

The keyword of the friend is friend

Three Realizations of Friends

  • Global functions as friends
  • class as friend
  • member function as friend

4.4.1 Global functions as friends

#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 Classes as friends

#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;
}

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

4.4.3 Member functions as friends

#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的成员函数;
 */

Error-prone points for member functions as friends:
1. Because the Goodgay class needs to declare the Building class variables, the Building class must be declared before the Goodgay class (forward declaration);
2. Because the definition of the Building needs to declare the member functions of the Goodgay class as Friend member function, so the Building class must be defined after the Goodgay class;
3. Because the constructor in Goodgay needs to call the Building constructor, the implementation of the constructor in the Goodgay class must be after the definition of the Building class;

Summarize:

  1. The Building class is declared before the Goodgay class and defined later;
  2. The Goodgay class does not implement constructors and member functions that require friends when defining "in-class";
  3. After the definition of the Building class, Goodgay implements the constructor and member functions that require friends "outside the class";

4.5 Operator overloading


Operator overloading concept: redefine existing operators and give them another function to adapt to different data types

4.5.1 Plus operator overloading

Function: realize the operation of adding two custom data types

#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;
}

Summary 1: The + after overloading is just a shorthand, in principle, you still have to pass the value according to the parameter list

4.5.2 Left shift operator overloading

Role: You can output custom data types
By overloading the left shift operator, let the compiler know how to operate similar to cout<<pthis type of operator

#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;
}

Note: member functions cannot perform left shift operator overloading, only global functions can perform left shift operator overloading
Note: cout belongs to the ostream output stream, the representative of chain programming is cout
Note: chain programming must be added before the function returns &, otherwise a new object will be created

4.5.3 Increment operator overloading

Function: Realize your own plastic data pre-increment and post-increment operations by overloading the increment operator

#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;
}

Note: The pre-operator needs to be quoted, and the post-operator needs to return a value.
Note: The key to distinguish between pre-operator overloading and post-operator overloading is the placeholder int.
Note: Post-increment error reporting, principle and two solutions:

Temporary objects generated in C++ are unmodifiable, that is,
non-const references that are const by default can only be bound to objects of the same type as the reference, but non-constant objects can be bound to const references,
so the left shift can be removed The reference character of the class that carries the parameter, that is, ostream &operator<<(ostream &cout, MyInt myint)
or add const to become a constant reference, that is, ostream &operator<<(ostream &cout, const MyInt &myint)
Note that these two methods must be remembered Modify the top friend to the same form, otherwise an error will be reported

Note: The third method solves the post-increment operation error report, does not need to modify the overloaded left shift operator function, and uses the post-increment operation. myint1++;cout<<myint1<<out;This method can only output the value after the operator post-increment operation, and cannot output myint1the value
problem . Legacy: Although this section implements the overloading of pre-operators and post-operators, and increments custom integer parameters, based on the idea of ​​chain programming, only the pre-increment operation is completed, and the post-increment operation is completed. The operation has not been implemented. If you have the ability, you should rebuild the post-increment operator in this section;
extend the decrement operation overload

#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 Assignment operator overloading

The c++ compiler adds at least 4 functions to a class

Default constructor (no parameter, function body is empty)
default destructor (no parameter, function body is empty)
default copy constructor, copy the value of the attribute
assignment operator=, copy the value of the attribute
if there is in the class The attribute points to the heap area, and the deep and shallow copy problem will also occur when doing the assignment operation

#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;
}


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

Note: Because the second judgment is to judge whether the address in p2 is empty instead of judging the memory in the heap area, the two pointer addresses point to the same memory, so there will be a refactoring running bug Solution: Use deep copy to
solve Problems with shallow copying

4.5.5 Relational operator overloading

Role: Overload the two relational operators equal to ==and not equal to !=, used for comparison operations of custom type objects

#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 Function call operator overloading

The function call operator () is called a functor because the way it is used after overloading is very similar to a function call
Function: Functors are more flexible and changeable Here it is used to implement a printout class
extension: anonymous functions use overloading directly after the function call operator (no declaration)

#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 Inheritance

Inheritance is one of the three major characteristics of object-oriented
. There are special relationships between some classes and classes. When defining these classes, members at the lower level not only have the commonality of the upper level, but also have their own characteristics.
At this time, we can consider using inheritance techniques to reduce duplication of code

4.6.1 Basic Syntax of Inheritance

The benefits of inheritance: reduce duplication of code
Inheritance uses syntax: class 子类 : 继承方式 父类
subclasses are also called derived classes,
parent classes are also called base classes
subclasses contain two parts:
one part is inherited from the parent class in different ways, and the other part is that it is different from the parent class class added.
The part inherited from the parent class shows the commonality of the subclass, while the newly added part reflects the personality of the subclass.

#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;
}



Summarize

This series is used to record notes during the usual learning of C++;

Guess you like

Origin blog.csdn.net/TianHW103/article/details/127684289