Today Aear is talking about Class.ctor, constructor, and Class.dtor, destructor. I believe we all know constructor and destructor is what to do with the basic function I will not nonsense. Let's look at a simple example of the efficiency issue:
Class SomeClass; Forward declaration
Class Anotherclass {
Private
SomeClass someclassinstance;
Public
Anotherclass (const SomeClass & Para) {someclassinstance = Para;};
~anotherclass ();
};
Perhaps this is the code that many beginners often write, Aear has written before. Let's take a look at what's wrong with this piece of code.
The first thing to note is that all member will be initialized before a class instantiation, and if member is a class, then the constructor of that class will be called. In other words, SomeClass's constructor is already running before running Anotherclass's constructor. In the next code, Someclassinstance is re-executed again = operation. That is, when we give someclassinstance an initial value, we call the method of 2 times SomeClass. This waste is too big, the standard way is to use the initialization list, as follows:
Anotherclass (const SomeClass & Para): Someclassinstance (Para) {};
If you have more than one class member, you can use "," to split, such as:
Anotherclass (const SomeClass & Para1, UINT32 Para2):
Someclassinstance (PARA1),
Secondattr (PARA2),
Thirdattr (PARA3) {};
It is important to note that the order of initialization of class members and the order in which they are declared in a class should be consistent. This is controlled by compiler and is not based on the order of initialization you provide in the Anotherclass constructor. So, if you want to initialize the thirdattr first, and then upload the thirdattr to secondattr as the initialization parameter, it will fail. Only changes in the order of declarations will succeed.
Similarly, using a copy constructor is more efficient when declaring a class variable to be attached to an initial value:
===== Error =====
Class X1;
x1 = x2;
===== correct =====
Class X1 (x2);
=================== Split Line ===================
As you can see from the example above, almost all classes require a copy constructor, which is ClassName (const ClassName &). It is also worth noting that if a copy constructor is provided, it is generally necessary to provide a "=" operation, i.e. ClassName & operator = (const ClassName &), and when it comes to operator =, it is also necessary to emphasize implicit Type conversion question, which will be described in detail in a later chapter. As for why to provide operator =, give a simple example:
Class1 {
Public
Class1 () {p = new int[100];};
~class1 () {delete[] p;};
Private
Char* p;
} x1, x2;
If Class1 does not provide operator =, then when running X1 = x2, C + + will run the most basic copy operation, that is, X1.P = x2.p, then delete p is executed when X1 is released. At this time X2 again to visit p,p has become illegal pointer. Maybe someone will say, I will not use X1 = x2 so dangerous operation, let us look at the more covert operation, examples are as follows:
void func (Class1 Para) {...};
Func (x1);
At this point, C + + calls the copy constructor of Class1 to copy the parameters from the X1 to the Para, and if Class1 does not provide copy constructor, then c+ + performs a simple copy operation, which is PARA.P = x1. When Func returns, Para is freed, calls Para.~class1 (), and delete p; then x1.p becomes an illegal pointer.
So everyone knows why copy constructor and operator are available at the same time. Especially if there is a pointer in class, the above 2 method must be provided. If you do not want to provide, you can set them to private, the code is as follows:
Class1 {
...
Private
Class1 (const Class1 &);
Class1 & operator = (const Class1 &);
}
This will cause the error when the other person executes = and func ().
Also, when declaring a constructor, a single-argument constructor is best declared with explicit, for example:
Class1 {
Public
Class1 (int Para) {...}
...
};
where Class1 (int Para) is a single-argument constructor, perform the following actions, such as:
Class1 x1 = 2;
, because 2 is not Class1, C + + will convert with implicit type, that is, convert 2 to Class1, so it calls Class1 (2) and then operator = character value to X1. This kind of operation often produces many problems. For example, if we provide operator = =, then in the case of if (x1 = = 2), C + + will do similar operations, may produce the results we do not need. Therefore, for this single-parameter constructor it is best to make the following statement:
explicit Class1 (int Para) {...}
Do this again class1 x1 = 2, the time will be error, explicit means that C + + compiler can not do the implicit type conversion, must be done by the programmer type cast, such as:
Class1 x1 = static_cast<class1> (2) will succeed.
=================== Split Line ===================
When running constructor, it is important to note that if you want to initialize the code that will throw exception in constructor, you must catch it in constructor. Like what:
Class1 {
Class1 ()
{
PInt = new INT[100];
try {
PClass2 = new PClass2;
}catch (...)
{delete pInt; throw;};
}
}
You see, if you don't catch pClass2, the memory allocated by Exception,pint will not be freed, because if constructor fails, C + + will not call destructor.
=================== Split Line ===================
Finally, with regard to destructor, it should be noted that if the inherited base Class,destructor must be virtual. Like what:
BaseClass ()
{
Public
BaseClass ();
Virtual ~baseclass ();
}
Derivedclass:public BaseClass ()
{
Public
DerivedClass ();
~derivedclass ();
}
BaseClass * pbase = Static_cast<baseclass *> (new DerivedClass ());
Delete pbase;
If BaseClass's destructor is virtual, then the correct ctor Dtor call order is:
BaseClass ();
DerivedClass ();
~derivedclass ();
~baseclass ();
If it is not virtual, the call order is:
BaseClass ();
DerivedClass ();
~baseclass ();
In other words, DerivedClass's derived class cannot be called correctly, mainly because C + + does not know that you delete the derivedclass when you delete it, so you need to set BaseClass's dtor to virtual so you can use Vptr looks for destructor in Vtbl, which makes it possible to call destructor correctly.
=================== Split Line ===================
As you can see from the above example, if you are a derived class, call the constructor of the base class, and the constructor of the base class are called during the creation of the multi-layered derived class. destructor. Therefore, to improve efficiency, you can use non-derived classes in the critical code short.
Some might say that all constructor and destructor are compiler inline, but even if the inline and base class constructor do nothing, C + + sets vptr for each class, There are also overhead that are not needed. Of course, we get efficiency at the same time, the loss of scalability, good program hierarchy and so on, we have to weigh according to the specific situation.
Go C + + basic and Design Pattern series ctor & Dtor