Chapter 3 - subsection 3.3 of learning notes of C + + new classic course (important)

Keywords: C++ Back-end

  This blog will record: notes of relevant knowledge points of class!

(this has been learned once when learning the basic course of C + +, which is just a brief review here again)

This knowledge is divided into the following five points:

  1, Implement the member function inline in the class definition
  2, const at the end of member function
  3, mutable keyword
  4, Returns a reference to the object itself   as well as   this pointer
  5, static member

  1, Implement the member function inline in the class definition:

         I have summarized the basic details of inline function keywords in this blog. If you are not familiar with it, you might as well take a look at my blog:

Chapter 2 - Section 2.6 2 of learning notes of C + + new classic course, inline function

         That is, the compiler will directly replace the statement called by the inline function with the all statement in the function body of the function

#include<iostream>
using namespace std;
//Inline inline function
inline void func(int a) { cout << a << endl; }
int main(void) {
	func(5);//Directly use the statement cout < < a < < endl in the function body; Replace func(5); This statement!
	return 0;
}

         The purpose of the inline keyword is to improve the efficiency of your program. Because the statement called by the inline function will be replaced by the all statement in the corresponding function body at the compilation stage, so the subsequent sequence does not involve any problems such as function transfer and calculation.

         Now, I summarize how to implement inline inline functions in class definitions:

         The function that directly writes the specific implementation of the function in the class. h header file is the inline inline function in the class (in other words, this function may be treated as an inline function by the compiler. Because whether a function can really become an inline function depends on the decision of the compiler itself, which we can't control. Our developers add inline to a function is just a suggestion to the compiler, and whether the compiler adopts it or not depends on itself.)

For example:

#ifndef __TIME_H__
#define __TIME_H__
#include<iostream>
using namespace std;
class Time {
public:
	int m_Hour;//Time
	int m_Minute;//branch
	int m_Second;//second
public:
	Time(int h,int m,int s) :m_Hour(h), m_Minute(m), m_Second(s){}
public:
    //This is how inline functions in classes are written
    void func(int h) { this->m_Hour = h; }//==>inline void func(int h) {this->m_Hour = h;}
};
#endif

  2, Const at the end of member function (i.e. constant (constant / const) member function):

         In fact, I have summarized this part in detail in a previous article, so I won't repeat it here. If you forget, you can see my blog below:

Briefly summarize the use of constant (constant / const) member functions and constant objects

         Note the usage scenario where const is added to the end of a function: const can only be added to the end of a member function and become a constant member function. It cannot be added to the end of an ordinary function. Adding const to the end of an ordinary function is wrong! Compilation fails!

void normal_Func()const{}//wrong!

 

  3, Mutable (Translation: changeable and changeable) keyword (the relationship between const constant keyword and const constant keyword is antonym)

         In fact, the mutable keyword is introduced to break through the previous restriction of const keyword.

Seriously: mutable can break through   const constant member functions and constant objects cannot modify the non static member variables of all in the class.

To put it bluntly, a mutable modified member variable can always be modified! Even in const constant member functions, this mutable modified member variable can also be modified!

(because mutable, the English translation tells us that it means easy to change, ha ha ha)

person_name.h

#ifndef __PERSON_NAME_H__
#define __PERSON_NAME_H__
#include<iostream>
#include<string>
using namespace std;
class person_Name {
private:
	string m_Name;
public:
	person_Name() :m_Name("") {}
	person_Name(string name):m_Name(name){}
	string getName() {
		return this->m_Name;
	}
};
#endif

Person.h

#ifndef __PERSON_H__
#define __PERSON_H__
#include<iostream>
#include"person_name.h"
using namespace std;
class Person {
public:
	mutable int m_Age;
	mutable person_Name m_Name;
public:
	static int m_girlFriendNums;
	//Of course, member variables of static type can only be declared inside the class and initialized outside the class
public:
	Person(int age,const person_Name& name):m_Age(age), m_Name(name){}
	void showInfo() const;
	void showInfo();
};
#endif

Person.cpp

#include"Person.h"
int Person::m_girlFriendNums = 0;
void Person::showInfo() const {
	cout<< (m_Age = 1998) <<endl;//Modify the member variable modified by mutable keyword in constant member function
	cout << m_girlFriendNums << endl;
	cout << this->m_Name.getName() << endl;
}
void Person::showInfo(){
	cout<< (m_Age = 1999) <<endl;//Modify the member variable modified by mutable keyword in non member function
	cout << m_girlFriendNums << endl;
	cout << this->m_Name.getName() << endl;
}

main.cpp

#include<iostream>
#include"Person.h"
using namespace std;
int main(void) {
	Person const p1(1, person_Name("lyf"));
	p1.showInfo();
    //1998 0 lyf
	Person p2(2,person_Name("lzf"));
	p2.showInfo();
    //1999 0 lzf
	return 0;
}

 

4, Return the reference of the object itself and the this pointer:

         To understand the reference of the object itself, first you have to know what is this pointer?

The so-called this pointer meets the following two conditions:

① this pointer is a pointer constant hidden in c + + classes

(as the name suggests, the pointer is a constant, that is, the address of the object pointed to by this pointer is immutable! It must point to the object calling a member function or a member variable in the class, and cannot point to other objects. Therefore, each data between each object is independent of each other.)

//Pointer constants of type int like the following:
int a = 1,b = 2;
int* const this_s= &a;
this_s = &b;//wrong ×! Because a pointer constant is a pointer (the address of the object pointed to), it means a constant, that is, it cannot be modified
//If you modify it here, you will report an error!

② The this pointer itself points to an object that calls a member function or a member variable of the class.

wjw teacher said a sentence that I think is particularly wonderful:

         From the compiler's point of view, any access to members of a class (member variables and member functions) is regarded as an implicit call to the this pointer!

So, what is an implicit call? Look at the following code:

//Still take the above Person class as an example
//Inside of class
Person& add_Age(int addage){
	m_Age += addage;//==> this->m_Age += addage; 
	return *this;
}
//==>It's equivalent to
Person& add_Age(Person* const this,int addage){
//Of course, this is just a piece of pseudo code. This is the keyword. You can't write it like this. Hahaha
	this->m_Age += addage;//==> m_Age += addage; 
	return *this;
}
//This is the code about this pointer hidden by the compiler
//Outside (outside of class)
Person p(20,person_Name("tjr"));
p.add_Age(3);//==>p.add_Age(&p,3);
//output: 23 0 lzf

The reference of the object itself is actually an alias for the object itself, or an alias for * this (the essence is the same!)

For the code in the example just given:

//Address of the object calling the function = = space pointed to by this pointer = = address of the reference of the returned object itself
&p == this == &( p.add_Age(3) )

I believe that through the above code explanation, you understand what is the reference of the return object itself and the this pointer.

Another important question is: why should we return a reference to the object itself?

Because returning a reference to the object itself allows us to do something similar to   a+b+c+d... Such a chain operation, that is:

Return the reference of the object itself, which is in line with the idea of chain programming.

For example, see the following code:

//Each p2.add_Age(3) = = one p2 object
//It's just that this is the p2 object after adding 3 to age
p2.add_Age(3).add_Age(3).add_Age(3).showInfo();
//==>
p2.add_Age(3);
p2.add_Age(3);
p2.add_Age(3);
p2.showInfo();
//==>
p2.add_Age(3*3).showInfo();
//==>
p2.add_Age(3*3);
p2.showInfo();

If you just return the Person object itself, you don't return its reference

Person Person::add_Age(int addage) {
	m_Age += addage;
	return *this;
}

Then the compiler will assign the value of * this Person object to an anonymous Person object (first open up space in the stack area to store the anonymous object, and then assign do), and then return the anonymous Person object   Go back. Then the address of the object pointed to by this and the address of the object returned by this return are two yards!

That is:

//Address of the object calling this function = = the space pointed to by this pointer! = the address of the returned object itself
&p == this != &( p.add_Age(3) )

At this time, you can't do chain programming for the anonymous object stored in the new address, that is, you can't

a+b+c+d.. do things like this. For example:

p2.add_Age(3).add_Age(3).add_Age(3).showInfo();//×!
//Wrong! p2.add returned_ Age (3) is not the original p2 at all, because the address of the anonymous object of return is different from that of p2
//so can't do continuous chain programming!

Supplementary knowledge: there are 3 precautions for the use of this pointer.

① this pointer can only be used in member functions, not global functions or static functions!

② In const member functions, this pointer is a constant pointer.

         In the example of this blog, that is, (const Person* const this;) because this pointer is a pointer constant, you just can't modify the object it points to, but you can modify the content of the object it points to. When this is used in a const constant member function, the constant member function specifies that the members of the class must not be modified in its function body (member function or member variable). Therefore, at this time, the this pointer in the function will smoothly become a constant pointer (because even the content of the object pointed to by this can not be modified). In summary, the this pointer is a constant pointer constant.

③ When using a member variable in a member function, you'd better add a this pointer (of course, you can also avoid this problem by standardizing the name of the member variable you write), otherwise there may be a case where the passed in parameter has the same name as the member variable. For example:

Person& Person::add_Age(int m_Age) {
	m_Age += m_Age;
    //If the passed in parameter has the same name as the member variable in my class
    //The compiler will consider this m_Age is the parameter you pass in, that is, the parameter you pass in on the left and right, not the member variable m_Age;
    //Then the logic will go wrong! You can't achieve the purpose of writing this function!
	return *this;
}
p2.add_Age(3).add_Age(3).add_Age(3).showInfo();
//result: 20 0 lzf
//It can be seen that what I said above is right!

Person& Person::add_Age(int m_Age) {
	this->m_Age += m_Age;//When you add this - > to call M_ When age is a member variable
    //There will be no case where the passed in parameter has the same name as the member variable
	return *this;
}
p2.add_Age(3).add_Age(3).add_Age(3).showInfo();
//result: 29  0 lzf
//It can be seen that what I said above is right!

         Although my explanation is a little verbose, I believe that through the above detailed explanation, you have learned two small but important knowledge points: what is the reference of the return object itself and the this pointer.

5, static members:

                 (it's an important concept and one that I often forget. Be sure to study and summarize it carefully!)

         First of all, let me take you back to the concept of static variables. Static variables are divided into local and global.

(Note: when you define a static variable, if you do not assign an initial value, the compiler will assign an initial value of 0 to the static variable by default, and the static variables are stored in the static storage area.)

static int abc;//The compiler assigns abc an initial value of 0 by default
cout << abc << endl;//    0

         ① Local static variable: it will be initialized only once, and then updated with the external call to the function, so as to retain the latest value, that is, it will only retain the value of the variable when the function was called last time.

(the so-called local is actually because the variable is in the function body, so it is a local variable)

(the so-called static is static when the static keyword is added. Static means that it is initialized only once.)

void func() {
	int static abc = 1;//Local static variable = = > static int ABC = 1;
	abc++;
	cout << abc << "\t";
}
//In main.cpp
for (int i = 0; i < 5; i++) { func(); }
//result: 2 3 4 5 6
 First it's 1, then++bring abc Change to 2, then output 2
 Then the last time the function was called abc The value is 2, so 2 is used++bring abc Becomes 3, then outputs 3
 Then the last time the function was called abc The value is 3, so 3 is used++bring abc Becomes 4, then outputs 4
 Then the last time the function was called abc The value is 4, so 4 is used++bring abc Becomes 5, and then outputs 5
 Then the last time the function was called abc The value is 5, so use 5++bring abc Becomes 6, then outputs 6
so To sum up, result: 2 3 4 5 6

         ② Global static variable: in a. cpp source file   A static static variable defined outside any function and whose scope is limited to the. cpp source file that defines the global static variable is a global static variable.

(other. cpp source files cannot access the global static variable even with the extern keyword.)

//A static static variable defined outside any function and whose scope is only in this. cpp source file is a global static variable
static int g_abc = 998;// ==> int static g_abc = 998;


//Variables defined outside any function are global variables (which can be used by other. cpp source files through the extern keyword)
int g_a = 1998;

In this case,

For other. cpp source files, use extern int g_abc; The global static variable G is also inaccessible_ abc. But,

Other. cpp source files can use extern int g_a; To access the global variable g_a;

         The above is what we learned about the static keyword in C language. What is the function of static in C + + classes? Let's have a look! We might as well understand this "new" knowledge point through code:

//Modify the showInfo() function of the Person class defined above to:
void Person::showInfo(){
	cout << "m_Age = " << m_Age << "\t";
	cout << "m_Name = " << this->m_Name.getName() << endl;
}
//And create two objects of Person class in main.cpp
Person p1(21, person_Name("lzf"));
p1.showInfo();
// m_Age = 21  m_Name = lzf 21 m belonging to object p1_ The age member variable "lzf" belongs to m of object p1_ Name member variable
Person p2(22, person_Name("lyf"));
p2.showInfo();
// m_Age = 22  m_Name = lyf 22 m belonging to object p2_ The age member variable "lyf" belongs to m of object p2_ Name member variable

It can be seen that each object has its own data. The age of p1 and p2 are irrelevant, and the name of p1 and p2 are also irrelevant. The data stored by these 2 objects occupy different memory addresses.

View the address by intercepting the breakpoint on VS2019: (you can verify my explanation above)

  Well, some students will ask, is there a public object that only belongs to the whole class?

Answer: static static member variables exist (the focus of this section)

         Static static member: member variable or member function modified with static. My own understanding of static member (member variable or member function) is summarized in one word:

         Cross object (static members span objects, are shared, and are public! They exist across all objects in the class)

Explanation: Ordinary members have their own copy of memory address for each object, while static members have only one copy of memory address in the class, or share the same copy!

characteristic:

         ① The member variable of static static does not belong to a specific object, but belongs to the whole class (the only one). Once we modify the static member variable in an object, we can see the updated static member variable in other objects. Moreover, member variables of static type can only:

1) Declare in class (static keyword shall be added when declaring, and memory shall not be allocated)

2) Initialize outside the class (or define it. At this time, you can't add the static keyword to allocate memory)

Format: name of the class to which the type of static variable belongs:: variable name = initial value;)

         Access method of static member variables:

