C++ expedition package (part 2)

C++ encapsulation overview

The second half of the chapter continues to focus on classes and objects

Combine simple elements you’ve learned into complex new knowledge.

  • Object + Data Member = Object member (object as data member)
  • Object + Array = Array of objects (every element in an array is an object)
  • Deep copy & shallow copy (objects assign to each other and copy each other)
  • Object pointer (operation object) & object pointer member
  • This pointer
  • Const + object -> constant object
  • Const + function -> constant member function
  • Const + object member -> constant object member

Designed a clever case, the maze.

C++ object array

How do I instantiate an object? Instantiating an object is important for a program to access member functions and data members only if the object is instantiated.

Sometimes we need to instantiate a set of objects. For example, we want to instantiate a class of 50 students.

A coordinate can only represent one point, if we want to define a rectangle. Define four points, the lines of which form a rectangle.

These four points can be defined as an array, and each point is an object.

Object array: Coordinate class

class Coordinate
{
public:
	int m_iX; / / x coordinate
	int m_iY; / / y
}

int main(a)
{
	Coordinate coord[3];// Instantiate an array of objects on the stack
	coord[1].m_iX = 10;

	Coordinate *p = new Coordinate[3];// Instantiate the array of objects on the heap, call the constructor three times
	p[0].m_iY =20; // p -> m_iY =20;

	delete []p; // Destroy the array of objects in the heap, calling the destructor three times
	p =NULL;

	return 0;
}
Copy the code

Stack area instantiates the object array, will allocate the corresponding memory, the system will automatically manage. Each memory holds the x,y heap allocation corresponding memory, p and p[0] is equivalent.

C++ object array practice code

2-2-InstanceArray

Coordinate.h

class Coordinate
{
public:
	Coordinate();
	~Coordinate();
public:
	int m_iX;
	int m_iY;
};
Copy the code

coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate()
{
	cout << "Coordinate" << endl;

}
Coordinate::~Coordinate()
{
	cout << "~Coordinate" << endl;
}
Copy the code

main.cpp

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Coordinate.h"
using namespace std;

int main(void)
{
	Coordinate coor[3];
	coor[0].m_iX = 3;
	coor[0].m_iY = 5;

	Coordinate *p = new Coordinate[3];
	p->m_iX = 7;
	p[0].m_iY = 9;

	p++;
	p->m_iX = 11;
	p[0].m_iY = 13;// because the above p++. P is already pointing to the second address

	p[1].m_iX = 15;// p refers to the third element

	p++;
	p->m_iY = 17;// p refers to the third element

	for (int i = 0; i < 3; i++)
	{
		cout << coor[i].m_iX << " coor x&y " << coor[i].m_iY << endl;

	}
	for (int j = 0; j < 3; j++)
	{
		//cout << "p_x" << p[j].m_iX << endl;
		//cout << "p_y" << p[j].m_iY << endl;
		cout << "p_x" << p->m_iX << endl;
		cout << "p_y" << p->m_iY << endl;
		p--;
	}

	p++;// The loop is closed when p=-1. So when you free it, it's not the original memory.

	delete []p;
	p = NULL;
	system("pause");
	return 0;
}
Copy the code

Traversal simply prints out the information for each element in the array.

Delete destroys the array of objects in the heap, showing three destructor calls. The system automatically manages stack destruction, as we can see when we hit Enter, which is also called three times.

Make sure that p is returned to its original position before deleting.

C++ array object practice (2)

Before, we said that if you use new, you need to use delete.

If new is an array, then delete is surrounded by brackets.

Why, however, should the delete corresponding to an array be enclosed in brackets?

  • When you instantiate an array, each object in the array executes its constructor.
  • We also want them to execute their own destructor when they are destroyed
  • If there are no brackets, only the first element is destroyed.
delete p;// After the brackets are removed, only the memory to which the current pointer points is destroyed and only one destructor is executed
Copy the code

You can see that the destructor is executed only once.

Members of the object

These are simple objects, and the data members are basic data types.

  • Object contains other objects (object members)

  • Cartesian coordinate system

Take A line segment in the coordinate system, starting at A(2,1) and ending at B(6,4).

Define a line segment class. Each line segment has a starting point and an ending point.

Definition of point coordinates:

class Coordinate
{
public:
	Coordinate();
private:
	int m_iX;
	int m_iY;
}
Copy the code

Definition of line segment:

class Line
{
public:
	Line();
private:
	Coordinate m_coorA;
	Coordinate m_coorB;
}
Copy the code

Instantiate the description line segment

int main(void)
{
	Line *p = new Line();

	delete p;
	p = NULL;
	return 0;
}
Copy the code

Conclusion:

When we instantiate a line object, we instantiate the a coordinate first, then the B coordinate point, and then the line object when the two objects are instantiated

When destroying, it does the opposite of creating, destroying line first, then B, and finally A

For example, making cars -> parts -> drawings; Tear down the car -> drawings -> Parts

In both cases, constructors take no arguments. Coordinate class constructors need arguments.

class Coordinate
{
public:
	Coordinate(int x, int y);
private:
	int m_iX;
	int m_iY;
}

class Line{
public:
	Line(int x1,int y1, int x2,int y2);
private:
	Coordinate m_coorA;
	Coordinate m_coorB;
}
Copy the code

It would be a problem if I wrote it as follows

int main(void)
{
	Line *p = new Line(2.1.6.4);

	delete p;
	p = NULL;
	return 0;
}
Copy the code

Because it’s passed in, it’s not assigned to the object member inside. One more code change: equip line’s constructor with an initializer list

Line(int x1,int y1, int x2,int y2):m_coorA(x1,y1),m_coorB(x2,y2)
{
	cout << "Line" << endl;
}
Copy the code

C++ object membership practices (part 1)

2-6-ObjectMember

Coordinate. H:

