[C++] Classes and Objects II [Detailed explanation of ten thousand words in simple terms]

Classes and Objects II



1. Six default member functions of the class

If there are no members in a class, it is referred to asempty class< a i=4> .

class Date {
    
    };

Is there really nothing in the empty class? No, when nothing is written in any class, the compiler will automatically generate the following 6 default member functions .

Default member function:The user does not implement it explicitly [can only be generated without writing a compiler] , the member function generated by the compiler is called the default member function.

Insert image description here



2. Constructor

Preface: The origin and introduction of the constructor

What problems will occur if there is no initialization?

If there is no initialization, it will cause problems with wild pointers and random values.
Insert image description here
Insert image description here



Summary of problems that may arise during initialization in C language:

    1. Initialization is easy to forget
class Date
{
    
    
public:
 void Init(int year, int month, int day)    //函数初始化
 {
    
    
 _year = year;
 _month = month;
 _day = day;
 }
 
 void Print()
 {
    
    
 cout << _year << "-" << _month << "-" << _day << endl;
 }
 
private:
 int _year;
 int _month;
 int _day;
};

int main()
{
    
    
 Date d1;
 d1.Init(2022, 7, 5);
 d1.Print();
 Date d2;
 d2.Init(2022, 7, 6);
 d2.Print();
 return 0;
}
    1. In C language, it must be initialized every time. For the Date class, you can set the date for the object through the Init public method, but if you call this method to set the information every time you create an object, , It’s a bit troublesome .

Can the information be set when the object is created?


C++ improvement: constructor (function automatic initialization).

The constructor embeds the initialization into the class, so that when the class object is created, the initialization is automatically called [that is, the default constructor]



(1) Concept of constructor function

  1. Constructor is a special member function

  2. The name is the same as the class name and is automatically called by the compiler when creating a class type object.

  3. to ensure that each data member has an appropriate initial value

  4. and are called only once during the entire lifetime of the object .



(2) Characteristics of constructor

The constructor is a special member function. It should be noted that although the name of the constructor is called constructor, the main task of the constructor is It does not create an object by opening a space, but initializes the object.


Its characteristics are as follows:


  1. The function name is the same as the class name.


  2. No return value . 【 No need to write void


  3. When the object is instantiated the compiler automatically calls the corresponding constructor.

    Built-in types are not processed by the compiler by default

    Custom type calls default constructor