1) It can be accessed or modified by class name:: static member variable name

2) Access or modify any object by its name, static member variable name

(because the compiler will not allocate memory for static member variables when they are in the class, so we can't initialize them. There is no memory space. Do you want to make them rough? Where do you store the initial values you give them, right?)

Please look at the following code: (continue to write the code with the Person class in mutable)

//Because I have defined a static member variable m in the class_ girlFriendNums
public:
    //Declare static member variables (no memory allocated)
	static int m_girlFriendNums;//This is just a static member m declared within the class_ Just girlfriendnums
    //Because member variables of static type can only be declared inside the class and initialized outside the class

//so initializes the static member variable m outside the class_ girlFriendNums
    //Define or to initialize the static member variable (allocate memory). If you don't give it an initial value at this time, the compiler will default to 0
int Person::m_girlFriendNums = 8;//Give m_ Girlfriendnum has an initial value of 8 (out of class initialization)

//Then write the following code in main.cpp:
int main(void) {
	Person p1(21, person_Name("lzf"));
	p1.m_girlFriendNums += 1;//When a static member variable is modified through a specific object, the public data will be modified
	p1.showInfo();
	Person p2(22, person_Name("lyf"));
	p2.showInfo();
    //You can also access or modify it through class name:: static member variable name!
    Person::m_girlFriendNums = 7;
    p1.showInfo();
    p2.showInfo();
	return 0;
}

  Operation results:

          ② The member function of static static does not belong to a specific object, but belongs to the whole class (the only one). Once we modify the static member function in an object, we can see the updated static member function in other objects. Moreover, static member functions can only access / modify static member variables, but not ordinary type member variables.

Explanation: that is, static member functions cannot access / modify member variables that do not span objects (that is, different objects have independent memory to store corresponding member variables), so that is, non static member variables cannot be accessed, You can remember that static member functions can only modify static member variables, not non static member variables

(memorizing this one is enough!!!)

Member functions of type static:

1) Declare in class (. h header file) (add static keyword when declaring)