class Coordinate
{
public:
	Coordinate();
	~Coordinate();
public:
	int getX(a);
	void setX(int x);

	int getY(a);
	void setY(int y);
private:
	int m_iX;
	int m_iY;
};
Copy the code

Coordinate. CPP:

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate()
{
	cout << "Coordinate" << endl;

}
Coordinate::~Coordinate()
{
	cout << "~Coordinate" << endl;
}

int Coordinate::getX() {
	return m_iX;
}
void Coordinate::setX(int x) {
	m_iX = x;
}
int Coordinate::getY(){
	return m_iY;
}
void Coordinate::setY(int y) {
	m_iY = y;
}
Copy the code

Line.h :

#include "Coordinate.h"

class Line {
public:
	Line();
	~Line();
	void setCoorA(int x, int y);
	void setCoorB(int x, int y);
	void printInfo(a);
private:
	Coordinate m_coorA;
	Coordinate m_coorB;
};
Copy the code

Line.cpp :

#include <iostream>
#include "Line.h"

using namespace std;

Line::Line() {
	cout << "Line()" << endl;
}
Line::~Line() {
	cout << "~Line()" << endl;
}
void Line::setCoorA(int x, int y) {
	m_coorA.setX(x);
	m_coorA.setX(y);
}
void Line::setCoorB(int x, int y) {
	m_coorB.setX(x);
	m_coorB.setY(y);
}
void Line::printInfo() {
	cout << "(" <<m_coorA.getX()<< "," <<m_coorA.getY()<< ")" << endl;
	cout << "(" << m_coorB.getX()<< "," << m_coorB.getY()<< ")" << endl;
}
Copy the code

main.cpp

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Line.h"

using namespace std;

int main(void)
{
	Line *p = new Line();

	delete p;
	p = NULL;
	system("pause");
	return 0;
}
Copy the code

In the figure above we can see the sequence in which object members are created and destroyed by the class.

C++ object membership practice (2)

As a line segment class, we want to identify the two points in it when it is created. Line segment class constructors take arguments and pass to points.

Coordinate(int x, int y);

Line::Line(int x1,int y1,int x2,int y2):m_coorA(x1,y1),m_coorB(x2,y2)
{
	cout << "Line()" << endl;
}
Copy the code

The point is:

  • Coordinate has two parameters
  • The constructor of Line uses an initializer list

2-6-2-ObjectMemberParameter

Coordinate.h:

class Coordinate
{
public:
	Coordinate(int x, int y);
	~Coordinate();
public:
	int getX(a);
	void setX(int x);
	int getY(a);
	void setY(int y);
private:
	int m_iX;
	int m_iY;
};
Copy the code

Coordinate.cpp :

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate(int x,int y)
{
	m_iX = x;
	m_iY = y;
	cout << "Coordinate()"<< m_iX << "," << m_iY << endl;

}
Coordinate::~Coordinate()
{
	cout << "~Coordinate()" << m_iX << "," << m_iY << endl;
}

int Coordinate::getX() {
	return m_iX;
}
void Coordinate::setX(int x) {
	m_iX = x;
}
int Coordinate::getY(){
	return m_iY;
}
void Coordinate::setY(int y) {
	m_iY = y;
}
Copy the code

Line. H:

#include "Coordinate.h"

class Line {
public:
	Line(int x1,int y1,int x2,int y2);
	~Line();
	void setCoorA(int x, int y);
	void setCoorB(int x, int y);
	void printInfo(a);
private:
	Coordinate m_coorA;
	Coordinate m_coorB;
};
Copy the code

Line.cpp:

#include <iostream>
#include "Line.h"

using namespace std;

Line::Line(int x1,int y1,int x2,int y2):m_coorA(x1,y1),m_coorB(x2,y2)
{
	cout << "Line()" << endl;
}
Line::~Line() {
	cout << "~Line()" << endl;
}
void Line::setCoorA(int x, int y) {
	m_coorA.setX(x);
	m_coorA.setX(y);
}
void Line::setCoorB(int x, int y) {
	m_coorB.setX(x);
	m_coorB.setY(y);
}
void Line::printInfo() {
	cout << "(" << m_coorA.getX() << "," << m_coorA.getY() << ")" << endl;
	cout << "(" << m_coorB.getX() << "," << m_coorB.getY() << ")" << endl;
}
Copy the code

main.cpp:

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Line.h"
using namespace std;

int main(void)
{
	Line *p = new Line(1.2.3.4);
	p->printInfo();
	delete p;
	p = NULL;
	system("pause");
	return 0;
}
Copy the code

Note:

If object A has object member B and object B does not have A default constructor, then object A must initialize object B in the initializer list.

If object member B has A default constructor, then it is possible to initialize B without using an initializer list in object A.

Unit to consolidate

Define a Coordinate array with 2 objects, traverse the array of objects, and print the object information

#include <iostream>
using namespace std;
class Coordinate
{
    
public:
	Coordinate()
	{
	}
	// Print the coordinate function
	void printInfo(a)  
	{
	    cout << "("<<m_iX<<","<<m_iY<<")"<<endl;
	}
public:
	int m_iX;
	int m_iY;
};
int main(void)
{
	// Define an object array
    Coordinate coorArr[2];
    coorArr[0].m_iX = 1;
    coorArr[0].m_iY = 2;
    coorArr[1].m_iX = 3; 
    coorArr[1].m_iY = 4;

	// Traverses the number group to print object information
	for(int i = 0; i < 2; i++)
	{
		coorArr[i].printInfo();
	}	
	return 0;
}
Copy the code

Deep copy and shallow copy

The copy constructor tutorial only explains how to declare the copy constructor and when it is automatically called. How to implement the copy constructor is not explained, because copying between objects is not easy.

There are two types: deep copy and shallow copy

