C ++ FAQ reading notes [4] - constructor

xiaoxiao2021-03-06  27

[10.1] What is the constructor?

The constructor is used to build an object in a messy memory.

The constructor is like "initialization functions". They can convert a series of irregularities into a living object. Minimize, they initialize the space used inside. They also allocate resources for objects (memory, semaphore, socket, etc.)

"CTOR" is an abbreviation for constructor

[10.2] Is LIST X and LIST X () What is different? These two are too different!

Suppose List is the name of the class, then f () is a List object that has declated a local called X.

Void f () {List x; // Locally a list of List called X}

But the function g () defines a function called X (), which will return a list object:

Void g () {list x (); // a function of returning a list of a list object}

[10.3] How can I call another constructor from another constructor to initialize? Don't do this.

The reason is: If you call another constructor, the compiler will initialize a temporary object without initializing this object. You can initialize two constructor with default parameters, or you can share public code in private init () member functions.

[10.4] Does the default constructor for the Fred class always fred :: fred ()? No, the default constructor is a constructor that can be called without parameters. There is a default constructor that does not have a parameter of the constructor:

Class Fred {public: fred (); // The default constructor: can be called without parameters. ....}; but the default constructor with parameters may occur as long as they have the default initial parameter value:

Class Fred {public: fred (int i = 3, int J = 5); // Default constructor: You can be called without parameters. // ...};

[10.5] Which constructor I will call when I build a Fred object array? It will call the default constructor of the FRED (exceptions).

There is no way to call another constructor in this case. If the class fred does not have the default constructor, build a Fred object array will have an error in the compile period.

Class Fred {public: Fred (INT i, INT J); // ... assuming that there is no default constructor in the Fred class} int main () {Fred a [10]; // error: no default constructor fred * P = new fred [10]; // Error: no default constructor}

However, if you construct a std :: Vector

When the object group is not a array (you should do this, because the data is usually a devil for your program), you don't have to have a default constructor in the Fred class, because you can STD :: Vector A Fred object is used to initialize the instance:

#include

Int main () {std :: vector

a (10, Fred (5, 7)); // 10 Fred objects in Std :: Vector use FRED (5, 7) to initialize. }

Although you should use Std :: Vector instead of data, it is also a correct choice to use the array. For this case, there is a "external array initialization" syntax, the following is its usage:

Class Fred {public: Fred (INT I, INT J); // Assume that there is no default constructor} in the Fred class}; int main () {Fred A [10] = {FRED (5, 7), FRED (5 , 7), Fred (5, 7), FRED (5, 7), Fred (5, 7), Fred (5, 7), Fred (5, 7), Fred (5, 7), Fred (5, 7)}; // These 10 FRED objects are initialized with FRED (5, 7). // ...} Of course, you don't need to make Fred (5, 7) initialization for all items, you can use any parameters to initialize, or even parameters or other variables. The key is that this approach is feasible, but there is no std :: vector. Remember: Array is the devil unless there is no way to use an array, other cases use std :: vector instead

[10.6] My constructor should be "initialized list" or "assignment"? The constructor should initialize all the members objects in the initial list.

For example, constructor is initialized by initialization list: fred :: fred (): x_ (wherever) {} to initialize the member object X_. From the performance considered, Note Whatver represents cannot automatically let a separate object are built and copied to X_. If the value type is similar to the value of Whatever, it can be configured directly from the inside of X_.

Unlike the following, Fred :: Fred () is different from the following. In this case, the expression wherever causes a separate, temporary object, which is passed to the assignment operator of the X_ object, and then it is designed to it. This is not efficient.

There is another source without efficiency: In the case of assignment, the default constructor of the object assigns some class memory or open some default files. Such a job is completely useless if the object is turned off if the Whatever expression or assignment operator is turned off, and the file is turned off, and the memory is released. (For example, when the default constructor is not assigned a sufficiently large memory pool or open the wrong file)

[10.7] Can I use the THIS pointer in the constructor? Some people think that there should not use this pointer in the constructor, because the object has not been fully initialized, but if you use it very carefully, you can use the THIS pointer in the constructor.

When you are constructed in the constructor, because all the base classes of the objects and members of the members have been constructed, this pointer is easily understood. But even in this case you have very careful, for example, if you call a virtual function on this object (or call other functions that call the virtual function), you may not get what you want.

But when you are very careful, you will not touch any member objects or base class objects that are initialized, you are allowed to use this pointer in the initialization list of constructors. This requires you to know the order in which things happen in the constructor. The most insurance approach is to save the value in the THIS pointer, after which the THIS pointer will be used.

[10.8] What is "Named Constructor IDiom"? This is a technology that provides more intuition or more insurance for the use of the use of the class.

The problem is that your constructor is always the same as the name of the class, which distinguishes different constructors of a class can only pass the parameter list. But if there are many constructor, then these differences look too small, it is easy to cause errors.

By named constructor language, you can define all the constructor inside: You can write a public static method to return an object. These static methods are so-called "named constructor". Overall, there is a such static method for each of the methods of constructing objects. For example, suppose we build a Point class representing the X-Y space. There are two ways to point out a two-dimensional space coordinate: square coordinate (X Y), polar coordinate (radius angle). (Don't worry, if you don't understand these things, the key is not the special case in the coordinate system. The key is to construct a way to have a variety of ways). Unfortunately, the parameters of these two coordinate breeding are the same: two floating points. This will cause the constructor to load the error:

Class Point {public: Point (float x, float y); // Coordinate system Point (float r, float a); // Polar coordinate // error: Intimo}; int main () {Point P = Point (5.7, 1.2); // Error: Cannot select constructor}

A way to solve this problem is to use named constructor language: #include

// Get the use of Sin () and COS () functions Class Point {public: static point reccTangular (Float X, Float Y); // Coordinate system static point point (float radius, float angle); // Polar coordinate / / These static functions are so-called "named constructor" // ... private: Point (float x, float y); // coordinate float x_, y_;}; inline point :: Point (float x, float y : X_ (x), y_ (y) {} Inline Point Point :: Rectangular (Float X, Float Y) {Return Point (x, y);} Inline Point Point :: Polar (Float Radius, Float Angle) { Return Point (Radius * Cos (Angle), RADIUS * SIN (ANGLE));

In this way, the use of the Point class will not be confused when constructing a coordinate system:

INT main () {Point P1 = Point :: Rectangular (5.7, 1.2); // Initialize POINT P2 = Point :: Polar (5.7, 1.2); // with polar coordinate system}

If you want Point to have inherited classes, make sure that the constructor is in the Protected area.

Name constructor can be used to ensure that your object can be created with new.

[10.9] Why can't I initialize static member data in the initialization list of my constructor?

Because you must define static data members outside.

Fred.h: class fred {public: fred (); // ... private: int 1_; static int j_;};

Fred.cpp (or Fred.c What is Fred :: Fred (): i_ (10) // OK, you can initialize member data J_ (42) // errors, you can't initialize static data {//. ..} // You must initialize the static data INT FRED :: j_ = 42;

[10.10] Why is there a couple with a static data member? Because static data members will be defined only in one compiler. If you don't do this, you may get a "undefined external" connection error. E.g:

// Fred.h class fred {public: // ... private: static int j_; // Defines a static data member fred: j_ // ...}; connector will tell you ("fred :: j_ IS not defined ") Unless you define fred :: j _ // Fred.cpp #include" fred.h "int Fred :: J_ = Some_Expression_EVALUATING_TO_EXPRESSION_EVALUATING_TO_EXPRESSION_EVALUATING_TO_EXPRESSION_EVALUATING_TO_EXPRESSION_EVALUTING_TO_EXPRESSION_EVALUATING = 0 value // int Fred :: j_;

The usual definition of the static data member of the class Fred is in Fred.cpp or Fred.c.

[10.11] What is "Static Initialization Sequence Failure"? A very small method that destroys your project

Static initialization order is a very subtle and a very universal misunderstanding. Unfortunately, it is very difficult to discover, it is wrong before the main () starts.

In short, it is recommended that you have two static objects x and y, they leave him in two source files, assuming X.cpp and y.cpp. Assume that the constructor of the constructor is called some methods of the X object

It is such a simple question.

This tragedy makes your project have a half a chance failure. If the X.cpp compiler is just initialized first, everything is normal. But if the Y.cpp compile unit is initialized, then Y's constructor will run before the X-constructor, then there is a problem. For example, the constructor Y is called a method of an X object, and the X object has not been constructed.

I heard that McDonald's is hiring new employees. Enjoy your new job in the Hand of the Hand, huh, huh

Note: The static initialization order failure does not occur on the original type like INT or CHAR *. For example, if you construct a static floating point object, there will never have a static initialization order failure. Static initialization order failed to have such problems only in your static or global objects with constructor.

[10.12] How to prevent static initialization failure? Using "Constructing for the first time", this will mean package your static object to the function.

For example, suppose you have two classes, fred and barney. There is a global Fred object called X, and a global barney object is called Y. Barney constructor calls the gobowling () function of the X object. File x.cpp defines the X object:

// x.cpp #include "fred.hpp" fred x;

The file y.cpp defines the Y object:

// y.cpp #include "barney.hpp" barney y;

For integrity, the Barney constructor is as follows: // barney.cpp #include "barney.hpp" barney :: barney () {// ... x.gobowling (); // ...}

As mentioned above, if Y is constructed before X, the disaster will happen because they have a chance of 50% in different files.

There are multiple solutions to this problem, but a simple and complete solution uses a global function x () instead of the global Fred object x, which will return a reference to a Fred object.

// x.cpp #include "fred.hpp" fred & x () {static fred * ANS = new fred (); return * ANS;}

Because static objects are constructed when the control flow is defined by the first time they define them, the above New Fred () is only called once. Every subsequent call will only return the same Fred object. This way you need to do is replaced with x (). // barney.cpp #include "barney.hpp" barney :: barney () {// ... x (). Gobowling (); // ...}

This is called the principle of constructive at the first time, because it is to make the entire Fred object only constructed when the first call is called.

The next question of this method is that the Fred object will never be paid. This problem is solved in the future FAQ, but it will cause "static inverse initialization order failure".

Note: You don't need to do such an operation like INT or CHAR *. For example, if you have created a static or global floating point object, it is not necessary to wrap it into a function. Only when you have a problem, you only have a constructor when your static or global object is

[10.13] How to prevent "Static Initialization Sequence" problem with state data? Just use the above technology to solve, but this time is a static member instead of a global function.

Suppose there is a class x having a static fred object: // x.hpp class x {public: // ... private: static fred x_;};

Naturally, this static member is initialized separately. // x.cpp #include "x.hpp" fred x :: x_;

Natural Fred objects will be used once in the X method or multiple: void x :: someMethod () {x_.gobowling ();}

But the current danger is that this method is called by some way before a person is initialized by some aspects of Fred object initialization. For example, if another person builds a static X object and calls the SomeMethod () method when still initialization, then you have to see the compiler can not see it, see it will be before x :: x_ Call someMethod () is still there. (Note The ANSI / ISO C Compilation Association is studying this issue, but the compiler has not been able to solve this problem completely, and you need to pay attention to this problem.)

In any case, turn x :: x_ to a static member function. It is always light and safe.

// x.hpp class x {public: // ... private: static fred & x ();

This naturally, this static member will be initialized separately.

// x.cpp #include "x.hpp" fred & x :: x () {static fred * ANS = new fred (); return * ANS;} This can only use X_ instead of x ().

Void x :: someMethod () {x (). gobowling ();

If your performance is very high, you can create a Fred & type static variable if you call X :: SomeMethod () more modes. Static local only initialize once (the first definition of the control flow), this x :: x () will only be called once: the first time x :: someMethod () is called.

Void x :: SomeMethod () {static fred & x = x :: x (); x.gobowling ();

Note: You don't need to do such an operation like INT or CHAR *. For example, if you have created a static or global floating point object, it is not necessary to wrap it into a function. Only when you have a problem, you only have a constructor when your static or global object is

转载请注明原文地址:https://www.9cbs.com/read-59563.html

New Post(0)