2) It is implemented outside the class (. cpp source file) (or defined. At this time, the static keyword cannot be added before the function return value type)

Format: name of the class to which the function return value type belongs:: function name (corresponding to the declared formal parameter table) {...}

         Access method of static member function:

1) It can be accessed or modified through class name:: static member function name (corresponding parameter table)

2) Access or modify any object by its name, static member function name (corresponding parameter table)

See the following code:

//Define a static member function static void reviseAge(int age) in the class;
//Person.h plus:
public:
    static void reviseAge(int age);
//Add the following to Person.cpp:
void  Person::reviseAge(int age) {
	m_girlFriendNums = age;
    //This static member function will the static member variable M_ The only value of girlfriendnum is changed to age
    //m_Age = 0;// Wrong! Because static member functions can only access static member variables
    //m_Name = person_Name("tjr");// Wrong! Because static member functions can only access static member variables
}
//Then write the following code in main.cpp:
int main(void) {
    Person p1(21, person_Name("lzf"));
	p1.m_girlFriendNums += 1;
	p1.reviseAge(111);
	p1.showInfo();
	Person p2(22, person_Name("lyf"));
	p1.reviseAge(222);
	p2.showInfo();
	Person::m_girlFriendNums = 7;
	p1.showInfo();
	p2.showInfo();
	Person::reviseAge(1);
	p1.showInfo();
	p2.showInfo();
	return 0;
}

  Operation results:

         Finally, through a few lines of code, verify again whether static member variables and static member functions are really the only part in the class. There is only one memory data, which is public and public across all objects?