class Array
{
public:
	Array() { m_iCount = 5; } Array(constArray& arr) { m_iCount = arr.m_iCount; }private:
	int m_iCount;
};

int main(void)
{
	Array arr1;
	Array arr2 = arr1;
	return 0;
}
Copy the code

The constructor Array() is called when arr1 is instantiated, then m_iCount = 5. The copy constructor is called for arR2, and Array(const Array& arR) passes arR1 as an argument through arR.

Enhanced version

class Array
{
public:
	Array(){
		m_iCount = 5;
		m_pArr = new int[m_iCount];
	}
	Array(const Array& arr){
		m_iCount = arr.m_iCount;
		m_pArr = arr.m_pArr;
	}
private:
	int m_iCount;
	int *m_pArr;
}

int main(void)
{
	Array arr1;
	Array arr2 = arr1;
	return 0;
}
Copy the code
  • In common, both the regular and enhanced versions simply copy the values of the data members. We also call this copying pattern shallow copy. Using a shallow copy is fine for the first example.

Copy a pointer from ARR1 to ARR2, and both Pointers will now point to the same memory address.

  • However, the problem with the enhanced version is that it simply copies the pointer (arr1 and ARR2 Pointers point to the same address). Once the data of the copied object is changed, the data in the copied object will also change. (After arR1 is destroyed, pointer no longer exists, null pointer is reclaimed when ARR2 is destroyed)

Therefore, what we want is to point to two different pieces of memory, and then the values (elements) in the memory will be equal

class Array
{
public:
	Array(){
		m_iCount = 5;
		m_pArr = new int[m_iCount];
	}
	Array(const Array& arr){
		m_iCount = arr.m_iCount;

		m_pArr = new int[m_iCount]; // The main implementation: instead of assigning a value directly, it creates its own memory address
		for(int i=0; i<m_iCount; i++){// Assign corresponding values to ensure that the values are equal.m_pArr[i] = arr.m_pArr[i]; }}private:
	int m_iCount;
	int *m_pArr;
}

int main(void)
{
	Array arr1;
	Array arr2 = arr1;
	return 0;
}
Copy the code

Deep copy: Create a new heap and copy the data in the heap one by one in a loop. In this way, you can avoid changing the data of the copied object when modifying the data of the copied object.

Shallow copy code practices

Requirements:

Illustrate the usefulness of deep copy in some situations.

3-2-ShallowCopy

Shallow copy code:

Array.h

class  Array
{
public:
	 Array();
	 Array(const Array& arr);
	~ Array();

	int getCount(a);
	void setCount(int val);
private:
	int m_iCount;
};
Copy the code

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array()
{
	cout << "Array()" << endl;
}

Array::Array(const Array& arr) {
	m_iCount = arr.m_iCount;
	cout << "Array(&)" << endl;
}

Array::~Array() {
	cout << "~Array()" << endl;
}

void Array::setCount(int c) {
	m_iCount = c;
}
int Array::getCount() {
	return m_iCount;
}
Copy the code

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1;
	arr1.setCount(5);

	Array arr2 = arr1;

	cout << "arr2,count:" <<arr2.getCount() << endl;
	system("pause");
	return 0;
}
Copy the code

Deep-copy code practices

Shallow copy code:

Array::Array(const Array& arr) {
	m_pArr = arr.m_pArr; // Use shallow copy
	m_iCount = arr.m_iCount;
	cout << "Array(&)" << endl;
}
Copy the code

Note that this makes both ARRs point to the same block of memory. An error abort occurs when the same block of memory is destroyed twice during destruction.

3-3-DeepCopy

Array.h:

class  Array
{
public:
	 Array(int count);
	 Array(const Array& arr);
	~ Array();

	int getCount(a);
	void setCount(int val);
	void printAddr(a);
private:
	int m_iCount;
	int *m_pArr;
};
Copy the code

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array(int count )
{
	m_iCount = count;
	m_pArr = new int[m_iCount];
	cout << "Array()" << endl;
}

Array::Array(const Array& arr) {
	m_pArr = arr.m_pArr;// Use shallow copy
	m_iCount = arr.m_iCount;
	cout << "Array(&)" << endl;
}

Array::~Array() {
	delete[]m_pArr;
	m_pArr = NULL;
	cout << "~Array()" << endl;
}

void Array::setCount(int c) {
	m_iCount = c;
}
int Array::getCount() {
	return m_iCount;
}
void Array::printAddr() {
	cout << "m_pArr:" << m_pArr << endl;
};
Copy the code

main.cpp

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(5);

	Array arr2(arr1);

	arr1.printAddr();
	arr2.printAddr();
	system("pause");
	return 0;
}
Copy the code

You can see that in the shallow copy, both point to the same block of memory. There are problems freeing memory.

Convert to deep copy

Modify the array. CPP copy function

Array::Array(const Array &arr) {
	m_iCount = arr.m_iCount;
	m_pArr = new int[m_iCount]; // Use deep copy
	for (int i =0; i<m_iCount; i++) { m_pArr[i] = arr.m_pArr[i]; }cout << "Array(&)" << endl;
}
Copy the code

Deep copy: 1. Apply for a memory. Then copy the value in the memory of the source object to the corresponding location.

For clarity, assign values to each element of arr1 in the constructor

Array::Array(int count)
{
	m_iCount = count;
	m_pArr = new int[m_iCount];
	for (int i=0; i<m_iCount; i++) { m_pArr[i] = i; }cout << "Array()" << endl;
}
Copy the code

Run it again. There are no errors and the two already point to different memory addresses.

Add void printArr() to array.h;

Add the print Array function to array. CPP:

void Array::printArr() {
	for (int i=0; i<m_iCount; i++) {cout << m_pArr[i] << endl; }}Copy the code

At this point main.cpp adds:

arr1.printArr();
arr2.printArr();
Copy the code

Full deep copy code:

3-3-DeepCopy

Array.h:

class  Array
{
public:
	Array(int count);
	Array(const Array& arr);
	~Array();

	int getCount(a);
	void setCount(int val);
	void printAddr(a);
	void printArr(a);
private:
	int m_iCount;
	int *m_pArr;
};
Copy the code

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array(int count)
{
	m_iCount = count;
	m_pArr = new int[m_iCount];
	for (int i = 0; i < m_iCount; i++)
	{
		m_pArr[i] = i;
	}
	cout << "Array()" << endl;
}

Array::Array(const Array& arr) {
	m_iCount = arr.m_iCount;
	m_pArr = new int[m_iCount]; // Use deep copy
	for (int i = 0; i < m_iCount; i++)
	{
		m_pArr[i] = arr.m_pArr[i];
	}

	cout << "Array(&)" << endl;
}

Array::~Array() {
	delete[]m_pArr;
	m_pArr = NULL;
	cout << "~Array()" << endl;
}

void Array::setCount(int c) {
	m_iCount = c;
}
int Array::getCount() {
	return m_iCount;
}
void Array::printAddr() {
	cout << "m_pArr:" << m_pArr << endl;
};
void Array::printArr() {
	for (int i = 0; i < m_iCount; i++)
	{
		cout << m_pArr[i] << endl; }}Copy the code

The main. CPP:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(5);

	Array arr2(arr1);

	arr1.printAddr();
	arr2.printAddr();
	arr1.printArr();
	arr2.printArr();
	system("pause");
	return 0;
}
Copy the code

You can see that the deep copy points to two different addresses with the same content.

C++ object pointer

There is a pointer to an object.

The demo:

class Coordinate{
public:
	int m_iX;
	int m_iY;
}
Copy the code

Instantiate our coordinate class in the heap:

Coordinate *p = new Coordinate; // Execute the constructor
Copy the code

P points to m_iX and is accessed as p->m_iX; *p becomes an object, adopted. Access the elements.

Specific example code:

int main(void)
{
	Coordinate *p = new Coordinate;
	p -> m_iX = 10;  //(*p).m_iX =10;
	p -> m_iY = 20;  //(*p).m_iY =20;
	delete p;
	p = NULL;
	return 0;
}
Copy the code
  • New automatically calls the object’s constructor;
  • Malloc in C does not call the constructor of the related object, but allocates memory.

C++ object pointer practice:

4-2-ObjectPointer

Coordinate.h

class Coordinate
{
public:
	Coordinate();
	~Coordinate();
	int m_iX;
	int m_iY;
};
Copy the code

Coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate()
{
	cout << "Coordinate()" << endl;
}

Coordinate::~Coordinate()
{
	cout << "~Coordinate()" << endl;
}
Copy the code

main.cpp:

#include <iostream>
#include "Coordinate.h"
#include <stdlib.h>

using namespace std;

int main(a)
{
	// Use object Pointers to point to memory, both ways

	// instantiate in the heap
	Coordinate *p1 = NULL;
	p1 = new Coordinate; // Parentheses can be written with or without the default constructor
	Coordinate *p2 = new Coordinate(); 2 / / method

	p1->m_iX = 10;
	p1->m_iY = 20; // Pointer mode
	(*p2).m_iX = 30; //*p2 makes P2 an object
	(*p2).m_iY = 40;

	cout << (*p1).m_iX + (*p2).m_iX << endl;
	cout << p1->m_iY + p2-> m_iY << endl;

	delete p1;
	p1 = NULL;
	delete p2;
	p2 = NULL;

	system("pause");
	return 0;
}
Copy the code

VS CTRL + K then CTRL + C to comment out a piece of code

    // stack instantiation
	Coordinate p1;
	Coordinate *p2 = &p1;// set p2 to the address of p1. P2 can operate p1

	p2->m_iX = 10; // (*p2).m_ix =10;
	p2->m_iY = 20;

	cout << p1.m_iX << "," << (*p2).m_iY << endl;
Copy the code

You can see that p2 points to the address of P1. If you change P2, p1 will change.

Coding practice

Define a coordinate class, instantiate the coordinate object on the heap and give the coordinate (3,5), then print the coordinate information and destroy the coordinate object.

#include <iostream>
using namespace std;
class Coordinate
{
    
public:
	Coordinate(int x, int y)
	{
		// Set X,Y coordinates
		m_iX = x;
        m_iY = y;
	}
public:
	int m_iX;
	int m_iY;
};

int main(void)
{
    // Create object Pointers on the heap
	Coordinate *p = new Coordinate(3.5);
    // Print coordinates
	cout <<"("<<(*p).m_iX<<","<<(*p).m_iY<<")"<< endl;
    // Destroy the object pointer
	delete p;
    p = NULL;
	return 0;
}
Copy the code

C++ object member pointer

  • Object member: An object becomes a data member of another class
  • Object member pointer: A pointer to an object becomes a data member of another class

Coordinates:

class Coordinate
{
    
public:
	Coordinate(int x, int y);
public:
	int m_iX;
	int m_iY;
};
Copy the code

Line:

class Line {
public:
	Line();
	~Line();
private:
	Coordinate m_coorA; / / starting point
	Coordinate m_coorB; / / the end
};

Copy the code

Change an object member in line segment code to an object member pointer:

class Line {
public:
	Line();
	~Line();
private:
	Coordinate *m_pCoorA;
	Coordinate *m_pCoorB;
};
Copy the code

Initializers can still be used when initializing:

Line::line():m_pCoorA(NULL),m_pCoorB(NULL){
}
Copy the code

You can also use plain initializers in constructors:

Line::line()
{
	m_pCoorB = NULL;
	m_pCoorA = NULL;
}
Copy the code

General general initialization cases:

Line::line()
{
	m_pCoorB = new Coordinate(1.3);
	m_pCoorA = new Coordinate(5.6);
}
Line::~line()
{
	delete m_pCoorA;
	delete m_pCoorB;
}
Copy the code
int main(void)
{
	Line line(a);
	cout << sizeof(line) <<endl; / / 8
	return 0;
}
Copy the code

Object members differ from object member Pointers:

For object members, sizeof is the sum of all the objects in it.

Pointers account for four basic memory units under 32-bit compilers, and two Pointers account for eight memory units.

  • Object member pointer definition:Class name * pointer name;
  • If there is an object member pointer 1,2. Sizeof, which counts only the sum of memory occupied by Pointers.

The line object is created with only two 4-byte Pointers. The instantiated objects are in the heap; When destroyed, the heap is destroyed before the line object is released.

Object member pointer practices

4-5-ObjectMemberPointer

Coordinate.h

class Coordinate
{
public:
	Coordinate(int x, int y);
	~Coordinate();
public:
	int getX(a);
	int getY(a);
private:
	int m_iX;
	int m_iY;
};
Copy the code

Coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate(int x,int y)
{
	m_iX = x;
	m_iY = y;
	cout << "Coordinate()"<<m_iX<<","<<m_iY << endl;

}
Coordinate::~Coordinate()
{
	cout << "~Coordinate()" << m_iX << "," << m_iY << endl;
}

int Coordinate::getX() {
	return m_iX;
}
int Coordinate::getY(){
	return m_iY;
}
Copy the code

Line.h:

#include "Coordinate.h"

class Line {
public:
	Line(int x1,int y1,int x2,int y2);
	~Line();
	void setCoorA(int x, int y);
	void setCoorB(int x, int y);
	void printInfo(a);
private:
	Coordinate *m_pCoorA;
	Coordinate *m_pCoorB; // This is an object pointer to a coordinate class. It's just a pointer.
};
Copy the code

Line.cpp:

#include "Line.h"
#include <iostream>
using namespace std;

Line::Line(int x1,int y1,int x2,int y2){
	m_pCoorA = new Coordinate(x1, y1);
	m_pCoorB = new Coordinate(x2, y2);
	cout << "Line()" << endl;
}
Line::~Line() {
	delete m_pCoorA;
	m_pCoorA = NULL;
	delete m_pCoorB;
	m_pCoorB = NULL;
	cout << "~Line()" << endl;
}
void Line::printInfo() {
	cout << "("<<(*m_pCoorA).getX()<<","<< (*m_pCoorA).getY()<< ")" << endl;
	cout << "(" << m_pCoorB->getX() << "," << m_pCoorB->getY() << ")" << endl;
}
Copy the code

main.cpp:

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Line.h"
using namespace std;

int main(void)
{
	Line *p = new Line(1.2.3.4);
	p->printInfo();

	delete p;
	p = NULL;

	cout << sizeof(p) << endl;
	cout << sizeof(Line) << endl;
	system("pause");
	return 0;
}
Copy the code

Running results:

  • You can see that when a class contains pointer objects, instantiate pointer objects A,b first. Call the parent object’s constructor.
  • Pointer objects A and B are also destroyed in sequence before destruction. Finally the parent object is destroyed.
  • The pointer p occupies four memory Spaces, and the object Line contains two Pointers to object members, i.e., two Pointers with size 8.

Here we are using 32-bit compilation, as shown in the figure above.

As you can see, under 64-bit compilation, a pointer takes up 8 bytes.

In this case the object is destroyed in the same order as it was created.

Here we need to note the difference between object members and object member Pointers when they are created and when they are destroyed

This pointer

  • Pointer to the object
  • Object member pointer
  • This pointer

Example:

class Array
{
	public:
		Array(int_len){len = _len; }int getLen(a){returnlen; }void setLen(int _len){len = _len; }private:
		int len;
}
Copy the code

Parameter and data member, do not have the same name. Data members and parameters have similar names when they express the same meaning.

Question: What happens when a parameter has the same name as a data member?

class Array
{
	public:
		Array(intlen){len = len; }/ / wrong
		int getLen(a){returnlen; }void setLen(int len){len = len; }/ / wrong
	private:
		int len;
}
Copy the code

Neither the computer nor the human can tell whether a parameter is assigned to a member or a member is assigned to a parameter. I can’t tell the difference between two Len’s.

This pointer: a pointer to the object’s own data

Array arr1;  //this <-> &arr1
Array arr2;  //this <-> &arr2
Copy the code

The address represented by this depends on the current scope. This allows you to mark its own members and tell which is which with its parameters.

class Array
{
	public:
		Array(int len){this->len = len; }/ / for
		int getLen(a){returnlen; }void setLen(int len){this->len = len; }/ / for
	private:
		int len;
}
Copy the code

Object structure:

  • There are multiple objects, and member functions have only one copy of the code area.

How does a member function determine which object’s data member to call without passing arguments?

  • How do member functions access the corresponding object’s data members?
class Array
{
	public:
		Array(T *this.int len){this->len = len; }/ / for
		int getLen(T *this){return this->len; }void setLen(T *this.int len){this->len = len; }/ / for
	private:
		int len;
}
Copy the code

  • Use this to resolve different ARRs.
  • The compiler automatically adds the this pointer to the argument list of each member function.

The position of this pointer in the argument list (code practice)

Requirements:

Normal Version 1:

4-7-ThisPointerPosition

Array.h

class  Array
{
public:
	Array(int len);
	~ Array();

	void printAddr(a);
	void printArr(a);
	int getLen(a);
	void setLen(int val);
	void printInfo(a);
private:
	int m_iLen;
};
Copy the code

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array(int len)
{
	m_iLen = len;
	cout << "Array()" << endl;
}
Array::~Array() {
	cout << "~Array()" << endl;
}

