[Elementary C++] 4. Classes and objects (constructors, destructors, copy constructors, assignment operator overloaded functions)

=========================================================================

Aikanyo gitee own take

C language learning diary: keep working hard (gitee.com)

 =========================================================================

approach period:

[C++ Elementary] 3. Classes and Objects
(Process-oriented, class class, class access qualifier and encapsulation, class instantiation, class object model, this pointer )
-CSDN Blog

 =========================================================================

                     

Introduction: six default member functions of the class

If there are no members in a class, is simply calledEmpty class.
But in the empty class there is not nothing , What is in any class If neither is written, the
compiler will automatically generate The followingSix default member functions,
Default member functions: User does not explicitly implement when , < a i=23>The compilerwillautomatically generatemember functions a> is calleddefault member function

                     

  • Initialization and cleanup:
    Constructor(1< /span>(resource cleanup after an object ends its life cycle) -- Complete2Destructor member variables) -- Complete the initialization of

                  
  • Copy copy:
    Copy constructor(3< /span>(Assign one object to another object) -- 4Assignment overloadingUse similar object initialization to create objects) --

                    
  • Location weighting
    Main ideaGeneral view (5)const对棯鳥地 Site(6), This is the self-representation of the student group

                 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                     

1. Constructor (difficult)

Concepts and characteristics of constructors:

                   

The concept of C++ constructor:

Or assume the following Date class:
//日期类:
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(2023, 11, 16);
	d1.Print();

	Date d1;
	d1.Init(2023, 11, 17);
	d1.Print();

	return 0;
}
  • For the Date classes above, you can pass our own definition Init has common functions (method)Set the date for the object< /span>,

    ButIfRequired every time is created If this method is called to initialize the object members,

    It will be a bit troublesome andmay forget to initialize, Socan it be automatically initialized when the object is created?

                        
  • C++In order to optimize the situation where C language needs to initialize itself, there is one New concept:Constructor.
    Constructorisspecialmember function, its name is the same as class name < a i=17>,
    Create class type object automatically by compiler Call to initialize the object,
    to ensure that each data member has a Appropriate initial value, andwill only be called onceduring the entire lifetime of the object
                      
  • Constructor is divided into parametric constructor and No-argument constructor,
    we
    create the object call the corresponding Parameter constructor object will , then the is set If when initializing the object,call the parameterless constructor the object will, then is not set if, You can set the initialization value of each member variable

Date class -- Illustration:

                  

The main function creates objects through the constructor - illustration:

                          

                          
---------------------------------------------------------------------------------------------

                    