Based on the above Person class code, please see the following code:

//Add a line to the static member function reviseAge() in Person.cpp to output the test code:
void  Person::reviseAge(int age) {
	m_girlFriendNums = age;
	cout << "Static member variable at this call m_girlFriendNums = " << m_girlFriendNums << endl;
}
//Write the following code in main.cpp:
int main(void) {
	Person p1(21, person_Name("lzf"));
	Person p2(22, person_Name("lyf"));
    //Static member variable m_ The default value of girlfriendnum is set to 8 
	cout <<"Person::m_girlFriendNums = "<< Person::m_girlFriendNums <<
		" &Person::m_girlFriendNums = "<< &Person::m_girlFriendNums <<endl;
	cout <<"p1.m_girlFriendNums = "<< p1.m_girlFriendNums << 
		" &p1.m_girlFriendNums = " << &p1.m_girlFriendNums << endl;
	cout <<"p2.m_girlFriendNums = "<< p2.m_girlFriendNums << 
		" &p2.m_girlFriendNums = " << &p2.m_girlFriendNums << endl;
	Person::reviseAge(0);
	p1.reviseAge(1);
	p2.reviseAge(2);
    return 0;
}

Operation results:

        

         OK, so the above is the learning notes of the content I reviewed in this important section 3.3. I hope you can understand and digest it. I also hope you can remember these small details. Come on, we are all on the way to coding~

Posted by urgido on Sat, 06 Nov 2021 08:04:11 -0700