void Array::setLen(int len) {
	m_iLen = len;
}
int Array::getLen() {
	return m_iLen;
}

void Array::printInfo() {

}
Copy the code

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(10);

	system("pause");
	return 0;
}
Copy the code

Changed: changed all m_iLen to len with the same parameter name, so that the human eye can no longer tell which is the data member and which is the parameter

To make the program look better (we can tell which is which), we introduce this.

Change the data member in array. h:

private:
	int len;
Copy the code

Changed array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array(int len)
{
	this->len = len;
	cout << "Array()" << endl;
}
Array::~Array() {
	cout << "~Array()" << endl;
}

void Array::setLen(int len) {
	this->len = len;
}
int Array::getLen() {
	return len;
}

void Array::printInfo() {

}
Copy the code

Main. CPP adds a print function that calls arr1.

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(10);
	cout << arr1.getLen() << endl;
	system("pause");
	return 0;
}
Copy the code

This pointer practice (2)

4-8-ThisPointerPositionLinkCall

Change printInfo() in array.h to:

Array printInfo(a);
Copy the code

Replace printInfo() in array.cpp with:

Array Array::printInfo() {
	cout << "len:" << len << endl;
	return *this; // This itself is a pointer, and the * becomes an object.
}
Copy the code

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(10);
	arr1.printInfo();
	system("pause");
	return 0;
}
Copy the code

PrintInfo is called normally, but does not show the value of returning this.

Because printInfo() returns the this pointer, it can be called chained.

arr1.printInfo().setLen(5);
cout << "len_after_set:" << arr1.getLen() << endl;
Copy the code

The printed results show that we have not successfully changed the value of ARr1.

Because the *this that we returned came out as another temporary object. This is a temporary object, not ARR1.

If you want it to be arr1, then the reference can be implemented.

Array.h

Array& printInfo(a);
Copy the code
Array& Array::printInfo() {
	cout << "len:" << len << endl;
	return *this; // This itself is a pointer, and the * becomes an object.
}
Copy the code

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(10);
	arr1.printInfo().setLen(5);
	cout << "len_after_set:" << arr1.getLen() << endl;
	system("pause");
	return 0;
}
Copy the code

As you can see, since it is a reference, arr1 is not destroyed, but is assigned a new value.

If we want to make chained calls longer, we simply give the setLen method a reference to this pointer as well.

4-8-ThisPointerPositionLinkCallTwo

Array.h

class  Array
{
public:
	 Array(int len);
	~ Array();

	void printAddr(a);
	void printArr(a);
	int getLen(a);
	Array& setLen(int val);
	Array& printInfo(a);
private:
	int len;
};
Copy the code

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array(int len )
{
	this->len = len;
	cout << "Array()" << endl;
}
Array::~Array() {
	cout << "~Array()" << endl;
}

Array& Array::setLen(int len) {
	this->len = len;
	return *this;
}
int Array::getLen() {
	return len;
}

// Add the reference before arr1
Array& Array::printInfo() {
	cout << "len:" << len << endl;
	return *this;// This itself is a pointer, and the * becomes an object.
}
Copy the code

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(10);
	// This returns the current object. So you can use "."
	arr1.printInfo().setLen(5).printInfo();
	system("pause");
	return 0;
}
Copy the code

Running results:

Pointer implementation version:

What if instead of returning a reference, we return a pointer?

  • Return typeArray &Instead ofArray *
  • willreturn *thisInstead ofreturn this
  • The user of the object.Change to the pointer operator->

The complete code is as follows: 4-8 – ThisPointerPositionLinkCallTwoByPointer

Array.h:

class  Array
{
public:
	 Array(int len);
	~ Array();
	void printAddr(a);
	void printArr(a);
	int getLen(a);
	Array* setLen(int val);
	Array* printInfo(a);
private:
	int len;
};
Copy the code

Array.cpp:

#include <iostream>
#include "Array.h"
using namespace std;

Array::Array(int len )
{
	this->len = len;
	cout << "Array()" << endl;
}
Array::~Array() {
	cout << "~Array()" << endl;
}

Array* Array::setLen(int len) {
	this->len = len;
	return this;
}
int Array::getLen() {
	return len;
}

Array* Array::printInfo() {
	cout << "len:" << len << endl;
	return this;// This is itself a pointer.
}
Copy the code

main.cpp:

#include <iostream>
#include <stdlib.h>
#include "Array.h"
using namespace std;

int main(void)
{
	Array arr1(10);
	// Since this returns a pointer to arr1, use "->"
	arr1.printInfo()->setLen(5)->printInfo();
	system("pause");
	return 0;
}
Copy the code

The final result is the same. Either a reference or a pointer can change the actual value.

The essence of the this pointer: corresponds to the address of the object

Print the value of this pointer in printInfo

Array.cpp:

Array* Array::printInfo() {
	cout << this << endl;
	return this;// This itself is a pointer, and the * becomes an object.
}
Copy the code

main.cpp:

int main(void)
{
	Array arr1(10);
	
	arr1.printInfo();
	cout << &arr1 << endl;
	system("pause");
	return 0;
}
Copy the code

Running results:

The this pointer does not need to be user-defined and is generated automatically by the compiler.

Constant object members and constant member functions

Const is back in business

Example:

class Coordinate
{
public:
	Coordinate(int x,int y);
private:
	const int m_iX;
	const int m_iY;
}

// Error:
Coordinate::Coordinate(int x,int y)
{
	m_iY =y;
	m_iX =x;
}

// Use an initializer list

Coordinate::Coordinate(int x,int y):m_iX(x),m_iY(y)
{
}
Copy the code

The data members of a class can be const, but so far we have been talking about data members of basic data types.

Constant object members: Object members are decorated by const

Line segments: No modification is allowed once the starting and ending points have been determined.