[ If explicitly defines the constructor, the compiler will call the explicitly defined constructor and will no longer automatically generate it. Constructor. 】


  1. Construction function Can be loaded. ( As shown below:without referencestructure,constructionstructure )
class Date
 {
    
    
  public:
      // 1.无参构造函数
      Date()
     {
    
    }
  
      // 2.带参构造函数
      Date(int year, int month, int day)
     {
    
    
          _year = year;
          _month = month;
          _day = day;
     }
     
  private:
      int _year;
      int _month;
      int _day;
 };
  
  void TestDate()
 {
    
    
      Date d1; // 调用无参构造函数     
      // 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
     
      Date d2(2015, 1, 1); // 调用带参的构造函数
  
     
      // 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
      // warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)
      Date d3();
 }


★ The difference between constructor and function declaration

  • No ginseng

    1. Constructor: Date d1; // has no parameters and cannot add ()
    2. Function declaration: Date d1(); //() function call operator

  • With ginseng

    1. Constructor: Date d1 (2023, 10, 19); // Only according to the default parameters, < a i=3>gives the corresponding initialization value
    2. Function declaration: Date d1 (int, int, int); // Function declaration, Parameters must have type declaration


  1. If there is no explicitly defined constructor in the class, the C++ compiler will automatically generate a default constructor without parameters.
    The compiler will no longer generate once explicitly defined by the user.
class Date
 {
    
    
  public:
 /*
 // 如果用户显式定义了构造函数,编译器将不再生成
 Date(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 */


 void Print()
 {
    
    
 cout << _year << "-" << _month << "-" << _day << endl;
 }
  
  
  private:
 int _year;
 int _month;
 int _day;
 };
  
  
  int main()
 {
    
    
 // 将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数
 // 将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再生成
 // 无参构造函数,放开后报错:error C2512: “Date”: 没有合适的默认构造函数可用
 Date d1;
 return 0;
 }


  1. Default constructor: For built-in types, the compiler does not process it by default; for custom types, the compiler calls the default constructor.
  • About the default member functions generated by the compiler:

    Many children will have doubts:If the constructor is not implemented, the compiler will generate a default constructor. But it seems that the default constructor is useless?

    The d object calls the default constructor generated by the compiler,But the d object _year/_month/_day is still a random value. In other words, the default constructor generated by the compiler is of no use? ?

    • answer:

    • C++ divides types into built-in types (basic types) and custom types.

    • Built-in type is the data type provided by language, such as: int/char/ . Self-defined type means we use class/struct/union, etc.Custom type ..., Pointer

      Date* p is also a built-in type, but it just points to different .

    • Look at the following program, and you will find thatThe compiler generates a default constructor that calls its default member function for the custom type member _t.

    Default constructor: For built-in types, the compiler does not process it by default; for custom types, the compiler calls the default constructor.
    Insert image description here

瀻结 :

  1. Under normal circumstances, we have to write the constructor ourselves

  2. For built-in types, are not processed by the default compiler, Initialize the default value when declaring it in the class (give the default value).

    The members are allcustom types, or default values ​​are given when declaring can consider letting the compiler generate the constructor itself. ,


class Time
{
    
    
public:
 Time()
 {
    
    
 cout << "Time()" << endl;
 _hour = 0;
 _minute = 0;
 _second = 0;
 }
 
private:
 int _hour;
 int _minute;
 int _second;
};

class Date
{
    
    
private:
 // 基本类型(内置类型)
 int _year;
 int _month;
 int _day;
 // 自定义类型
 Time _t;
};

int main()
{
    
    
 Date d;
 return 0;
}
  1. The defect of non-initialization of built-in type members in C++11 has been patched That is:Built-in type member variables can be initialized to default values ​​(to default values) when declared in a class.
class Time
{
    
    
public:
 Time()     //自定义类型 调用构造函数
 {
    
    
 cout << "Time()" << endl;
 _hour = 0;
 _minute = 0;
 _second = 0;
 }
 
private:
 int _hour;
 int _minute;
 int _second;
};

class Date
{
    
    
private:
 // 基本类型(内置类型) //内置类型成员变量在类中声明时可以给默认值进行初始化
 int _year = 1970;   //相当于声明(并没有开辟空间),而不是定义
 int _month = 1;
 int _day = 1;
 
 // 自定义类型
 Time _t;
};

int main()
{
    
    
 Date d;
 return 0;
}

[Tips: Generally, updates are only forward compatible. Don't dare to make changes to the original version, for fear that if you make the wrong change, the original code will be incompatible. Therefore, they are all in the form of patches and are compatible with the previous code]



  1. The constructor of no parameters and the constructor of full default are both calledThere can only be one default constructor and , Default constructor

    Note:No-argument constructor, Full default constructor, We did not write the constructor generated by default by the compiler, it can be considered as default constructor< /span> No need to pass parameters => Default constructor . 【

class Date
{
    
    
public:
 Date()
 {
    
    
 _year = 1900;
 _month = 1;
 _day = 1;
 }
 
 Date(int year = 1900, int month = 1, int day = 1)
 {
    
    
 _year = year;
 _month = month;
 _day = day;
 }
 
private:
 int _year;
 int _month;
 int _day;
};

// 以下测试函数能通过编译吗?   //不能,默认构造函数只能有一个
void Test()
{
    
    
 Date d1;
}


  1. Case:Separation of declaration and definition (X)Default parameters cannot be declared and defined at the same time (for fear of inconsistent , It is stipulated that it can only be declared to ), and private cannot be accessed during initialization of built-in types]


3. Destructor

Preface: Why destructors are produced and the introduction of destructors

Function destruction is also something that is often forgotten, which can lead tomemory leakage problems. The compiler cannot detect the memory leak problem and reports an error.

Therefore, the destruction information is also embedded into the class, and the compiler automatically calls the corresponding destructor (destroy).



(1) Destructor concept:

Contrary to the function of the constructor, the destructor does not complete the destruction of the object itself. The local object destruction work is completed by the compiler. When the object is destroyed, the destructor will be automatically called to complete the cleanup of the resources in the object.


(1) The space opening and destruction of objects and the opening and destruction of resources in objects

  • Space creation and destruction of objects

    The space development and destruction of objects is carried out along with the development and destruction of the system (stack frame). The space is opened when the stack frame is constructed. When the function call ends and the function main is destroyed, it is also destroyed. [Then the order in which they open, construct, destroy and destruct is the same as the order of the stack (last in, first out)].

[This is only the development of the object's space memory. The development and cleanup of resources in the object also need to be carried out by the constructor and destructor. 】

  • Development and destruction of resources in objects

    Regarding the dynamic development and destruction of memory resources, you have to use constructors and destructors.

    Open: Constructor (Although the constructor is called a constructor, it is also responsible forinitialization.)

    Destruction: destructor (destroy)

Insert image description here



(2) Characteristics

The destructor is a special member function with the following characteristics:

  1. The destructor name is preceded bythe class name with characters~.

  2. No parameters and no return value type. [This way the function will not be overloaded]

  3. A class can only have one destructor. If is not explicitly defined, the system will automatically generate a default destructor. Note: The destructor cannot be overloaded

  4. When the object life cycle ends, the C++ compilation system automatically calls the destructor.

    The memory space cannot be released [in some cases (such as iterators), the system does not dare to make decisions], If there is dynamically opened Resource , you need to build the destructor yourself.

  5. Regarding the destructor automatically generated by the compiler, will it accomplish something? In the following program, we will see that the default destructor generated by the compiler calls its destructor for a custom type member.

class Time
{
    
    
public:
 ~Time()
 {
    
    
 cout << "~Time()" << endl;
 }
private:
 int _hour;
 int _minute;
 int _second;
};
class Date
{
    
    
private:
 // 基本类型(内置类型)
 int _year = 1970;
 int _month = 1;
 int _day = 1;
 // 自定义类型
 Time _t;
};
int main()
{
    
    
 Date d;
 return 0;
}

Output after the program finishes running: ~Time()

There is no object of Time class directly created in the main method. Why is the destructor of Time class called in the end?

Because: the Date object d is created in the main method, and d contains 4 member variables, of which _year, _month, and _day are built-in type members. There is no need to clean up resources when they are destroyed. Finally, the system can directly recycle their memory. ;

And _t is a Time class object, so when d is destroyed, the _t object of the Time class contained inside it must be destroyed, so the destructor of the Time class must be called.

But:
[The destructor of the Time class cannot be directly called in the main function. What is actually to be released is the Date class object, so compile The compiler will call the destructor of the Date class, and Date is not provided explicitly, the compiler will generate a default destructor for the Date class, with the purpose of calling the destructor of the Time class internally, that is, when the Date object is destroyed When doing this, make sure that every custom object inside it can be destroyed correctly]

The main function does not directly call the Time class destructor, but explicitly calls the default destructor generated by the compiler for the Date class.

【★ Note: The destructor of that class is called when an object of that class is created, and the destructor of that class is called when an object of that class is destroyed< a i=2>】


  1. If there are no resources in the classApply for resources [Whether there is application for resources to dynamically open memory is a criterion for whether you need to manually build a destructor] When , the destructor does not need to be written, and the default destructor generated by the compiler is directly used.

    For example, Date class;When there is a resource application, it must be written, otherwise it will cause resource leakage, such as Stack class.



(3) C and CPP [Comparison of examples of adding constructors and destructors]

Insert image description here



4. Copy constructor

Preface: When creating an object, you want to create a new object that is the same as an existing object.

  • Problem recurrence

  • Native version in C

    wants to create a new object that is the same as an existing object, but what problems will occur during the following creation process?
    Insert image description here
    But when calling class Stack stk1, can it still copy parameters like the above class Date()?

  • Problem analysis: If you have your own space,shallow copy/value copy will appear Risk of secondary destruction.

    Pass parameters by value (value copy), the formal parameter st (a temporary copy of st1 (the formal parameter has no effect on the actual parameter), since it is a copy, then. a pointers all point to the same address)

    1. st has func2 will automatically call the destructor once [temporary copy (formal parameters have no effect on actual parameters) a in st Destruction and setting nullPtr to null will not affect the pointer a in the original actual parameter still pointing to the original address].
    2. When Stack st1 exits the main function, the destructor will be automatically called again.

For Stack, it is still shallow copy, and the pointer assigned by is still the same as the original one , pointing to the same place, then the same space will be destructed twice, and the function will crash.

And this is not creating a new object. The pointers all point to the same memory space. This is not creating a new object in the true sense.

The actual creation of a new object is to open up another space of the same size as the original one. Both objects point to their corresponding spaces respectively, rather than pointing to the same one. Pointing to the same one, that's just a shallow copy/value copy.



There are risks in shallow copy/value copy in C++, and deep copy can solve the problem.

  • How to solve the problem:

    When passing parameters and copying, copy structure (deep copy)

    Generates 's value copy by default

[For those who need to open their own space, they need to make a deep copy (and open another space of the same size as the original)]

If there is no resource application involved in the class, the copy constructor can be written or not; once resource application is involved, the copy constructor must be written, otherwise it will be a shallow copy.

So there is the introduction of copy constructor in C++.

☆ C++ regulations, Custom type object Parameter copy, Copy construction must be called



The default member function will complete the built-in member function in the classvalue copy ,Custom type calls itscopy constructor

  1. Date are all built-in types, and both only need to use the default copy constructor (default copy constructor ) Complete the value copy [Compatible with C language, C means passing value and parameter to complete the value copy]

  2. MyQueue is implemented by Stack because has a copy constructor written in it. Every time you pass parameters and call the Stack class, you need to go through a copy constructor.

  3. When Stack (is the basic unit, the space opened by the pointer needs to be deep copied , so you need to write the copy structure yourself) then you need to write the copy structure yourself to complete the deep copy

Sequence list (similar to stack copy), linked list (open as a node, data copy), binary tree [if the space is opened by oneself, deep copy is required]



(1) The concept of copy constructor

★ Copy construction: Call an object of the same type to assign and initialize this object.


Copy constructor:

  1. Only a single parameter

  2. This formal parameter is a reference to an object of this class (generally commonly used const modification)

  3. When creating a new object from an existing class type object Automatically called by the compiler.



(2) Characteristics of copy constructor

The copy constructor is also a special member function with the following characteristics:

  1. The copy constructor is an overloaded form of the constructor.

  2. The copy constructor's parameter has only one parameter and must be a reference to the class type object because it will cause infinite recursive calls. , When using the pass-by-value method, the compiler directly reports an error ,
    Insert image description here

  3. If is not explicitly defined, the compiler will generate a default copy constructor. The default copy constructor object is stored in memory and copied in byte order. This type of copy is called Shallow copy< /span>. value copy, or

    [Note: is the compiler that generates the default In the copy constructor, the built-in type is copied directly in byte mode, The custom type calls its copy constructor to complete the copy.

class Time
{
    
    
public:
 Time()
 {
    
    
 _hour = 1;
 _minute = 1;
 _second = 1;
  }
  
 Time(const Time& t)
 {
    
    
 _hour = t._hour;
 _minute = t._minute;
 _second = t._second;
 cout << "Time::Time(const Time&)" << endl;
 }
 
private:
 int _hour;
 int _minute;
 int _second;
};

class Date
{
    
    
private:
 // 基本类型(内置类型)
 int _year = 1970;
 int _month = 1;
 int _day = 1;
 // 自定义类型
 Time _t;
};

int main()
{
    
    
 Date d1;// 用已经存在的d1拷贝构造d2,此处会调用 Date类的拷贝构造函数// 但Date类并 没有显式定义拷贝构造函数,则编译器会给 Date类生成一个 默认的拷贝构造函数
 Date d2(d1);
 return 0;
}
  1. The default copy constructor generated by the compiler can already complete the byte order value copy. Do I still need to implement it explicitly by myself?

    It depends on the situation:

    1. If there is no resource application involved in the class, it does not matter whether the copy constructor is written;

    2. Once resource application is involved, the copy constructor must be written, otherwise it will be a shallow copy.


[The detailed use case is in what we mentioned earlier: 4. Secondary destruction of the copy constructor. Multiple releases of the same space will cause the program to crash]
Just understand it No need to look at the examples in this part.
Insert image description here

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;

class Stack
{
    
    
public:

 Stack(size_t capacity = 10)
 {
    
    
 _array = (DataType*)malloc(capacity * sizeof(DataType));
 if (nullptr == _array)
 {
    
    
 perror("malloc申请空间失败");
 return;
 }
 _size = 0;
 _capacity = capacity;
 }
 
 void Push(const DataType& data)
 {
    
    
 // CheckCapacity();
 _array[_size] = data;
 _size++;
 }
 
 ~Stack()
 {
    
    
 if (_array)
 {
    
    
 free(_array);
 _array = nullptr;
 _capacity = 0;
 _size = 0;
 }
 }
 
private:
 DataType *_array;
 size_t _size;
 size_t _capacity;
};

int main()
{
    
    
 Stack s1;
 s1.Push(1);
 s1.Push(2);
 s1.Push(3);
 s1.Push(4);
 Stack s2(s1);
 return 0;
}


  1. Typical calling scenarios of copy constructor:
    • Create new object using existing object
    • The function parameter type is a class type object
    • The function return value type is a class type object

(The complete code is posted later)
Insert image description here

1) Pass references as much as possible

Although C++ transfers copy by value and has a copy constructor for initialization, it is okay when encountering Date d2 (d1), which only needs to transfer 12 bytes of content, and If a structure like Tree() is copied by value and constructed by copy, the efficiency will be extremely low.

If you can use pass-by-reference, use pass-by-reference (the underlying essence is to use pointers, which are as efficient as pointers in code running, and references are more convenient for programmers when typing code)

In order to improve program efficiency, generally try to use reference types when transferring object parameters. When returning, use references as much as possible according to the actual scenario.

class Date
{
    
    
public:
 Date(int year, int minute, int day)
 {
    
    
 cout << "Date(int,int,int):" << this << endl;
 }
 
 Date(const Date& d)
 {
    
    
 cout << "Date(const Date& d):" << this << endl;
 }
 
 ~Date()
 {
    
    
 cout << "~Date():" << this << endl;
 }
 
private:
 int _year;
 int _month;
 int _day;
};

Date Test(Date d)
{
    
    
 Date temp(d);
 return temp;
}

int main()
{
    
    
 Date d1(2022,1,13);
 Test(d1);
 return 0;
}

temp goes out of scope and the function stack frame is destroyed[ can only be returned by value] , return temp;

Return type Date, temp returns a temporary copy of temp (if you need to call to create a new Date() object and assign temp to it, you have to go through the copy construction again [the efficiency is already extremely low])

If is added with static and it is not destroyed when it goes out of scope, you can use to pass the reference and return , [just one less copy structure, the efficiency is extremely high]

correct

Date& Test(Date d)
{
    
    
 static Date temp(d);
 return temp;
}

int main()
{
    
    
 Date d1(2022,1,13);
 Test(d1);
 return 0;
}


5. Assignment operator overloading

Preface: Operator overloading (the meaning of operator overloading)

  • Built-in type objects are types that come with the computer itself. To understand the definition of each built-in type, you can do it according to the size comparison rules of the computer. (Built-in type objects can directly use various operators. Built-in types are simple types, defined by the language itself, and compiled directly into instructions)

  • Custom type,A human-defined type. The compiler does not know the comparison rules for comparing the sizes of the types you define [Custom type comparison is implemented with functions ( There is logic)], so various operators cannot be used.

Custom type operator is not supported by default (if you want to support it, just use operator overloading).
C++Introduced operator overloadingin order to enhance the readability of the code a>



(1) Operator overloading

C++ introduces operator overloading in order to enhance the readability of the code. Operator overloading is a function with a special function name, which also has its return value type, function name and parameter list. Its return value type and parameter list are similar to those of ordinary functions.


(1) Basic concepts of operator overloading

  • 关键字operator

  • Function name:Keyword operator followed by the operator symbol that needs to be overloaded .

  • Function prototype:Return value type operator (parameter list)


Notice:

  • New operators cannot be created by concatenating other symbols: such as operator@

  • Overloaded operator must have a class type parameter —> cannot be overloaded operator to change the operation rules of built-in types

  • Operator used for built-in types, its meaning cannot be changed, for example: built-in integer type +, its meaning cannot be changed

  • When is overloaded as class member function , ’s formal parameters appear to be 1 less than the number of operands. , because the first parameter of the member function is hidden this

  • .* :: [Field] sizeof[Size] ?:[Ternary operator] . [Object variable (structure ) take its members]
    NoteThe above five operators cannot be overloaded. This often appears inmultiple choice questions in written exams.

    .*It’s good to understand this. It’s really rarely used.
    Insert image description here

*Can be overloaded, don’t get confused

*: 1. Multiply by 2. Dereference (double meaning) ==> Following this idea, the founder inspired that operators can have multiple meanings=> Operator overloading< /span>



[C++] Detailed Introduction to C++ I, (2)Features of C++ input and output: automatic identification of variable types

  • << The stream operator automatically identifies the type (actually through operator overloading operate << (), function overloading, parameter (type) matching, function name modification rules, to call the corresponding function, this function is used by others It has been written in the library, built-in types can support it, and custom types are function overloading)
    Insert image description here

  1. is placed in the class , by default the first parameter is the class object pointed to by this pointer ( The Date object occupies the first position by default) , << The implemented member function does not meet the readability , After changing the direction, I don’t know whether it is stream insertion or stream extraction
  • Operator with two operands, the first parameter is the left operand (this pointer, hidden default parameter), and the second parameter is the right operator

Insert image description here

  1. Put it globally, so that the Date object does not occupy the first position by default
    Insert image description here

  2. private Do not set private for now

Butset the member function private to public, this is not advisable

  • Java: Private access cannot be accessed, => get and set

  • C++: Friend functions
    Insert image description here


  • Summarize:

    1. Other operators are generally implemented as member functions

    2. >> << stream operator must be implemented globally , so that can make the stream object the first parameters to ensure readability.

  • analyze:

  • The essence of stream is to solve the input and output problems of custom types.

    printf scanf ("%?") [can only solve built-in types], but cannot solve the input and output problem of custom types (C cannot solve this problem)

  • 面向对象+ 运算符重载 Solve【 Completely solve the custom type

Here is the input and output to the console

Later, the input and output of files and strings were also solved.



<< >>Double meaning:

  1. Stream input and output

  2. Bitwise operator (shift left and right) =》Integer type can be shifted left and right [There is no bit operation (shift left and right) in custom types, only integer type can be used]

  • Distinguish:

    cin/cout + << >> + custom type => Stream insertion/stream extraction

    cin/cout + << >> + built-in type=> It is also stream insertion/stream extraction [It is just automatic recognition of the type, and the overloaded function has been written in the library]< /span>

    << >>+ Integer type => Bit operation (shift left and right)



(2) Assignment operator overloading

(1) Assignment operator overloading format

  • Parameter type: const T&, passingreferencecanImprove parameter transmission efficiency

  • Return value type: T&, Returning a reference can improve the efficiency of return,The purpose of returning a value is to support continuous assignment

  • Check whether you assign a value to yourself

  • Return *this: To compound Continuous assignmentThe meaning of



(2) The assignment operator can only be overloaded as a member function of the class and cannot be overloaded as a global function.

class Date
{
    
    
public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
    
    
 _year = year;
 _month = month;
 _day = day;
 }
 
 int _year;
 int _month;
 int _day;
};

// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right)
{
    
    
 if (&left != &right)
 {
    
    
 left._year = right._year;
 left._month = right._month;
 left._day = right._day;
 }
 
 return left;
}

// 编译失败:
// error C2801: “operator =”必须是非静态成员

Cause:If the assignment operator is not implemented explicitly, the compiler will generate a default.

At this time, the user implements a global assignment operator overload outside the class, which conflicts with the default assignment operator overload generated by the compiler in the class, Therefore, assignment operator overloading can only be member functions of the class.

Insert image description here


(3)When the user does not implement it explicitly, the compiler (automatically) will generate a default assignment operator overload, copying by value byte by byte

Note:Built-in type member variables aredirect assignment , and custom type member variables need to call the assignment operator overload of the corresponding class to complete the assignment.

class Time
{
    
    
public:
 Time()
 {
    
    
 _hour = 1;
 _minute = 1;
 _second = 1;
 }
 
 Time& operator=(const Time& t)
 {
    
    
 if (this != &t)
 {
    
    
 _hour = t._hour;
 _minute = t._minute;
 _second = t._second;
 }
 return *this;
 }
 
private:
 int _hour;
 int _minute;
 int _second;
};

class Date
{
    
    
private:
 // 基本类型(内置类型)
 int _year = 1970;
 int _month = 1;
 int _day = 1;
 // 自定义类型
 Time _t;
};

int main()
{
    
    
 Date d1;
 Date d2;
 d1 = d2;
 return 0;
}

Although the default assignment operator overloaded function generated by the compiler can already complete byte order value copying, if resource management is not involved in the class, the assignment operator can be implemented or not; once resource management is involved, it must be implemented.

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
    
    
public:
 Stack(size_t capacity = 10)
 {
    
    
 _array = (DataType*)malloc(capacity * sizeof(DataType));   
 if (nullptr == _array)
 {
    
    
 perror("malloc申请空间失败");
 return;
 }
 
 size = 0;
 _capacity = capacity;
 }
 
 void Push(const DataType& data)
 {
    
    
 // CheckCapacity();
 _array[_size] = data;
 _size++;
 }
 
 ~Stack()
 {
    
    
 if (_array)
 {
    
    
 free(_array);
 _array = nullptr;
 _capacity = 0;
 _size = 0;
 }
 }
 
private:
 DataType *_array;
 size_t _size;
 size_t _capacity;
};

