Keywords: constructors, shallow copy, deep copy, stack (stack), heap heap, assignment operator
Summary:
In object-oriented programming, the mutual copying and assignment between objects is a frequent operation.
If an object is initialized at the same time as it is declared, it is called a copy operation. For example:
Class1 A ("AF"); Class1 B=a;
At this point it actually invokes a shallow copy operation such as B (A).
If the object is declared, the assignment operation is called assignment. For example:
Class1 A ("AF"); Class1 B;
B=a;
The default assignment function for the class that is actually called at this time is b.operator= (A);
Whether it is a shallow copy or an assignment operation, it has a default definition. That is, even if we do not overload these two operation, we can still run.
So, do we need to overload these two kinds of operation?
The answer is: In general, we need to manually write destructors for classes that require overload copy functions and assignment operators.
the assignment operators for classes are described below
How to allocate memory for objects in 1.c++
In C + +, an instance of an object needs to be allocated memory size when it is compiled, so the system allocates memory on the stack. This is completely different from C #! Remember: In C #, all classes are reference type, and to create an entity of a class, you must allocate space on the heap with new and return the reference that point to its address on the stack.
Therefore, in C + +, as long as the instance is declared, after the program compiles, it is allocated the corresponding memory space, and the values of each domain within the entity are determined by its constructor.
For example:
Class A
{
Public
A ()
{
}
A (int Id,char *t_name)
{
_id=id;
Name=new Char[strlen (t_name) +1];
strcpy (Name,t_name);
}
Private
Char *username;
int _id;
}
int main ()
{
A (1, "Herengang");
A b;
}
After the program is compiled, A and B are allocated the corresponding memory size on the stack. Only the domain of object A is initialized, and B is a random value.
Its memory allocations are as follows:
2. Assignment operators by default
If we do the following:
B=a;
Then it executes the default assignment operation defined by default. The so-called default assignment operation refers to all the fields in the stack that are in the object and replicate accordingly. However, if the object has a field on the heap, it does not allocate space on the heap for the copied object, but only points to the same address on the same heap.
After performing the default assignment operation such as B=a, its memory allocation is as follows:
Therefore, for the default assignment operation, there is no problem if there is no space on the heap in the object domain. However, if the space on the heap needs to be requested within the object domain, the same chunk of memory on the heap is released twice in a row when the object is being refactored, resulting in an exception.
~a ()
{
Delete name;
}
3. Workaround--Overload (overload) assignment operator
Therefore, we must overload the assignment operator for the case where the object's domain allocates memory on the heap. When copying between objects, we have to point the member fields of different objects to their different heap addresses--if the member domain belongs to the heap.
Therefore, the code after overloading the assignment operator is as follows: Class A
{
Public
A ()
{
}
A (int Id,char *t_name)
{
_id=id;
Name=new Char[strlen (t_name) +1];
strcpy (Name,t_name);
}
a& operator = (a& A)
Note: It is important to return a reference to an object here, otherwise its value disappears immediately after it returns!
{
if (name!=null)
Delete name;
this->_id=a._id;
int Len=strlen (a.name);
Name=new char[len+1];
strcpy (Name,a.name);
return *this;
}
~a ()
{
cout<< "~destructor" <<endl;
Delete name;
}
int _id;
Char *name;
};
int main ()
{
A (1, "Herengang");
A b;
B=a;
}
Its memory allocations are as follows:
In this way, at the object A, a, the corresponding scope is exited, it calls the corresponding destructor, and then releases the memory belonging to different heap space, the program ends normally.
References
Overloading of deep copy functions of a class
public class A
{
Public
...
A (a &a);//Overloaded copy function
a& operator= (A &b);//Overloaded Assignment function
Or we can overload the assignment operator void operator= (A &a), that is, no value is returned. If this is the case, he will not support the customer's buy-in chain assignment, such as a=b=c'll be prohibited!
Private
int _id;
Char *username;
}
A::a (A &a)
{
_id=a._id;
Username=new Char[strlen (a.username) +1];
if (username!=null)
strcpy (Username,a.usernam);
}
a& a::operaton= (A &a)
{
if (this==&a)//Q: What needs to be judged on this condition? (not required, just optimization). Answer: Hint: Consider a=a such an operation.
return *this;
if (username!=null)
Delete username;
_id=a._id;
Username=new Char[strlen (a.username) +1];
if (username!=null)
strcpy (Username,a.usernam);
return *this;
}
Another way to do this:
void a::operation= (A &a)
{
if (username!=null)
Delete username;
_id=a._id;
Username=new Char[strlen (a.username) +1];
if (username!=null)
strcpy (Username,a.usernam);
}
In fact, it can be seen from the above that the assignment operator is very similar to the copy function. Only the assignment function preferably has a return value (for chained assignment), and it is better to return a reference to the object (why not the object itself?). Note2 is explained), and the copy function does not need to return any. At the same time, the assignment function first releases the heap space of the object itself (if necessary) and then makes other operation. The copy function does not need this, because the object does not allocate heap space at this time.
Note1:
Do not pass objects by value to the function. If the object has an internal pointer to the dynamically allocated heap memory, do not consider passing the object by value to the function, by reference. And remember: If the function cannot change the state of the Parameter object and the state of the target object, use the const modifier
Note2: Question:
For classes whose members need to dynamically request heap space for the object of the class, we all know that it is best to overload its assignment function and copy function. It is no doubt that the copy constructor has no return type. The assignment function can return many types, such as the void above, the class itself Class1, and the class's reference class & Q, what are the similarities and differences in the return of these kinds of assignment functions?
A: 1 if the assignment function returns void, we know that its only point to note is that it does not support chained assignment operations, i.e. a=b=c is not allowed!
2 There is an essential difference between returning a class object itself, or a reference to a class object!
First: If it returns the class object itself.
A operator = (a& a)
{
if (name!=null)
Delete name;
this->_id=a._id;
int Len=strlen (a.name);
Name=new char[len+1];
strcpy (Name,a.name);
return *this;
}
The process is this:
Class1 A ("Herengnag");
Class1 B;
B=a;
Seemingly simple assignment operation, all of its procedures are as follows:
1 releasing an object's original heap resource
2 re-application of heap space
3 Copy the value of the source to the object's heap space
4 Create temporary object (call temporary object copy constructor), return temporary object
5. End of temporary object, call temporary object destructor, release temporary object heap memory
My God, it's complicated!!
However, in these steps, if the 4th step, we do not overload copy function, that is, no deep copy. Then, when the 5th step frees the heap space for the temporary object, it will release the heap space that is the same piece of the target object. This results in an error when the target object B scope ends calling the destructor!!
Therefore, if the assignment operator returns the class object itself, then be sure to overload the copy function of the class (deep copy)!
Second: If the assignment operator returns a reference to an object,
a& operator = (a& A)
{
if (name!=null)
Delete name;
this->_id=a._id;
int Len=strlen (a.name);
Name=new char[len+1];
strcpy (Name,a.name);
return *this;
}
Then the process is as follows:
1 release the heap space occupied by the original object
1. Request a new heap of memory
2 Copy the value of the heap memory of the source object to the new heap memory
3 Returns a reference to the source object
4 end.
Therefore, if the assignment operator returns an object reference, then it does not call the copy constructor of the class, which is the key to the problem!!
The complete code is as follows:
Virtual.cpp:Defines the entry point for the console application.
//
#include "stdafx.h"
#include "string.h"
#include "Stdlib.h"
#include "Assert.h"
Class Complex
{
Public
int real;
int virt;
Public
Complex (){real=virt=0;}
Complex (int treal,int tvirt){real=treal;virt=tvirt;}
Complex operator+ (const complex &X)
{
Real+=x.real;
Virt+=x.virt;
return *this;
}
Complex operator= (const complex &X)
{
Return complex (X.real,x.virt);
}
};
Class A
{
Public
A (){m_username=null;printf ("NULL constructor");}
A (char *username)
{
int Len;
Len=strlen (username);
M_username=new char[len+1];//(char*) malloc (sizeof (len+1));
strcpy (M_username,username);
printf ("\nusername is%s\n", m_username);
}
A (a &a);
A operator= (a &b);
int test (const int &x)
{
return x;
}
Virtual ~a ()
{
if (m_username)
{
Delete M_username;
printf ("\na is destructed\n");
}
}
Protected
Char *m_username;
};
A::a (A &a)
{
int Len=strlen (a.m_username);
This->m_username=new char[len+2];
strcpy (M_username,a.m_username);
strcat (M_username, "F");
printf ("\ndeep copy function");
}
A a::operator= (a &b)
{
if (m_username)
Delete M_username;
int Len=strlen (b.m_username);
This->m_username=new char[len+1];
strcpy (M_username,b.m_username);
printf ("copied successfully!");
return *this;
}
Class B:public A
{
Public
B (char *username,char *password): A (username)
{
int Len=strlen (password) +1;
M_password=new char[len];//(char *) malloc (sizeof (LEN));
strcpy (M_password,password);
printf ("username:%s,password:%s\n", M_username,m_password);
}
~b ()
{
delete m_password;
printf ("b is destructed\n");
}
Protected:
char *m_password;
};
Int main (int argc, char* argv[])
{
// b b ( "Herengang", "982135");
// a *a=&b;
// delete a;
a a ("haha");
A b;
printf ("\nbegin to invoke copy function");
b=a;
// printf ("%d", B.test (2));
//complex x (1,3), Y (1,4);
//x= (x+y);
//printf ("%d,%d", X.real,x.virt);
return 0;
}
1 Overloaded assignment operator returns the result of the run of the class object
Obviously, the operator finally called the copy constructor
2 Overloaded assignment operator returns the result of a run result for a class object reference
Obviously, the copy constructor is not called
C + + Nature: Overloading of class assignment operators =, and deep and shallow copies