class Line
{
public:
	Line(int x1,int y1,int x2 ,int y2)
private:
	const Coordinate m_coorA;
	const Coordinate m_coorB;
}

// Initialize two objects using the initializer list

Line::Line(int x1,int y1,int x2 ,int y2):m_coorA(x1,y1),m_coorB(x2,y2)
{
	cout<< "Line" << endl;
}

/ / call:

int main(void)
{
	Line *p = new Line(2.1.6.4);

	delete p;
	p = NULL;
	return 0;
}
Copy the code

Const decorates member functions (constant member functions)

Example:

class Coordinate
{
public:
	Coordinate(int x,int y);
	void changeX(a) const; // constant member functions
	void changeX(a);
private:
	int m_iX;
	int m_iY;
}

// Define a constant member function
void Coordinate::changeX() const
{
	m_iX = 10;/ / error
};

// A normal function
void Coordinate::changeX() 
{
	m_iX = 20;
};
Copy the code

Consider: Why can’t a constant member function change the value of a data member?

The actual member function has a hidden argument, the this pointer.

The this pointer becomes a constant pointer, and changing data through a constant pointer is obviously not allowed.

Mutual overload:

	void changeX(a) const;
	void changeX(a); // both reloads
Copy the code

Q: Which one is called when you call: coordinate.changex ()?

A: The call is plain, nonconst.

Q: How about calling the const one?

A: The code is as follows

int main(void)
{
	// Instantiate the object with const
	const Coordinate coordinate(3.5);/ / object
	coordinate.changeX(); // Call a constant member function
	return 0;
}
Copy the code

A constant object calls a constant member function. Ordinary objects call ordinary member functions.

Constant object members and constant member function code practices

5-2-ConstantMemberFunction

Coordinate.h :

class Coordinate
{
public:
	Coordinate(int x, int y);
	~Coordinate();
public:
	int getX(a) const;// Declare the member function as a constant member function
	void setX(int x); SetX (Coordinate *this, int x)
	int getY(a) const;/ / same as above
	void setY(int y);
private:
	int m_iX;
	int m_iY;
};
Copy the code

Coordinate.cpp

#include <iostream>
#include "Coordinate.h"
using namespace std;

Coordinate::Coordinate(int x, int y)
{
	m_iX = x;
	m_iY = y;
	cout << "Coordinate()" << m_iX << "," << m_iY << endl;

}
Coordinate::~Coordinate()
{
	cout << "~Coordinate()" << m_iX << "," << m_iY << endl;
}

int Coordinate::getX() const{
	return m_iX;
}
void Coordinate::setX(int x) { 
	m_iX = x;
}
int Coordinate::getY() const{
	return m_iY;
}
void Coordinate::setY(int y) {
	m_iY = y;
}
Copy the code

Line.h:

#include "Coordinate.h"

class Line {
public:
	Line(int x1, int y1, int x2, int y2);
	~Line();
	void setCoorA(int x, int y);
	void setCoorB(int x, int y);
	void printInfo(a);
	void printInfo(a) const;// both reloads

private:
	const Coordinate m_coorA; // Coordinate const m_coorA;
	Coordinate m_coorB;
};
Copy the code

Line.cpp:

#include "Line.h"
#include <iostream>
using namespace std;

Line::Line(int x1, int y1, int x2, int y2) :m_coorA(x1, y1), m_coorB(x2, y2) {
	cout << "Line()" << endl;
}
Line::~Line() {
	cout << "~Line()" << endl;
}
void Line::setCoorA(int x, int y) {
	//m_coorA.setX(x); // This pointer is passed in setX
	//m_coorA.setX(y);
}
void Line::setCoorB(int x, int y) {
	m_coorB.setX(x);
	m_coorB.setY(y);
}
void Line::printInfo() {
	cout << "printInfo()" << endl;
	cout << "(" << m_coorA.getX() << "," << m_coorA.getY() << ")" << endl;
	cout << "(" << m_coorB.getX() << "," << m_coorB.getY() << ")" << endl;

}
void Line::printInfo() const{
	cout << "printInfo() const" << endl;
	cout << "(" << m_coorA.getX() << "," << m_coorA.getY() << ")" << endl;
	cout << "(" << m_coorB.getX() << "," << m_coorB.getY() << ")" << endl;
}
Copy the code

main.cpp

#include <stdlib.h>
#include <iostream>
#include <string>
#include "Line.h"
using namespace std;

int main(void)
{
	Line line(1.2.3.4);
	line.printInfo();// The call is normal

	const Line line2(1.2.3.4);
	line2.printInfo();// Call a constant member function
	
	system("pause");
	return 0;
}
Copy the code

void setX(int x); SetX (Coordinate *this, int x)
Copy the code

So when we define Coordinate *this, what we’re asking for is a pointer that has both write permission and read permission.

When we call m_coorA, we pass in an object with read permission only.

If we want the function to work, we just add const. SetX can’t be added, otherwise you can’t change x and y but getX and getY can be added.

	int getX(a) const;// Declare the member function as a constant member function
	int getY(a) const;// Const should be written at the end of function declarations
Copy the code

And then we synchronize const to the definition as well. Self-completion is omitted here. Comment out setX and setY.

int getX(const Coordinate *this) const;
Copy the code

This requires that we pass in a constant object.

  • A constant object can only call a constant member function.
  • Ordinary objects can call all member functions (non-member functions).

Consider: Why do we need const member functions?

We often define member functions of a class that do not change the data members of the class, that is, they are “read-only” functions, and some that modify the values of the data members of the class. Obviously, the readability of the program can be improved if functions that do not change their data members are identified with the const keyword. In fact, it can improve the reliability of the program, has been defined as a const member function, any attempt to modify the value of the data member, the compiler as an error.

Constant Pointers and constant references

Object Pointers and object references