C++ constructor characteristics:

                   

  • Construction function namesumclassname homology, < /span>Construction function for < /span>Automatic controlMeetingEditing deviceTimeImplementation, No return returnConstruction function

                    
  • Ifthe constructor is not explicitly defined in the class, thenC++ compiler will automatically generateadefault constructor without parameters,
    Once the user explicitly defines the constructor , the compiler will < /span> to define a parameterless constructorIt is best, Defined a parameterized constructorso if, constructor is no longer automatically generated Functionbut cannot be called


                    
  • Constructor is also a function, can have parameters< /span>This shouldif when initializing the object two constructs Functionwithout parameters and with parametersreplacement will doa constructorIn this wayThe task of parameterless constructorimplemented, play a rolewillThe default parametersConstructor with parameters then, No initialization value, becausethe task of parameterless constructorAnother realization of,parametric constructor has realized the task ofConstructor), Full default constructor( default Parameters are set to a All parameters) a constructor that initializes all member variables (parametric constructorConfigure a, can also set default parameters for , so






                
  • Constructor supports overloading, although supports overloading. Contains ,
    but if has defined the full default constructor a>, can already be implemented in the case of parameterless constructor < a i=13>,
    then if define another parameterless constructor, Although constitutes constructoroverloaded
    < a i=22>, but will make an error when actually calling , Because full default constructor and no-argument constructor a>The function is repeated, The compiler Willnot know which constructor to call

                  
  • Constructor without parameters and Fully default constructor are both called,Constructor that can be called without passing parameters (Default constructor can be considered as , The constructors generated by default by the compiler)Full default constructor,No-argument constructorNote:call ambiguityotherwise there will be ( There can only be oneDefault constructor and , Default constructordefault constructor)




Full default constructor -- illustration:

                            

The function of the constructor generated by the compiler by default:
  • C++middle classclass typecomponent completedinternal class type< /span>linguistic primitive number category type, The beginning of the undetermined change in the amount of change该构结构法对I编译器generative默认结构法关于. Self-determined typeunion/ struct / class this is my useself-determined type……);directiondouble, int(it isinternal category type,self Determined category typesum)basic type(



                   
  • Different compilers have different initialization methods, VS2013 : If the member variables of the object are built-in types ,The default generated constructor will not process it( is a random value); if the member variable of the object is Custom type , default generated constructor will call the custom The default constructor of the typeVS2019The situation will be more complicated:





    built-in types< /span>), < /span> Constructor, the default value of the custom type will be calledcustom typeFor the int type member variable will be initialized to 0 ( is processed among them and has a built-in type There are also custom types the member variable of the object if); is a random value( will not process itThe default generated constructor,built-in typesare allthe member variables of the object
    If




               
  • Sothe default-generated constructorwillaccording to the object’s member variables come to determine whether to process it,
    ifThe member variable of the object is a custom type, so calls the default constructor of the custom typeIt is recommended to treat it as if it will not be processed< /span>)), Look at the compiler(built-in types may not necessarily handle, custom typesWill handle () is a random value ( is not Process , then built-in type
    If it is ;
Illustration:

           

  • ThereforeC++11for built-in type members are not initialized defect, and a patch:
    built-in type When a member variable is declared in a class it can be given a default valueexplicit constructor) shall prevailIf , If defines Explicit constructor and the default value gives (
Illustration:

                     

Summarize:
  • Under normal circumstances, we have towrite the constructor ourselves
                 
  • Member variablesIf both arecustom types, Or member variable is declared with a default value,
    then< /span>the compiler generate its own constructorYou can consider letting

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

2. Destructor

Concepts and characteristics of destructor:

                 

The concept of C++ destructor:

            

  • Through’s previous understanding of constructor, We know how an object comes , but how does an object disappear< What about a i=8>? If the constructor is the Init initialization function we wrote before, < /span>

    NanaAnalysis functionThis is my previous copyDestroy销毁Function
                            

  • analytical functionsumstructural functionobjectcontrary to function HoweverAnalysis functionNot correctCompletionEarth elephant's body's carpentry,
    Local elephant carpentry workKoreyu Complete installationof.
    butthe momentisthe moment MeetingAutomatic controlAnalysis function,CompleteCleaning work of source in the elephant

                          

                          
---------------------------------------------------------------------------------------------

                    

Characteristics of C++ destructor:

                

  • Analysis function number name = ExistClass name addition character ~” (appointment and reversal sign)
                        
  • Destructorhas no return value and function parameters
                
  • One itemOnly one itemAnalysis function, YoungUnauthorized style settingediting devicekai Automatically generated analytical function
    (Note:Analysis functionUnsupported weight)
                      
  • ImageStatement periodicitytime,C++ editing system MeetingAutomatic control analysis function

Destructor -- Illustration:

                            

The function of the constructor generated by the compiler by default:
  • The destructor generated by default, behaves like the constructor is similar to ,
    is aimed at the member variables of built-in types a>,The destructor will not process it;< a i=13>For member variables ofcustom type, is destructed The functionwill alsocall the default destructor of the custom type

                       
  • If does not apply for resources in the class, destructorYou can not write , directly use the default destructor generated by compiler,
    For example, the Date class written before does not need to be written ; And if there are application resources in the category , must be written a> needs to explicitly define a destructor for resource cleanupStack classFor example, Leak) Memory(resourceotherwise it will result in, Destructor

Illustration:

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

3. Copy constructor (difficult)

Concepts and characteristics of copy constructor:

                

The concept of C++ copy constructor:

                     

  • Copy constructor:
    Onlya single formal parameter, This formal parameter is a reference to an object of this class ( compiler Automatic call by the is copied when creating a new object An existing class type object is used ), ModificationconstGenerally used

Illustration:

                          

                          
---------------------------------------------------------------------------------------------

                    

Characteristics of C++ copy constructor:

                       

  • The copy constructor is also aspecial member function, Isan overloaded form of the constructor
                     
  • There is only one parameter of the copy constructor and must be A reference to a class type object, uses the pass-by-value method as its parameter The compiler will crash directly, because it will trigger infinite recursive calls a>

                           
  • If is not explicitly definedcopy constructor, The compiler willgenerate a default copy constructor.
    The default copy constructorWhen copying an object, it will store it in byte order in memoryComplete copy,
    This kind of copy is called shallow copy, a>value copyor
Note:

In the default copy constructor generated by the compiler, The built-in type is directly copied in byte format (< /span>to complete the copy be calledThe copy constructor of the custom type willcustom type and ), value copy

Illustration:

                

                

  • editing device generative reading torture constructing function completed character ordering torture torturecomplete ,
    currentlynot available andsource application(< a i=13>application time, etc.)time,shallow torture< /span>it has been completed< /span>torture Constructive function Deep tortureProgresstimefunding requestOnceHowever,;right or wrong The formula can be determined by the number of functions that can be constructedcompleteFoot use已经

Illustration:

                   

  • Copy constructorTypical calling scenario:
    Used Existing objectscome"copy"Create new object, function parameter type isclass type object< /span>class type object is
    The function return value type,
Note:

为了High efficiencyGeneral information introductionWhen , exhaustive usecitation type return,
Return time root setting practical scene,functional usecitation returnexhaustive use Quote return

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

4. Assignment operator overloading

The use and precautions of operator overloading

                   

introduction:

对于Internal type(int, > a>Self-determination and judgmental considerationDemand I,Becauseedit the unknown path or judge our self-determined category type reasonimpossible direct value Use calculation mark, to beand wordsself-determined category-type numerical valuebut对), judgment size(ba) , judgment equality,< /span> b==a Can be used, websumforming change aI can use itDirectly use the calculation markI can use itcountertarget……)double



Illustration -- Custom type judgment rules:

                          

                          
---------------------------------------------------------------------------------------------

                    

Use of operator overloading:

  • C++Introducedenhance the readability of the code >Operator overloading,Operator overloading is a function with a special function name /span> are similar to ordinary functions< /span>parameter listandreturn value type Its, Parameter list and Function name, return value type​​​​​​ also has its,


                    
  • Function name关键字 operatorNext demand multiplication code)​+ operator  -- addition and summation mark multiplicationas
    (
                      
  • Function prototype:Return type operatorOperation mark (Sequence table)

Illustration -- Out-of-class operator overloading:

                          

                          
---------------------------------------------------------------------------------------------

                    

Notes on operator overloading:

  • New operators cannot be created by concatenatingother symbols: for example< a i=4>operator@
                  
  • Overloaded operatormust have oneclass type parameter
                        
  • UseInternal category type calculation mark, that Impossible modification,
    Example:Infix type + ) is not one-sided+= sum +(impossible modification 并义,
                   
  • Key points:
    When overloading as a class member function , itsformal parameterslookOne less than the number of operands, becausemember function a>The first parameter is the hidden this pointer

                    
  • Caution The following five-digit multiplication markImpossible weight:
    .* ” , ​“ :: ” , “ < /span> ”​​​​​ . ” , “?: ” , “ sizeof
Illustration -- Operator overloading in the class:

                      

  • Important items for important calculationsMain viewsThis item for important calculations说 has no significance
    significantlyservicepossible weight >,Not worth itJobUnnecessary loading
    Date classarrival, Date +(Add) *() /(excluding) To be lost, < a i=32>However -() < a i=37>issignificantfor,both dates are compatible Can be doneCalculation and date difference may be slightly higherDate+Date a>Not applicableHoweverDate + shapingissignificanttoasd1 + 100 , Calculationd1 day period 100 days after day


Illustration - Implement += and + operator overloading in the class:

(Note: “+= --Settings and returns中文Additional marks
                     

                     


                    

Assignment operator (=) overloading

                

Assignment operator -- "=" , Assignment operator overloading means that allows custom types to be used like built-in types”< a i=8>=

               

Assignment operator overloading format:

  • const T&constmodified number type ,abilityprevention 赋值tortureTime and left copyingcompleted, guidedchanged to original photo T& /span>                  High efficiency rate


  • return type:T&
    quote returnpossible Submission return efficiency, setting return recoveryadvance completion Support=target 连续赋值
                     
  • When defining an assignment operator overloaded function, needs to check whether "Assign value to yourself"Situation
                         
  • last reply *this (immediatelyreturn to the original body), ability sign=connectionconnotation
                 
  • UseNot availabletimeediting device associationgenerate one piece of information for reading the arithmetic mark multiplex function,
    that:< /span>), Required number requiredExpense multiplication functionStack class” (sourceUnnecessary or unnecessary. =40>“Additional multiplication function), Date class” (Source Not available As a resultAttention:Self-determined type of function : MeetingAmount of changeSelf-determined type针对Shallow TortureTough Torture: Progress Adult change amountInternal type针对similaritytorture construction functionsumaction





                          
  • Assignment operator can only be overloaded into a class member function (< a i=4>overloading can only be defined in the class), cannot be overloaded as a global functionreason a>
    , is not implemented explicitlyAssignment operator overloaded function If:willgenerate a default. At this time, if implements a global assignment operator overload function outside the class, It will conflict withthe default assignment operator overloaded function generated by the compiler in the class ,​​​​​​​So assignment operator overloaded function can only be a member function of the class



Illustration -- taking the Date class as an example:

 ​​​

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

Code related to this blog

Test.cpp -- C++ file:

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <assert.h>
using namespace std;

//class Date
//{
//public:
//
//	//(有参)构造函数 -- 用于初始化对象:
//	//Date(int year, int month, int day)
//	///*
//	//*			有参构造函数:
//	//* 如果创建类对象时有传参数就自动调用
//	//* 有参构造函数对其进行初始化
//	//*/
//	//{
//	//	_year = year;
//	//	_month = month;
//	//	_day = day;
//	//}
//
//	/*
//	*				构造函数特征:
//	* 1、函数名和类名相同;
//	* 2、没有返回值,所以不用设置返回值类型;
//	* 3、对象示例化时编译器自动调用对应的构造函数;
//	* 4、构造函数可以重载
//	* 
//	* 构造函数实现的功能就是我们下面写的Init初始化函数的功能,
//	* 而且还会在创建该类对象时就自动帮你初始化该对象
//	*/
//
//	//构造函数重载(无参):
//	//Date()
//	///*
//	//*			无参构造函数:
//	//* 如果创建类对象时没有传参数就自动调用
//	//* 无参构造函数对其进行初始化
//	//*/
//	//{
//	//	_year = 1;
//	//	_month = 1;
//	//	_day = 1;
//	//	
//	//	//没有传参就初始化为 1年1月1日
//	//}
//
//	/*
//	* 有参数构成函数也可以使用(全)缺省参数,
//	* 设置后有参构造函数也能实现无参构造函数的效果,
//	* 因为如果不传参数,就默认使用全缺省参数,
//	* (在有参构造函数的基础上通过全缺省参数实现无参构造函数)
//	* 
//	* 因为全缺省参数的特点,只传初始化参数的部分参数,
//	* 也可以实现只初始化其中一部分参数的效果
//	*/
//
//	//设置了缺省参数的有参构造函数:
//	Date(int year = 1 , int month = 1, int day = 1)
//		//有参构造函数的参数设置成缺省参数:
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	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);
//	/*
//	*		注意不要忘记初始化:
//	* 如果没有初始化,程序可能会出现随机值,
//	* 严重的情况下程序还会崩溃
//	* 
//	* 平常写代码时还是很容易忘记初始化的,
//	* 像是有时创建一个栈对象后,没有初始化然后
//	* 就直接进行push出栈操作了
//	* 
//	* C++中为了防止出现忘记初始化的情况,
//	* 有了构造函数,构造函数可以在创建一个对象时
//	* 就自动初始化该对象
//	*/
//
//	/*
//	* 创建对象后不调用自己写的Init函数,
//	* 让构造函数帮我们完成初始化,
//	* 此时调用的是无参构造函数,
//	* 调用打印函数查看自动初始化情况:
//	*/
//	cout << "通过无参构造函数初始化对象:";
//	d1.Print(); 
//
//	/*
//	* 有了构造函数后,创建对象时可以自己设置
//	* 对象初始化时的值(通过有参构造函数),
//	* 只需要在创建对象时后面加上(成员变量,成员变量,……)即可:
//	*/
//	//通过有参构造函数对类进行初始化:
//	Date d2(2023, 11, 16);
//	
//	cout << "通过有参构造函数初始化对象:";
//	//打印通过有参构造函数初始化的对象:
//	d2.Print();
//
//	/*
//	*				 注:
//	* 初始化对象时,如果想调用无参构造函数,
//	* 初始化时对象名后面是不需要加括号的,
//	* 如果加了的话,那可能就是声明了一个函数,
//	* 而不是初始化类对象
//	* 
//	* 如果是调用有参构造函数的话,
//	* 初始化对象时会在括号中写上初始化的值,
//	* 没有函数的声明会这样写,所以不用担心
//	* 调用无参构造函数时的问题
//	*/
//
//	//通过设置了缺省参数的有参构造函数初始化部分参数:
//	Date d3(2023, 10);
//
//	cout << "通过有参构造函数(设置了缺省函数)部分初始化对象:";
//	d3.Print();
//
//	return 0;
//}



//class Date
//{
//public:
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//
//	/*
//	* 没有显式定义构造函数且没有自定义初始化函数的情况下,
//	* 编译器会有一个默认的无参构造函数,
//	* 但该默认的无参构造函数调用后初始化的值会是随机值
//	*/
//
//private:
//	int _year = 1;
//	int _month = 1;
//	int _day = 1;
//	/*
//	* 注:这里虽然给出了默认值,
//	* 但也不是成员变量定义,还是成员变量声明,
//	* 只是在声明时给了一个缺省值,没有开空间,
//	* 在类中,它始终只是“设计图”的一部分,
//	* 示例化对象后,开了空间,成员变量才被定义
//	*/
//};
//
//
C++实现栈(部分):
//class Stack
//{
//public:
//	//栈初始化构造函数:
//	Stack(size_t capacity = 3)
//		/*
//		* 构造函数初始化对象时的情况要按实际情况而定,
//		* 像这里的栈初始化构造函数就不需要将所有的成员变量都初始化,
//		* 最多只用传栈容量大小即可,用于开辟对应容量的动态空间,
//		* 不传的话缺省参数默认容量为3
//		*/
//	{
//		cout << "Stack(size_t capacity = 3)" << endl;
//
//		_a = (int*)malloc(sizeof(int) * capacity);
//		if (nullptr == _a)
//		{
//			perror("malloc申请空间失败!!!");
//		}
//		_capacity = capacity;
//		_top = 0;
//	}
//	
//private:
//	int* _a; //栈底层数组指针
//	int _capacity; //栈容量
//	int _top; //栈顶值
//};
//
//
定义一个类:通过两个栈实现一个队列
//class MyQueue
//{
//private:
//	//成员变量:
//	Stack _pushst; //出栈值
//	Stack _popst; //入栈值
//	int _size = 1; //当前存储数据个数
//};
//
//
//
//int main()
//{
//	Date d1;
//	d1.Print();
//	//如果没有自己定义构造函数和其它初始化函数,
//	//使用编译器默认的无参构造函数后初始值为随机值
//
//	Stack st1;
//	//如果没有自己定义构造函数和其它初始化函数,
//	//使用编译器默认的无参构造函数后初始值为随机值
//
//	/*所以对与以上两个对象的情况,不自己定义构造函数是不合适的*/
//	
//	MyQueue mq;
//	/*
//	* MyQueue类中对象中,需要生成栈的对象,_pushst和_popst,
//	* 所以当创建MyQueue对象mq时,就需要初始化这两个栈对象,
//	* 
//	* C++中有内置类型和自定义类型:
//	* 内置类型:语言原生就有的类型(int、double、指针……)
//	* (注:指向自定义类型的指针也是内置类型)
//	* 自定义函数:我们自己通过class、struct定义的类型
//	* 
//	* 当调用默认生成的构造函数时(VS2013):
//	* 内置类型成员变量不会进行处理(为随机值)
//	* 自定义类型则会去调用它的默认构造函数
//	* 
//	* 当调用默认生成的构造函数时(VS2019):
//	* VS2019在这方面比较奇怪,要分两种情况。
//	* 当所有成员变量都是内置类型时,不会进行处理(全为随机值)
//	* 当成员变量既有内置类型又有自定义类型时,
//	* 那么这两种类型都会被处理,自定义类类型变量会调用其构造函数,
//	* 自定义函数会被初始化为0(int)
//	* (所以VS2019编译器在这方面有种“半生不熟”的感觉)
//	* 
//	* 所以默认生成的构造函数并不是什么都不做,
//	* 而是看成员的情况来进行要不要进行处理,
//	* 如果成员变量是自定义类型,那就会调用其默认构造函数;
//	* 如果是内置类型,则不进行处理(为随机值)
//	* (处理自定义类型,内置类型不确定(看编译器),建议当成不处理)
//	*/
//
//	return 0;
//}



//class Date
//{
//public:
//	
//	/*
//	*				默认构造函数:
//	* 1、编译器默认生成的构造函数,叫默认构造函数
//	* 2、我们自己定义的无参构造函数也可以叫做默认构造函数
//	* 3、我们定义的全缺省构造函数也可以叫默认构造函数
//	* 不传参数还可以被调用的构造函数,都可以叫默认构造函数
//	*/
//
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//
//private:
//	int _year = 1;
//	int _month = 1;
//	int _day = 1;
//};
//
//int main()
//{
//	Date d1;
//	d1.Print();
//
//	return 0;
//}



//析构函数:
//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//
//	//析构函数:
//	~Date() 
//		/*
//		* 对象销毁时会自动调用析构函数,
//		* 完成对象中资源的清理工作,
//		* 和构造函数相反的概念,
//		* 构造函数名和类名相同,
//		* 析构函数名则需要在类名前再加上一个 “~” 符号
//		*/
//	{
//		//当前日期类中没有什么资源需要被清理,
//		//所以只能打印相关内容来证明对象销毁时会自动调用析构函数:
//		cout << "~Date()" << endl;
//	}
//
//private:
//	int _year = 1;
//	int _month = 1;
//	int _day = 1;
//};


//class Stack
//{
//public:
//	//栈初始化构造函数:
//	Stack(size_t capacity = 3)
//	{
//		//cout << "Stack(size_t capacity = 3)" << endl;
//
//		_a = (int*)malloc(sizeof(int) * capacity);
//		if (nullptr == _a)
//		{
//			perror("malloc申请空间失败!!!");
//		}
//		_capacity = capacity;
//		_top = 0;
//	}
//
//	//析构函数:
//	~Stack()
//		/*
//		* 对象销毁时会自动调用析构函数,
//		* 完成对象中资源的清理工作,
//		* 和构造函数相反的概念,
//		* 构造函数名和类名相同,
//		* 析构函数名则需要在类名前再加上一个 “~” 符号
//		* (按位取反符号),且没有参数和返回值
//		* 
//		* 构造函数相当于我们之前在数据结构中写的Init初始化函数
//		* 析构函数则相当于之前写的Destroy“销毁”函数
//		* 和Init函数相同,Destroy函数也很容易最后忘记调用
//		* 
//		* 构造函数和析构函数都是默认成员函数,
//		* 不显式定义的话,编译器会自动生成
//		* 但自动生成的析构函数不会对动态空间进行释放,
//		* 也不会将指向该动态空间的指针置为空指针,
//		* 所以当一个类中有类似资源时就需要自己定义析构函数了
//		*/
//	{
//		cout << "~Stack()" << endl;
//		//释放之前开辟的动态空间资源:
//		free(_a);
//		_capacity = _top = 0; //将栈容量和栈顶值都初始化为0
//		_a = nullptr; //将底层数组指针置为空指针
//	}
//	
//private:
//	int* _a; //栈底层数组指针
//	int _capacity; //栈容量
//	int _top; //栈顶值
//};


定义一个类:通过两个栈实现一个队列
//class MyQueue
//{
//private:
//	//成员变量:
//	Stack _pushst; //出栈值
//	Stack _popst; //入栈值
//	int _size = 1; //当前存储数据个数
//
//	/*
//	* 和构造函数相同,
//	* 针对内置类型成员变量,析构函数不进行处理
//	* 针对自定义类型成员变量,
//	* 析构函数也会调用该自定义类型的默认析构函数
//	*/
//};


//int main()
//{
//	//Stack st1;
//	出了生命周期后,会自动调用析构函数清理资源
//
//	MyQueue mq;
//	/*
//	* 默认生成的析构函数,其行为跟构造函数类似,
//	* 内置类型成员不做处理,
//	* 自定义类型成员会去调用它的默认析构函数
//	*/
//
//	return 0;
//}




//class Date
//{
//public:
//    Date(int year = 1900, int month = 1, int day = 1)
//    {
//        _year = year;
//        _month = month;
//        _day = day;
//    }
//   
//    void Print()
//    {
//        cout << _year << "/" << "_month" << "/" << _day << endl;
//    }
//
//    指针传参:
//    //Date(Date* dd)
//    //{
//    //    _year = dd->_year;
//    //    _year = dd->_year;
//    //    _year = dd->_year;
//    //}
//
//    //拷贝函数:
//    Date(Date& dd) //引用传参
//    {
//        _year = dd._year;
//        _year = dd._year;
//        _year = dd._year;
//    }
//
//private:
//    int _year;
//    int _month;
//    int _day;
//};


//class Stack
//{
//public:
//	//栈初始化构造函数:
//	Stack(size_t capacity = 3)
//	{
//		cout << "Stack(size_t capacity = 3)" << endl;
//
//		_a = (int*)malloc(sizeof(int) * capacity);
//		if (nullptr == _a)
//		{
//			perror("malloc申请空间失败!!!");
//		}
//		_capacity = capacity;
//		_top = 0;
//	}
//
//	//析构函数:
//	~Stack()
//	{
//		cout << "~Stack()" << endl;
//		//释放之前开辟的动态空间资源:
//		free(_a);
//		_capacity = _top = 0; //将栈容量和栈顶值都初始化为0
//		_a = nullptr; //将底层数组指针置为空指针
//	}
//	
//    Stack(const Stack& stt) //通过引用传参
//        /*
//        * 拷贝构造函数中,在值拷贝时,即使等号两边写反了也不会报错,
//        * 所以为了防止出现不小心写反的情况,使用const修饰被拷贝对象,
//        * 让被拷贝对象不能被修改,此时如果值拷贝写反了就会报错了。
//        */
//    {
//        cout << "Stack(Stack& stt)" << endl;
//        /*
//        * 如果一个类中有“资源”,
//        * 在定义该类的拷贝函数时就需要进行深拷贝,
//        * 深拷贝本质是拷贝指向的资源,
//        * 让拷贝对象和被拷贝对象有一样大的空间和一样的值,
//        * 此时各自调用析构函数时析构的就是各自的空间,
//        * 而不是析构同一块空间两次,导致程序崩溃
//        */
//        //进行深拷贝 -- 让拷贝对象和被拷贝对象有一样大的动态空间:
//        _a = (int*)malloc(sizeof(int) * stt._capacity);
//        //检查是否开辟成功:
//        if (_a == nullptr)
//        {
//            perror("malloc fail");
//            exit(-1);
//        }
//        //使用memcpy让拷贝对象空间中的值和被拷贝对象的一样:
//        memcpy(_a, stt._a, sizeof(int) * stt._top);
//
//        _top = stt._top; //栈顶值拷贝
//        _capacity = stt._capacity; //栈容量拷贝
//    }
//    /*
//    * 拷贝函数是特殊的构造函数,是构造函数的重载,
//    * 其参数只有一个同类型对象的引用,
//    * 当需要拷贝一个对象时就会调用拷贝函数
//    *(通过同类型对象拷贝出另一个对象、函数传值传参或返回都需要进行拷贝)
//    * 
//    * 不能通过传值方式调用拷贝函数,
//    * 因为会引发无穷递归调用,
//    * 传值拷贝时,自定义类型调用其拷贝函数,
//    * 传参时,还未调用到就先拷贝了一份形参出来,
//    * 形参又需要调用拷贝函数,就形成了无穷递归调用
//    *(调用拷贝构造函数->先传参->传值传参->形成新的拷贝构造函数)
//    * 
//    * 解决方法:通过指针或者引用进行传参
//    */
//    
//private:
//	int* _a; //栈底层数组指针
//	int _capacity; //栈容量
//	int _top; //栈顶值
//};


创建一个类,参数是接收另一个类的对象:
//void func1(Date d) //接收日期类对象
//{
//    d.Print(); 
//
//    /*
//    * 这里将日期类对象(自定义类型)作为函数参数,
//    * 而且我们知道形参是实参的临时拷贝,
//    * 
//    * C语言中也可以将结构体变量当作函数参数,
//    * 但是有两个缺陷:
//    * 1、实参拷贝时效率较低
//    * 2、形参结构体变量改变不会影响实参结构体变量
//    * 我们这里只考虑传值传参,需要拷贝实参,
//    * 也称 值拷贝 或者 浅拷贝 
//    * 
//    * 为了解决第二个问题,可以使用指针或者引用(&)
//    */
//}


//void func2(Stack st) //接收栈类
//{
//    
//}


//class MyQueue
//{
//    Stack _pushst;
//    Stack _popst;
//    int _size = 0;
//};


//Stack& func3()
//{
//    static Stack st;
//    /*
//    * static修饰后st出了函数后不会销毁,
//    * 所以此时可以使用引用返回,返回st的“别名”,
//    * 返回时就不需要进行拷贝了,也就不用调用拷贝构造函数了
//    */
//
//    return st;
//    /*
//    *           如果使用传值返回:
//    * 传值返回时,返回的是自定义类型st的拷贝,
//    * 所以也需要调用到该类型的拷贝构造函数
//    */
//}


//int main()
//{
//    Date d1(2023, 10, 22);
//    func1(d1); //接收日期类对象d1
//    /*
//    * 实参拷贝时,拷贝成员变量:年、月、日,
//    * 共12个字节,要通过实参d1拷贝生成形参d,
//    * 拷贝时要先调用拷贝函数,拷贝函数中dd是d1的别名,
//    * 隐藏的this指针会指向形参d,
//    * 所以可以将d1的成员变量值拷贝到形参d。
//    * 拷贝完成后再执行func1函数中的内容
//    */
//    Date d2(d1); //使用d1拷贝出一个d2
//    //这种情况下也会进行拷贝
//    /*
//    * 此时拷贝同样需要调用拷贝函数,
//    * 拷贝函数中dd是d1的别名,隐藏的this指针会指向对象d2
//    * 所以可以通过对象d1拷贝生成对象d2
//    */
//
//    //Date d3(&d1); 
//    //指针传参,可以解决传值方式的拷贝构造函数问题,
//    //但是用起来没有引用传参方便
//
//
//    Stack st1;
//    func2(st1); //接收栈类对象st1
//    /*
//    * 实参拷贝时,拷贝成员变量:
//    * 指针_a、栈顶值_top、栈容量capacity
//    * 也是12个字节,但是这里有一个指针_a,
//    * 指向一块动态开辟的空间,拷贝指针后,
//    * 形参拷贝的指针也会指向该动态空间,
//    * 但是栈类中是有析构函数的,
//    * 形参st出了作用域,析构函数会先释放掉动态空间,
//    * 之后实参st1出了主函数,其析构函数又会再释放一次动态空间,
//    * 导致一块空间被释放了两次,程序会崩溃,
//    * 所以C++中使用值拷贝(浅拷贝)是有风险的
//    * (C语言默认拷贝 -- 浅拷贝)
//    */
//
//    /*
//    * 此时就需要进行深拷贝,来解决浅拷贝的问题
//    * C++中规定,自定义类型对象拷贝的时候,
//    * 需要调用一个函数,这个函数就叫做拷贝构造函数,
//    * 拷贝构造函数默认的行为:值拷贝,这也是导致上面会崩溃的原因,
//    * 
//    * 对于内置类型的成员变量,值拷贝就够了,
//    * 但对于自定义类型的成员变量有“资源”的情况下,就需要进行深拷贝了
//    */
//    Stack st2(st1); //使用st1拷贝出一个st2
//    /*
//    * 拷贝函数中stt时st1的别名,隐藏的this这种指向对象st2,
//    * 所以可以通过对象st1拷贝生成对象st2
//    */
//
//
//    MyQueue q1;
//    MyQueue q2(q1); //使用q1拷贝出一个q2
//
//    /*
//    * 默认生成的拷贝构造函数的作用:
//    * 1、内置类型成员 -- 默认生成拷贝构造函数会完成值拷贝
//    * 2、自定义类型成员 -- 
//    * 默认生成拷贝构造函数会调用该自定义类型的拷贝构造函数
//    */
//
//    func3(); //传值返回一个自定义类型
//    
//    return 0;
//}



运算符重载:
//class Date
//{
//public:
//	Date(int year = 1900, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	/*
//	* 在了解了构造函数、析构函数、拷贝构造函数后,
//	* 可以知道日期类中只需要写一个全缺省的构造函数即可,
//	* 析构函数和拷贝构造函数可以不进行显式定义(没有“资源”需要处理)
//	*/
//
//	void Print()
//	{
//		cout << _year << "/" << _month << "/" << _day << endl;
//	}
//
//	//运算符重载
//	//判断对象是否相等的函数(以日期类为例):
//	bool operator==(const Date y)
//		/*
//		* (注:)在类中的话,隐藏的this指针是第一个参数,
//		* == 有两个操作数,this指针 和 y 就是两个操作数,
//		*(运算符重载,这个运算符操作数和要和函数的参数匹配)
//		*/
//	{
//		/*
//		* 实现前需要先把Date类的成员变量权限设置为共有,
//		* 才能在类外部进行调用:
//		*/
//		return _year == y._year 
//			&& _month == y._month
//			&& _day == y._day;
//		//比较两日期类对象是否相等只要判断两者年月日是否相等即可
//		
//		/*
//		* 成员变量虽然是私有的,
//		* 但在类中通过this指针访问私有成员变量是可以的
//		*/
//	}
//
//	//写一个函数判断自定义类型大小(以日期类对象为例):
//	bool operator>(Date y)
//		/*
//		* > 同样有两个操作数,隐藏的this指针是第一个参数
//		*/
//	{
//		//“年大就大”:
//		if (_year > y._year)
//		{
//			return true;
//		}
//		//"年相等,月大就大":
//		else if (_year == y._year && _month > y._month)
//		{
//			return true;
//		}
//		//"年相等,月相等,天大就大":
//		else if (_year == y._year && _month == y._month && _day > y._day)
//		{
//			return true;
//		}
//
//		//上面已经写出了所有大于的情况,执行到这说明是小于等于:
//		return false;  //返回false
//	}
//
//	/*
//	* 一个类要重载哪些运算符,
//	* 主要看这个运算符对这个类来说有没有意义,
//	* 有意义就可以重载,没有意义就不要重载,
//	* 对日期类来说,日期的 +(加) *(乘) /(除) 都没有意义,
//	* 但 -(减) 是有意义的,
//	* 两个日期相减可以计算两日期相差了多少天
//	*/
//	//实现 d1 - d2,计算两日期相差多少天 :
//	int operator-(const Date& d)
//	{
//		//(目前还不太好实现)……
//		return 0;
//	}
//
//	//日期+日期没有意义,但日期+整型是有意义的,
//	//如:d1 + 100 ,计算d1日期的100天后的日期:
//
//	/*
//	* 因为考虑到各月份日期可能不一样,
//	* 二月还需考虑闰年还是平年,
//	* 所以可以单独写一个函数处理月份的情况:
//	*/
//	int GetMonthDay(int year, int month)
//	{
//		//assert断言防止month传错:
//		assert(year >= 1 && month >= 1 && month <= 12);
//
//		int monthArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
//		//月份:  				  一  二  三   四  五  六  七   八  九  十 十一 十二
//
//		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
//			//月份是二月(不是二月就不用管是不是闰年了),且该年是闰年:
//		{
//			return 29; //返回闰年二月的29天
//		}
//		
//		//把数组下标当作月份,返回对应月份:
//		return monthArray[month];
//	}
//	
//	//d1 += 100(整数) ,计算d1日期的100天后的日期:
//	Date& operator+=(int day) // += 才会改变d1对象
//		//为了防止拷贝返回,使用引用返回
//	{
//		//思路:当月天数满了进位到月,月满了则进位到年:
//
//		_day += day; //先将要加的天数加到当前的天数上
//
//		//开始进位(如果需要的话):
//		while (_day > GetMonthDay(_year, _month))
//			/*
//			* 先通过GetMonthDay函数获得当月的天数,
//			* 再比较相加后的天数是否超过了当月的天数,
//			* 只要超过了则进行进位,进位到月:
//			* (while循环到没超过为止)
//			*/
//		{
//			//天数减去一轮当前月天数:
//			_day -= GetMonthDay(_year, _month);
//
//			//减去的一轮当前月天数进位到月中:
//			++_month;
//
//			//如果当前月进位后超过了12个月:
//			if (_month == 13)
//			{
//				//将一轮月份进位到年:
//				++_year;
//
//				//将月份重置为1月:
//				_month = 1;
//			}
//		}
//		
//		return *this;
//	}
//
//	//d1 + 100(整数) ,计算d1日期的100天后的日期:
//	Date operator+(int day) // + 不会改变d1对象
//		//为了防止拷贝返回,使用引用返回
//	{
//		Date tmp(*this); 
//		/*
//		* 为了实现加法,加了后不改变d1对象(+=才会改变)
//		* 先通过*this(即d1)拷贝出一个tmp,
//		* 对tmp进行加法操作就不会改变d1对象了
//		*/
//
//		//思路:当月天数满了进位到月,月满了则进位到年:
//
//		tmp._day += day; //先将要加的天数加到当前的天数上
//
//		//开始进位(如果需要的话):
//		while (tmp._day > GetMonthDay(tmp._year, tmp._month))
//			/*
//			* 先通过GetMonthDay函数获得当月的天数,
//			* 再比较相加后的天数是否超过了当月的天数,
//			* 只要超过了则进行进位,进位到月:
//			* (while循环到没超过为止)
//			*/
//		{
//			//天数减去一轮当前月天数:
//			tmp._day -= GetMonthDay(tmp._year, tmp._month);
//
//			//减去的一轮当前月天数进位到月中:
//			++tmp._month;
//
//			//如果当前月进位后超过了12个月:
//			if (tmp._month == 13)
//			{
//				//将一轮月份进位到年:
//				++tmp._year;
//
//				//将月份重置为1月:
//				tmp._month = 1;
//			}
//		}
//
//	return tmp;
//	/*
//	* 这里tmp是d1的拷贝,出了函数就销毁了,
//	* 所以需要传值返回拷贝一份回主函数
//	*/
//	}
//
//	// d1+整型 加法运算符重载(优化):
//	Date operator+(int day)
//	{
//		Date tmp(*this);
//		/*
//		* 为了实现加法,加了后不改变d1对象(+=才会改变)
//		* 先通过*this(即d1)拷贝出一个tmp,
//		* 对tmp进行加法操作就不会改变d1对象了
//		*/
//
//		/*
//		* 复用 “+=运算符重载” ,只要 += 到d1的拷贝tmp上即可,
//		* 就不会改变到d1对象,通过tmp返回d1的加法结果:
//		*/
//		tmp += day;
//
//		//通过tmp返回d1的加法结果:
//		return tmp;
//		/*
//		* 这里tmp是d1的拷贝,出了函数就销毁了,
//		* 所以需要传值返回拷贝一份回主函数
//		*/
//	}
//
//
private:
//	int _year;
//	int _month;
//	int _day;
//};

写一个函数判断自定义类型大小(以日期类对象为例):
//bool Greater(Date x, Date y)
//{
//	//“年大就大”:
//	if (x._year > y._year)
//	{
//		return true;
//	}
//	//"年相等,月大就大":
//	else if (x._year == y._year && x._month > y._month)
//	{
//		return true;
//	}
//	//"年相等,月相等,天大就大":
//	else if (x._year == y._year && x._month == y._month && x._day > y._day)
//	{
//		return true;
//	}
//
//	//上面已经写出了所有大于的情况,执行到这说明是小于等于:
//	return false;  //返回false
//}



写一个函数判断自定义类型大小(以日期类对象为例):
//bool operator>(Date x, Date y) 
///*
//* 为了在自己定义自定义类型比较函数时,
//* 函数命名能够更规范,可以使用 operator> 表示
//* 这是比较自定义类型大小的函数
//*/
//{
//	//“年大就大”:
//	if (x._year > y._year)
//	{
//		return true;
//	}
//	//"年相等,月大就大":
//	else if (x._year == y._year && x._month > x._month)
//	{
//		return true;
//	}
//	//"年相等,月相等,天大就大":
//	else if (x._year == y._year && x._month == x._month && x._day > y._day)
//	{
//		return true;
//	}
//
//	//上面已经写出了所有大于的情况,执行到这说明是小于等于:
//	return false;  //返回false
//}

判断对象是否相等的函数(以日期类为例):
//bool Equal(Date x, Date y)
//{
//	/*
//	* 实现前需要先把Date类的成员变量权限设置为共有,
//	* 才能在类外部进行调用:
//	*/
//	return x._year == y._year
//		&& x._month == y._month
//		&& x._day == y._day;
//	//比较两日期类对象是否相等只要判断两者年月日是否相等即可
//}

//判断对象是否相等的函数(以日期类为例):
//bool operator==(Date x, Date y)
///*
//* 为了在自己定义自定义类型比较函数时,
//* 函数命名能够更规范,可以使用 operator== 表示
//* 这是判断自定义类型是否相等的函数
//*/
//{
//	/*
//	* 实现前需要先把Date类的成员变量权限设置为共有,
//	* 才能在类外部进行调用:
//	*/
//	return x._year == y._year
//		&& x._month == y._month
//		&& x._day == y._day;
//	//比较两日期类对象是否相等只要判断两者年月日是否相等即可
//}

//int main()
//{
//	Date d1;
//	Date d2(2023, 10, 22);
//
//	/*
//	* 内置类型对象可以直接使用各种运算符,
//	* 那自定义类型呢?
//	*/
//
//	//内置类型:
//	int x = 1, y = 2;
//	bool ret1 = x > y;
//	bool ret2 = x == y;
//	/*
//	* 内置类型都是简单类型,是编程语言自己定义的,
//	* 编译器能直接转换成指令(通过汇编指令cmp完成比较的各种行为)。
//	* 自定义类型则不支持,需要自己定义比较规则
//	*/
//	//自定义类型:
//	d1 == d2; //自定义类型无法使用 “==” 运算符
//	d1 > d2; //自定义类型无法使用 “>” 运算符
//
//	//通过函数判断d1和d2的大小:
//	cout << Greater(d1, d2) << endl;
//	cout << operator>(d1, d2) << endl;
//
//	//通过函数判断d1和d2是否相等:
//	cout << Equal(d1, d2) << endl;
//	cout << operator==(d1, d2) << endl;
//
//	/*
//	* 为进行自定义类型对象的比较定义一个比较规则(函数)
//	* 
//	* operator> 和 operator== 都是运算符重载,
//	* 使用运算符重载作为该函数的名字,更加规范
//	*/
//
//	/*
//	* 为了让自定义类型比较更接近内置类型比较,
//	* 可以直接写成:(d1 > d2)、(d1 == d2)
//	* 可以看起来就和内置类型的比较一样了,
//	* 
//	* 这里加()是因为 <<流插入运算符 优先级比较高,
//	* 所以要加()调整优先级
//	* 
//	* 这里虽然看起来和内置类型比较一样,
//	* 但编译器实际还是调用了运算符重载的函数:
//	* d1 > d2  编译器会调用  operator>(d1, d2)函数
//	* d1 == d2  编译器会调用  operator==(d1, d2)函数
//	* 
//	* 如果没有使用对应的运算符重载作为对应的比较函数名的话,
//	* 就不能像 d1 > d2 这样去比较自定义类型了,
//	* 因为编译器找不到对应的运算符重载函数
//	*/
//	cout << (d1 > d2) << endl; //调用operator
//	cout << (d1 == d2) << endl;
//
//	/*
//	* 写了运算符重载的好处:
//	* 1、可以像比较内置类型一样来比较自定义类型对象
//	* 2、更加规范,不会说每个人定义的自定义比较函数名都不一样
//	*/
//
//	/*
//	* 运算符重载 和 函数重载 之间没有关联:
//	* 运算符重载:让自定义类型可以直接使用运算符(像内置类型一样)
//	* 函数重载:允许有参数不同的多个同名函数
//	*/
//
//
//	cout << (d1 > d2) << endl; 
//	/*
//	* 实际编译器执行:
//	* 调用Date类中的成员函数 -- d1.operator>(d2)
//	* 实际执行时 -- d1.operator>(&d1, d2)
//	* &d1 为隐藏的this指针存储的地址
//	*/
//
//	cout << (d1 == d2) << endl;
//	/*
//	* 实际编译器执行:
//	* 调用Date类中的成员函数 -- d1.operator==(d2)
//	* 实际执行时 -- d1.operator==(&d1, d2)
//	* &d1 为隐藏的this指针存储的地址
//	*/
//
//	d1 - d2;
//
//	d2 += 50;
//	//调用:Date& operator+=(int day)
//	d2.Print();
//
//	Date ret = d1 + 50; //因为是传值返回所以需要一个对象接收
//	//调用:Date operator+(int day)
//	d1.Print(); //d1本身不会改变
//	ret.Print(); //ret 接收 d1+整型的结果 
//
//	return 0;
//}


//运算符重载 -- 让自定义类型能够像内置类型一样使用运算符


//class Date
//{
//public:
//
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//
//	//赋值运算符(=)重载 -- d1=d3 :
//	Date& operator=(const Date& d)
//		//this指针存储d1地址,形参d存储d3“别名”:
//	{
//		//应对“自己给自己赋值”的情况:
//		if (this != &d)
//		/*
//		* this 存储着d1的地址,
//		* &d 为形参接收的对象地址,
//		* 如果this == &d,说明是“自己给自己赋值”的情况,
//		* 就没必要进行赋值操作了,直接返回*this对象本身即可
//		*/
//		{
//			//排除“自己给自己赋值”的情况后,进行赋值操作:
//			_year = d._year;
//			_month = d._month;
//			_day = d._day;
//		}
//
//		return *this; 
//		//返回*this“别名”,即d1“别名”,省略拷贝操作
//	}
//
//private:
//	int _year;
//	int _month;
//	int _day;
//
//};
//
//int main()
//{
//	Date d1(2023, 10, 24);
//	Date d2(2022, 1, 1);
//	//定义初始化对象 -- 调用构造函数 
//
//	//拷贝构造:
//	Date d3(d1); 
//	//用d1拷贝出d3 -- 调用拷贝构造函数
//	//(一个已经存在的对象去拷贝初始化另一个对象出来)
//
//	//赋值重载:
//	d1 = d3; 
//	/*
//	* 把对象(d3)赋值拷贝给另一个对象(d1)
//	*(两个已经存在的对象拷贝)
//	* 这时就需要进行 赋值运算符(=)的重载,
//	* 调用:operator=
//	*/
//	
//	d2 = d1 = d3;
//	/*
//	* 连续赋值:
//	* 先将d3赋值给d1,d1作为返回值再赋值给d2
//	* 所以调用operator=后要返回 d1(“别名”)
//	*/
//
//	d1 = d1; //“自己给自己赋值”
//	/*
//	* 可以自己给自己赋值,
//	* 但是实际调用operator=时没必要赋值,
//	* 直接返回*this对象本身即可
//	*/
//
//	/*
//	* 我们不显式定义operator=赋值运算符重载的话,
//	* 编译器会自己生成一个默认的operator=
//	* 
//	* 默认生成的operator=函数的行为和拷贝构造的行为类似,
//	* 针对内置类型成员变量,operator=函数会完成值拷贝(浅拷贝);
//	* 针对自定义类型成员变量,
//	* operator=函数会调用该自定义类型的operator=函数
//	* 
//	* 所以对于 Date类 和 MyQueue类,可以不显式写operator=函数,
//	* 默认生成的operator=函数就足够了,Date类只有内置类型只需浅拷贝,
//	* MyQueue类中会的自定义类型Stack类会调用Stack类的operator=函数
//	* 
//	* 而Stack类就必须自己实现operator=函数了,因为其中有“资源”,
//	* 需要对其进行深拷贝
//	*/
//
//	return 0;
//}


/*
*			默认生成的:
* 
* 构造函数 和 析构函数 的行为类似,
* 针对内置类型成员变量:不进行处理(为随机值)
* 针对自定义类型成员变量:会调用该自定义类型的 构造函数 或 析构函数
* 
* 拷贝构造函数 和 赋值运算符重载函数 的行为类似,
* 针对内置类型成员变量:进行值拷贝(浅拷贝)
* 针对自定义类型成员变量:会调用该自定义类型的 拷贝构造函数 或 赋值运算符重载函数
*/

Guess you like

Origin blog.csdn.net/weixin_63176266/article/details/134431227