Initialize C class members and join the location bar in your MFC application
Paul Dilascia
problem
My problem is about initializing C class members. I have seen a lot of such code (including it in your column):
CsomeClass :: csomeclass ()
{
X = 0;
Y = 1;
}
And where else is written as below:
CsomeClass :: csomeclass (): x (0), y (1)
{
}
Some of my programmers say that the second method is better, but they don't know why it is. Can you tell me the difference between these two membership initialization methods?
Reply
Technically, your programmer friend is right, but in most cases, the two actually have no difference. There are two reasons such that we choose a second syntax, which is called a member initialization list: one reason is necessary, the other is only considered for efficiency.
Let's take a look at the first reason - the need. Imagine that you have a class member, it itself is a class or structure, and there is only one constructor with a parameter.
Class cmember {
PUBLIC:
Cmember (int x) {...}
}
Because cmember has an explicit declared constructor, the compiler does not generate a default constructor (without parameters), so there is no integer that cannot create an instance of CMEMBER.
Cmember * pm = new cmember; // error !!
CMEMBER * PM = New cmember (2); // ok
If cmember is a member of another class, how do you initialize it? You must use a member to initialize a list.
Class CMYCLASS {
Cmember m_member;
PUBLIC:
CMYCLASS ();
}
/ / Must use the member initialization list
CMYCLASS :: CMYCLASS (): m_member (2)
{
•••••
}
There is no other way to pass the parameters to m_member, if the member is a constant object or reference is also. According to the rules of C , constant objects and references cannot be assigned, they can only be initialized.
The second reason is for efficiency, when the member class has a default constructor and an assignment operator. The MFC's CString provides a perfect example. Assume that you have a class CMYClass member M_STR, you want to initialize it into "Yada Yada.". You have two options:
CMYCLASS :: CMYCLASS () {
// Use assignment operators
// cstring :: Operator = (lpctstr);
m_str = _t ("Yada Yada");
}
// Use class members list
// and constructor cstring :: CString (lpctstr)
CMYCLASS :: CMYCLASS (): m_str (_t ("Yada Yada"))
{
}
Is there something difference between them? Yes. The compiler always ensures that all member objects are initialized before the constructor is executed, so the code compiled in the first example will call CString :: CString to initialize M_STR, which is completed before controlling the assignment statement. In the second example, the compiler generates a call to the CString :: CString (LPCTSTR) and passes "YADA YADA" to this function. The result is that two CSTRING functions (constructor and assignment operators) are called in the first example, and only one function is called in the second example. This doesn't matter in the case of CString, because the default constructor is inline, CSTRING is only assigned memory as a string when needed (ie, when you actually assign). However, in general, the repetitive function call is a waste of resources, especially when constructor and assignment operators allocate memory. In some big classes, you may have a constructor and an assignment operator to call the same init function responsible for allocating a large amount of memory space. In this case, you must use an initialization list to avoid not allocating two memory. Inside the type such as INTS or LONGS or other type without constructor, there is no performance difference in the initialization list and the two methods assigned in the constructor. Regardless of the way, only one assignment will occur. Some programmers say that you should always use the initial list to maintain a good habit, but I have never found that there is difficulty in converting the two methods. In the programming style, I tend to use assignments in the body, because more space is used to format and add a comment, you can write this statement: x = y = z = 0; or MEMSET (this, 0 SIZEOF (this));
Note that the second piece is definitely non-objective.
When I consider the problem of initialization list, there is a strange feature that I should warn you, it is a member of the C initialization class, which is initialized in the order of statements, rather than in the order in the initialization list.
Class CMYCLASS {
CMYCLASS (INT X, INT Y);
INT M_X;
INT M_Y;
}
CMYCLASS :: CMYCLASS (INT I): M_Y (i), m_x (m_y)
{
}
You may think that the above code will do M_Y = I, then do M_X = M_y, and finally they have the same value. However, the compiler first initializes M_x, then M_Y, because they are in this order. The result is that M_x will have an unpredictable value. My example is designed to illustrate this, but this BUG will appear more natural. There are two ways to avoid it, one is always in accordance with the order in which you want them to be initialized, the second is that if you decide to use the initialization list, you always follow these members in order to declare the order. This will help eliminate confusion.