class Coordinate
{
public:
	Coordinate(int x, int y);
public:
	int getX(a);
	int getY(a);
	void printInfo(a) const; // constant member functions
private:
	int m_iX;
	int m_iY;
};
Copy the code

Definition:

int Coordinate::getX(){
	return m_iX;
}

int Coordinate::getY() const{
	return m_iY;
}

void Coordinate::printInfo() const
{
	cout << "(" <<m_iX <<","<<m_iY <<")"<<endl;
}
Copy the code

Object reference & pointer to object

int main(void)
{
	Coordinate coor1(3.5);
	Coordinate &coor2 = coor1; // Alias a reference to an object
	Coordinate *pCoor = &coor1;// A pointer to an object.
	coor1.printInfo();
	coor2.printInfo(); // will also print the coordinates of coor1 (3,5)
	pCoor -> printInfo();
	return 0;
}
Copy the code

A constant pointer to an object and a constant reference to an object

int main(void)
{
	Coordinate coor1(3.5);
	const Coordinate &coor2 = coor1; // often: references to objects
	const Coordinate *pCoor = &coor1; // constant: a pointer to an object.
	coor1.printInfo(); // Common objects are used normally

	coor2.getX(); // Error, often referenced (this pointer with read permission only)
	// getX is defined without const, so it hides this inside and requires a read/write permission.
	
	// Only constant member functions can be called
	coor2.printInfo();

	pCoor -> getY(); / / error. Constant pointer (read-only only).
	// The hidden argument to getY requires that this be passed with read-write permission
	
	// Only constant member functions can be called
	pCoor -> printInfo();
	
	return 0;
}
Copy the code

A more complex example:

int main(a)
{
	Coordinate coor1(3.5);
	Coordinate coor2(7.9);

	// Define an object pointer
	Coordinate *const pCoor = &coor1; 
	// Note that const comes after *.
	// Once pCoor points to one object, it cannot point to other objects

	// The pointer cannot point to any other object, but the object to which the pointer itself points can be changed.
	// This is a pointer with read and write permissions. Restricted to the currently pointed object.
	pCoor ->getY(); / / right

	//pCoor is already const and cannot be modified
	pCoor = &coor2;

	//printInfo is a constant member function (a pointer that requires read permissions), whereas pCoor has read and write permissions.
	pCoor -> printInfo();

	return 0;
}
Copy the code

3. Easily confused by a constant pointer:

  • const *p -> *pYou can’t reassign
  • *const p -> pYou can’t reassign
  • const * const p -> *pandpYou can’t reassign

You cannot point a small permission to a large permission, but you can point a large permission to a small permission.

  • A regular object can only call a regular member function, not a normal member function
  • Ordinary objects can call regular member functions as well as ordinary member functions (with large permissions and small permissions).
  • Both constant Pointers and constant references can only call the constant member functions of an object. (Lower permission to lower permission)
  • An object can have more than one object constant reference (the subname itself cannot be changed, but it can have multiple aliases)

Unit to consolidate

Define a coordinate class, instantiate the coordinate class constant object on the stack, and give the coordinate (3,5), then define constant reference, constant pointer, finally use the object, reference, pointer to print the coordinate information by calling the information printing function respectively.

#include <iostream>
using namespace std;
class Coordinate
{
    
public:
	Coordinate(int x, int y)
	{
		// Set X,Y coordinates
	    m_iX = x;
        m_iY = y;
	}
    // Implement a constant member function
	void printInfo(a) const
	{
	    cout << "("<<m_iX<<","<<m_iY<<")"<<endl;
	}
public:
	int m_iX;
	int m_iY;
};


int main(void)
{
	const Coordinate coor(3.5);

	// create a constant pointer p
    const Coordinate *p = &coor;
    // create a constant reference to c
    const Coordinate &c = coor;
	
	coor.printInfo();
	p->printInfo();
	c.printInfo();  
	
	return 0;
}
Copy the code

Maze program (Get out of the maze)

Out of rules (algorithms) :

  • Left hand rule & right hand rule
  • Rule: Keep your hands on the wall at all times (walk on the wall at home in the dark)
  • Result: Out of the maze

Situation 1(recommended design) : There is an in and an out.

Situation 2: The entrance and exit are one)

Architectural description

There are two classes involved: MazeMap and Person

Two-dimensional arrays:

1 is the wall, 0 is the road, you decide.

Maze class (MazeMap)

Data member:

- Wall character - Path character - Maze arrayCopy the code

Member functions:

- Constructor - Data encapsulation function - Maze loop function - Maze boundary checking functionCopy the code

Human (MazePerson)

Data member:

- Person's character - person's orientation - person's current position (set in the entrance) - a position in front of the person (the person walks, the front position is erased, the back position is drawn) - person's speedCopy the code

Member functions:

- Constructors - Data encapsulation functions - functions that go in different directions (up, down, left and right) - turn functions - start functionsCopy the code

Console animation control:

/* * Function name: gotoxy * function function: determine the output position of characters in the console * list of functions: * x: x * y: y */

void MazePerson::gotoxy(int x, int y)   
{   
	COORD cd;    
	cd.X   =   x; 
	cd.Y   =   y;
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  
	SetConsoleCursorPosition(handle,cd); // Move the cursor to the appropriate position
};
Copy the code

First, we need to define a maze. Maze is a two-dimensional array, WaLL is WaLL, and Road is Road.

Draw the maze Cout. Given a two-dimensional array of mazes, instantiate a maze object and set the two-dimensional array in using the setMazeMap function. SetMazeWall tells the computer what the wall should be. Once set up, draw the maze.

For maze runners, set the person’s position at the entrance. Set the speed of the person, set the character shape of the person.

People start to move.

Matters needing attention:

  • Enumeration type: direction (up, down, left, and right)
  • Constant definition: macro definition & const

A sense of achievement comes from overcoming difficulties

Maze code implementation

To be continued, to be added later.