int main()
{
    
    
 Stack s1;
 s1.Push(1);
 s1.Push(2);
 s1.Push(3);
 s1.Push(4);
 Stack s2;
 s2 = s1;    //没有写赋值运算符重载函数,编译器会自动生成的默认赋值运算符重载函数完成字节序的值拷贝/浅拷贝
 return 0;
}

Insert image description here



6. Pre++ and post++ overloading

7. Implementation of date class

[Will open a separate article to explain todayPre++ and post++ overloading and Implementation of date class, the article link will be placed here]



8. const member function

Syntax: put const after the member function [Practical meaning: const member function]

The "member function" modified by const is called a const member function, The const modified class member function actually modifies the member function implicitly The included this pointer, indicates that no member of the class can be modified in this member function.
Insert image description here



Please consider the following questions:

[Analysis of the lower part of the figure below]

  1. Can a const object call non-const member functions?

    No (permissions cannot be enlarged)

  2. Can non-const objects call const member functions?

    Yes (permissions can be reduced)

[Analysis of the upper part of the figure below]

  1. Can other non-const member functions be called within a const member function?

    No (permissions cannot be enlarged)

  2. Can other const member functions be called within a non-const member function?

    Yes (permissions can be reduced)

Insert image description here

const Date * [const this]=> is equivalent to the const variable being initialized [ const int i = j ], and there will be no problem of permission amplification



