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 type
Array &
Instead ofArray *
- will
return *this
Instead 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
->*p
You can’t reassign*const p
->p
You can’t reassignconst * const p
->*p
andp
You 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.