There are many operations on variables in C + +, such as assignment, initialization, etc. Many people confuse assignment with initialization. Let's study the difference between assignment and initialization. First of all:
initialization | assignment |
---|---|
This can only be done once in the variable lifecycle | It can be performed an unlimited number of times |
Variables of any type must be initialized (if the basic type has no initial value, it can be regarded as calling the default constructor, and the object must call the constructor for initialization. If there is no constructor, the default constructor will be called, and if there is a constructor, one of them must be called. When calling the nonparametric constructor, the parentheses can be omitted, which is also regarded as initialization) | not essential |
Must be declared immediately after the variable name | Can be anywhere in the variable lifecycle |
In the class constructor, initialization must be written in the initialization list | Can be anywhere in the constructor of a class |
You can use either (), or = (if it is a custom type, the constructor must have only one parameter and the constructor of the class is not explicitly specified. You cannot use =) | Only = (overloaded operator) can be used for narrow assignment |
Reference type initialization is a variable that specifies the point to | The assignment of reference type is regarded as the assignment of original variable |
The = or () in initialization should not be regarded as an operator, but only as a flag, so it has no return value (not the return value of void type, but directly, just like a break statement has no return value) | The basic type returns its own reference. The user-defined type can be modified as needed. Generally, it also returns its own reference |
Next, we illustrate the difference between assignment and initialization through several specific examples.
Example 1
int main() { int a = 5;//initialization a = 3;//assignment return 0; }
Although this example is short, it shows the syntactic difference between initialization and assignment. Of course, this is not enough to explain the actual difference between initialization and assignment.
Example 2
#include<iostream> void myfunc() { static int a = 0;//Static variable initialization, only executed once static int b;//Static variable b = 0;//The assignment of variables is executed every time the function is called a++; b++; std::cout << a << ' ' << b << std::endl; } int main() { for (int i = 0; i < 10; i++) myfunc(); return 0; }
Operation results:
A and b here are static variables. Why are the results different? The reason is that a=1 is initialization, which will only be executed once in the life cycle of a (from the first call to the end of the program), while b=1 is assignment, which does not belong to variable declaration code, so each call will be executed.
Example 3
#include<iostream> class MyClass { public: MyClass() { std::cout << "Parameterless constructor called" << std::endl; } MyClass(int x) { std::cout << "A parameterized constructor is called" << x << std::endl; } void operator=(int x) { std::cout << "operator=Called" << x << std::endl; } }; void func(int t) { std::cout << "The first" << t << "Call times func" << std::endl; static MyClass a = 10;//Static variable initialization, implicitly call the constructor, and execute it only once in the whole program, not assignment! static MyClass b;//Static variable initialization, call parameterless constructor b = 20;//Assignment, calling operator =, is different from initialization! MyClass c(10);//Ordinary variable initialization, implicit call constructor MyClass d;//Ordinary variable initialization, call parameterless constructor d = 10;//assignment } int main() { for (int i = 0; i < 5; i++) { func(i); std::cout << std::endl; } return 0; }
Operation results:
It can be seen from this example that the initialization of static variables is only performed once, the initialization of ordinary variables is performed once in each life cycle, and all variable assignment operations are executed every time the function is called.
Example 4
#include<iostream> class MyClass { public: MyClass() { std::cout << "Parameterless constructor called" << std::endl; } MyClass(int x) { std::cout << "A parameterized constructor is called" << x << std::endl; } void operator=(int x) { std::cout << "operator=Called" << x << std::endl; } }; class Test { private: MyClass obj; public: Test() { std::cout << "Not initialized in constructor:" << std::endl; std::cout << std::endl; } Test(int x) { std::cout << "Assignment in constructor:" << std::endl; obj = x;//assignment std::cout << std::endl; } Test(int x, int y) :obj(x)//initialization //Setting y is only for overloading { std::cout << "Initialize in constructor:" << std::endl; std::cout << std::endl; } }; int main() { Test a; Test b(7); Test c(5, 0); return 0; }
Operation results:
Through this example, we can draw two conclusions:
1. Members in the constructor initialization list will be initialized, and members not in the initialization list will be called the parameterless constructor. If a member does not have a parameterless constructor and is not in the initialization list, an error will be reported;
2. Member initialization is performed before any code in the constructor.
Through conclusion 1, we can conclude that if you want to set member variables in the constructor, initialization is faster than assignment, because the constructor will be called before assignment. If you do not initialize in the initialization list, it will cause repeated calls and waste of time.
Example 5
#include<iostream> class MyClass { public: MyClass() { std::cout << "Parameterless constructor called" << std::endl; } MyClass(int x) { std::cout << "A parameterized constructor is called" << x << std::endl; } void operator=(int x) { std::cout << "operator=Called" << x << std::endl; } }; class Father { protected: MyClass obj; public: Father() { std::cout << "Parent class parameterless constructor" << std::endl; std::cout << std::endl; } Father(int x) :obj(x)//initialization { std::cout << "The parent class has a parameter constructor" << std::endl; std::cout << std::endl; } }; class Son :public Father { private: MyClass son_obj; public: Son() { std::cout << "Subclass parameterless constructor" << std::endl; std::cout << std::endl; } Son(int x) :son_obj(x) { std::cout << "Subclass single parameter constructor" << std::endl; std::cout << std::endl; } Son(int x, int y) :/*obj(x),Cannot initialize like this*/Father(x),son_obj(y) { std::cout << "Subclass two parameter constructor 1" << std::endl; std::cout << std::endl; } Son(int x, int y, int i) :Father(x)//i is set for overloading { son_obj = y; std::cout << "Subclass two parameter constructor 2" << std::endl; std::cout << std::endl; } }; int main() { Father a; std::cout << "-------------------------" << std::endl; Father b(1); std::cout << "-------------------------" << std::endl; Son c; std::cout << "-------------------------" << std::endl; Son d(2); std::cout << "-------------------------" << std::endl; Son e(3, 4); std::cout << "-------------------------" << std::endl; Son f(5, 6, 0); return 0; }
Operation results:
This example shows the initialization sequence with inheritance: in any case, first initialize the parent class, then initialize the members in the subclass initialization list, and finally execute the code in the subclass constructor. Another point: the order in the initialization list has nothing to do with the actual initialization order!!! The actual initialization sequence is initialized according to the declaration sequence, not according to the order of the initialization list!!!
At this point, I believe you can distinguish and reasonably use assignment and initialization. That's all for today. I'll see you next time!