Insert image description here

  • Principles for member function definition:
  1. For member functions that do not modify member variables, add const
    [which is very good], so thatconst objects [permissions can Translation] and non-const objects [permissions can be reduced] can callconst member functions

  1. But not all member functions need to be const.Member functions that need to modify member variables cannot be defined as const

    [It is even more impossible to pass const member variables to non-const (can be modified) member functions] Const objects cannot be called (very reasonable) only non-const can be called

    [Then pay attention to the order of passing parameters, so as not to cause permission amplification]


  1. Only member functions need to add const
  • Features:Both declarations and definitions must be written const


9. Address retrieval and const address retrieval operator overloading

The last two of the 6 default member functions

Default member function, the compiler will automatically generate it for any class when nothing is written (no implementation is shown).

In order to be logically consistent, all operators used by custom types must be overloaded.

Essence: Get addressOverloading (different parameters) => Function name modification rules< /span>

Although it is overloaded, it is of no use. Even if it is not overloaded, either of these two can be used.
const can call const, non-const can also call const [reduced permissions] will find a more matching one


class Date
{
    
    
public :

 //取地址操作符重载 ( 普通对象取地址 )
 Date* operator&()
 {
    
    
 return this ;
 }
 
 //const取地址操作符重载 ( const对象取地址 )
 const Date* operator&()const
 {
    
    
 return this ;
 }
 
private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};

The compiler does not have these intermediate steps. The compiler does not need to add the hidden this pointer before compiling. The compiler directly converts After assembly, use the instruction to get the hidden this pointer, and there is no problem of infinite loop in the intermediate steps.

These two operators generally do not need to be overloaded. Just use the overloading of the default address generated by the compiler,
only has special Overloading is required only under certain circumstances, such as if you want others to obtain the specified content!

[General classes do not need to overload this problem]

Guess you like

Origin blog.csdn.net/NiNi_suanfa/article/details/134386618