Chapter 17 Special Member Functions

xiaoxiao2021-03-06  21

Chapter 17 Special Member Functions

C defines several functions that can only be described as a class member function, which is called the "Special Member" function. These functions affect how to create, delete, copy, and convert to other types of objects. Another important feature of these functions is that they can be invisible by the compiler.

These special functions are briefly description in the table below:

* Constructor

* Destructor

* Temporary object

* Conversion

* New and Delete operators

* Initialization with special member functions

* Copy class object

All items listed above can be customized by the user in each class.

Special member functions follow the same access rules as other member functions. These access rules are described in Chapter 10, "Members Access Control". Table 11.1 summarizes the behavior of member functions and friend functions.

Table 11.1 Summary of function behavior

Whether the function type function is inherited from the base class whether the virtual function can have a return value member function or a friend function if the user does not provide this function, can the compiler generate the constructor whether the member function is a copy constructor? No Member function is whether the destructuring function is whether the member function is whether the conversion is whether the member function is assigned (=) No Yes is a member function is a message. Void * Static member function is delete whether the Void Static member function is not whether the function is a member function. Function No By Functions Do you have a friend function?

Constructor

The member function with the same name with the class name is the constructor. The constructor cannot have a return value, and even if there is a returnite. Note The constructor with a return value is wrong, and the address of the function of the function is incorrect.

If a class has a constructor, the objects of each class type in the program are initialized before use (more information about initialization, see "Initializing with Special Members" later in this chapter ").

The constructor is called at the creation point of the object. Creating an object can be:

* Global object (file range or external link).

* Local variables in a function or small block.

* Dynamic objects created with a New operator. The NEW operation allocates an object in the stack of programs or free storage.

* Temporary objects created due to the explicit call constructor (see "Temporary objects" behind this chapter).

* The temporary object created by the compiler implies the calling constructor (see "Temporary objects" later behind this chapter).

* Other class data members. When you create a class type object, if this type is composed of other class type variables, the creation of each object in this class will cause.

* A class base class sub-object. Creating a class-type object is created when the object class is created.

The role of constructor

A constructor performs a variety of tasks, but for programmers, these tasks are invisible, and you can even write any code for constructor. These tasks are related to the establishment of a complete, correct class type object instance.

In MS C (also in many other C ) a constructor:

* Initialize the virtual base pointer (VBPTR) of the object. This step is to be executed if the class is delivered by the virtual base class.

* Call the constructor of the base class and the member in the order of the instructions.

* Initialize the virtual function pointer (VFPTR) of the object. If the class has or inherits the virtual function, this step is to be executed, the virtual function pointer points to the class's virtual function table (V-Table), and causes the virtual function to correctly bind the same code.

* Perform an optional code in the constructor.

When the constructor is completed, the allocated memory is a given class type object. Since the constructor performs these steps, the "late binding" form of the virtual function can be resolved in the call point of the virtual function, and the constructor should also construct the base class and the construct combination object (as an object of the data), after being tied later It is a mechanism for the polymorphism of the C to achieve objects.

Describe the rules of constructor

The constructor has the same name as the same name. As long as the rules of the overload function (see Chapter 12 "Referring to Details"), multiple constructors can be explained.

grammar

Class Name (Parallel Description Table OPT) CV-Modified Table OPT

C defines two types of constructor, default, and copy constructor. As described in Table 11.2.

Table 11.2 Default and copy constructor

Type Parameter Purpose Default Construction Function The default constructor can be invoked to construct a class type default object copy constructor can accept reference to the same type of type as a unique parameter copy class type object.

The default constructor can be called, but you can explain a default constructor with a parameter table, as long as all the parameters are default. Similarly, the copy constructor must accept reference to the same type as a unique parameter. However, more parameters can be provided, as long as subsequent parameters have default values. If you don't provide any constructor, the compiler will attempt to generate a default constructor. Similarly, if you do not provide a copy constructor, the compiler will also try to generate one. The constructor generated by the compiler is considered a public member function. If you explain a copy constructor, and its first parameter is an object instead of a reference, an error will occur.

The default constructor generated by the compiler establishes an object (initialized Vftables and VBTables, as described above), and calls the base class and the default constructor, but will not take other actions. The construction function of the base class and member is accessible as long as there is, and it is invisible and is called.

The copy constructor generated by the compiler establishes an object and uses a copy of a member method to copy the contents of the object to be copied. If the base class or member constructor exists, they will be called, otherwise, the copy of the bit mode is taken.

If all base classes and members of this class have a constructor that accepts a constant parameter, the copy constructor generated by the compiler accepts a unique type of parameter is const type &; otherwise, the copy constructor generated by the compiler accepts The only type of unique parameter is Type &.

You can use a constructor to initialize a const and volatile objects, but the constructor itself cannot be explained as const and volatile. For the uniquely legal storage type inline of constructor, for constructor, any other storage class modifier is used, including the __declspec keyword causes an error. The constructor and the destructor cannot be explained in addition to __stdcall.

Derived class is the constructor in which the base class cannot be inherited. When a derived object is created, it is constructed from the base system, but it enters the derived class component. The compiler uses the constructor of each base class as part of the initialization of the complete object (see "initialization based class" behind this chapter in addition to the virtual derived.

Explicitly modulated constructor

In the program, in order to create a given type object, the constructor can be explicitly adjusted. For example: Creating two port points of a line segment of two Point objects, you can write the following code:

Drawline (Point (13, 22), Point (87, 91);

Two POINT objects are created, pass it to the Drawline function and remove it after the expression (function call).

Another situation in which a function of explicitly modulating construct is in an initialization:

Point Pt = Point (7, 11);

Create a Point type object and initialize with a constructor that accepts two shaded parameters. As in the two examples, the object created by the explicit moduli is an unnamed object, and there is a surplus in the expression they created. This will discuss this in "Temporary Object" in this chapter.

Call the member function and virtual functions within the constructor

Any member function calls in the constructor is usually very secure, because before performing the first line of user code, the object has been fully established (already initialized the virtual table, etc.). However, when the member function calls the virtual member function of its abstract base class, there is potential unsafeness in the constructor and the destructor.

The constructor can call the virtual function. When the virtual function is called, the called is a function defined in the class that constructs the function itself (or the function inherited from the base class). The following example shows a case where a virtual function occurs during a constructor.

#include

Class Base

{

PUBLIC:

Base (); // default constructor

Virtual void f (); // Virtual member function

}

Base :: base ()

{

COUT << "Constructing Base Sub-Object / N";

f (); // Call the virtual member function in the constructor

}

Void base :: f ()

{

COUT << "Called Base :: f () / n";

}

Class Derived: Public Base

{

PUBLIC:

Derived (); // default constructor

Void f (); // Realization of this type of virtual function

}

Derived :: derived () {

COUT << "constructing derived object / n";

}

Void derived :: f ()

{

COUT << "Called Derived :: f () / n";

}

void main ()

{

Derived D;

}

When running on the above program, Derived D instructions will trigger the following series of events:

1. Class Derived constructor (Derived :: Derived) is called.

2. The constructor of the base class base is called before entering the conferid class.

3. Base :: base call function f, it is a virtual function. Usually called the function is derived :: f, because the object D is the object of the derived type. But because Base :: base is a constructor, the object is an object of a derived type, so Base: F will be called.

Constructor and array

The configuration of the array can only use the default constructor. The default constructor either does not accept any parameters or there is a default value for all of its parameters. Arranges are usually constructed in ascending order, and initialization of each member of the array uses the same constructor.

Structure order

For derived classes or their member data is class types, the order of constructs help you understand that you can use which part of the object in any given constructor.

Construction and inheritance

A derived object is constructed from base classes to derived classes by calling constructor for each class by order.

The constructor of each class can depend only on its base class that is completely constructed.

For complete descriptions of initialization, including the order of initialization, see "Initialization Base and Members" later behind this chapter.

Construction and combination type

Class containing class type data is called a combined class. When an object of a combined class type is created, the constructor containing classes is called before the constructor of the class.

Initialization on this situation, see "Initialization Base" and members of this chapter.

Destructor

The destructor is "reverse" constructor. They are adjusted when the object is destroyed (recovered). Designing a function of a class is the desired function to add (~) numbers before class name. For example, the destructor of class String is ~ String ().

The destructor is usually "clear" when an object is no longer needed. Consider the description of the following String:

#include

Class String

{

PUBLIC:

String (char * ch); // Description constructor

~ String (); // and destructor

Private:

Char * _Text;

}

// Define constructor

String :: string (char * ch)

{

// Dynamically assign the correct number of memory

_Text = New Char [Strlen 1];

// If the assignment is successful, copy the initialization string

IF (_Text)

STRCPY (_Text, CH);

}

// Define the patterns string :: ~ String ()

{

// Recycle a memory that is previously reserved for this string

Delete [] _Text;

}

On the previous code. The destructor string :: ~ String uses the deLete operator recycling (DEALLOCATE) to dynamically assign the storage space of Text.

Illustrated

The destructor has the same name and the name of the name, and the prefix is ​​~ number.

grammar

~ Class name ()

or

Class Name :: ~ Class Name ()

The first form of the grammar is used for the description of the description of the description; the second form is used for the description of the description.

There are several rules to constrain the description of the description function. Destructor:

* Cannot accept parameters

* Cannot not explain that any return type (including Void) L cannot be returned by RETURN statement

* It cannot be described as const, volatile or static, but the destructor can be called by a description of the sect of the object of const, volatile, or static.

* The virtual can be explained. Using the false preframe function, you can deck the object without having to know the type of object. Due to the use of the virtual function mechanism, the correct destructor of the object will be called. Note that in an abstract class, the destructor can be explained as a pure virtual function.

Destructure function

The destructor will be called when the following event occurs:

* An object assigned with a New operator explicitly uses the Delete operator recycled. When reclaiming an object with the Delete operator, the released memory is a "Most DeriveD Object), or a complete object rather than a sub-object representing the base class. Recycling for the "outer derivative object" is only guaranteed when working with virtual destructuring functions. Recycling may fail in the case of multiple inheritance, because in this case, class type information is consistent with the type trust of different actual objects.

* A local (automatic) object in the block range is outside its range.

* The end of the temporary object survival period.

* Global or static members still exist, but the program has ended.

* Explicitly adjust the destructive function with the fully qualified name of the analyte function (see the "Explicit destructor call" behind this chapter).

The situation described in the previous list guarantees that all objects can be removed by user-defined methods. If a base class or data member has an accessible destructor, if a derived class does not have an illustrative function, the compiler generates one. The destructor generated by the compiler calls the destructor function of the base class and the destructor of the derived class member. The default destructor is public (see "Basic Access Description" in Chapter 10, "Members Access Control").

The destructor can freely adjust class member functions and access class member data. When a virtual function is called in the destructor, the function is a function of the class currently being wiped (see the next section below, "descriptions").

There are two principles using the destructor, and the first is the address of the system. The second is a sectic function that derives class cannot inherit its basis. Instead, as explained earlier, they always cover the sectors of the base class.

Sector

When an object exceeds its scope or deleted, some series of events occur in its complete description:

1. Call the destructor function of this class and execute the code of the destructor.

2. Non-static members call their destructor in the back sequence in the class description. The application of optional member initialization tables in the constructor does not affect the order of constructors or destructors (see "Initialization Base and Members" after the initialization members).

3. The destructor of the non-virtual base class is called in the reverse sequence of its description.

4. The destructor of the virtual base class is called in the reverse sequence of the description.

Destructor of non-virtual base class

The destructor of the non-virtual base class is called in the back sequence of the base class name. Consider the following description: Class Multinherit: Public Base1, Public Base2 ...

In the above example, the destructor of Base2 is called before the destructor of Base1.

Destructor of virtual base class

The destructive function of the virtual base class is called in the reverse sequence that appears in the channelless diagram (priority, traverses from left to right, rear sequence). A inheritance diagram depicted as shown in Figure 11.1.

The following are listed below:

Class A

Class B

Class C: Virtual Public A, Virtual Public B

Class D: Virtual Public A, Virtual Public B

Class E: Public C, Public D, Virtual Public B

For the object of type E To determine the order of the virtual base class destructor. The compiler is compiled with the following algorithm:

1. Start from the deepest point in the figure (in this example is E point) traversed the left sub-map.

2. The left has been traversed to all the nodes are accessed, and write down the name of the current node.

3. Access the previous node (down and right) to confirm whether the marked node is a virtual base class.

4. If the marked node is a virtual base class, search for the list to see if the node is already in the list. If the tagged node is not a virtual base class, ignore it.

5. If the node of the tag is not in the list, add it to the tail of the list.

6. Return to the previous layer of the map and traverse the map along the next path.

7. Steering 2 Continue.

8. When the path of this node can be used through the path, you can write down the node.

9. Steering 3 Continue.

10. Continue this process until the bottom node is again a current node.

Therefore, for class E, the sequence of sectations is:

1. Non-virtual base class E.

2. Non-virtual base class D.

3. Non-virtual base class C.

4. Virtual base class B.

5. Virtual base class A.

This process produces a single list of ordered lists, and class names do not appear twice. Once the list is built, the list of each class will be called from the last to the forefront.

When a class constructor and the destructor depend on other components being created or when the components are required for a long time, for example, (in Figure 11.1) When A's destructor (if the execution of the code) is dependent on B is still present, or the order of constructors and sectations in turn is very important. In the inheritance diagram, this interaction between the class has an inherent hazard because the derived class will change the last path, and the order of the construction and sectors is also changed.

Explicit destructor call

Explicitly adjusting the designer is usually unnecessary, but they are useful in performing objects in an absolute address. These objects are typically allocated with a user-defined NEW operator with a location parameter. DELETE operations cannot be recycled because it is not allocated from the free storage area (see "New and Delete operator" behind this chapter for details). However, a call to the destructor can complete the appropriate clear work. To explicitly call the class String object S destructor, one of the following statements can be used:

S.String :: ~ String (); // Non-virtual call

PS-> string :: ~ string (); // Non-virtual call

s. ~ String (); // virtual call

PS-> ~ string (); // virtual call

The symbols of the explicit call description function displayed in the above code can be used directly, and ignore whether the type defines a destructor. This allows you to use this explicit call, but you don't have to know if this type defines a destructor. If a destructor is not defined, the explicit call of the destructor does not produce.

Temporary object

In some cases, temporary objects must be created for compilers. These temporary variables are created for the following reason:

* To initialize a constant reference with another type of reference type that is being initialized.

* To save the return value of the user-defined type returned by a function. This temporary object will be created if the user program does not copy the return value to another object:

UDT FUNC1 (); // Description a function that returns a user-defined type

...

FUNC1 (); // Call the FUNC1 function, but ignore the return value

// Create a temporary object to save the return value

Because the return value is not copied to other objects, a temporary object is created. A more common situation to create a temporary object is to call the expression evaluation of the overload operator function. These overloaded operators return to the value of the user-defined type (usually not copied to other objects). Consider expressions:

ComplexResult = COMPLEX1 Complex2 Complex3

The value of the expression Complex1 Complex2 is obtained, and the result is stored in the temporary object. The value of the expression Temporary Complex3 is then stored and the result is stored in the ComplexResult (assuming that the assignment operator is not overloaded).

* Save a model to convert the transition result of the user's custom type. When a given type object is explicitly converted to a user-defined type, the new object is constructed as a temporary object.

Temporary objects have a survival period, there is a definition between its creation points and dismantling points. Any expression that creates multiple temporary objects is finally removed in the reverse order of creating their opposite. The occurrence point of the sect is shown in Table 11.3.

Table 11.3 Destructor of Temporary Objects

Creating a reason for the reason for the conformance point expression of the interim object All the result of the value of the value of the expression all due to the results of the expression value (also at the semicolon) or in the control expression (for, IF) due to the end of the expression , When the While, Do and Switch statements are removed at the end. The built-in (non-overloaded) character (|| and &&) is over the end of the right operand. In this analysis, all temporary objects created by the right logical operation operates are removed. Initialization constant references If an initializer is not the same L-value type to be initialized, create a temporary object based on this object type and initialize using this initialization expression. This temporary object is removed immediately after the reference object with which it is bound to it.

Conversion

A given class type object can be converted to other types of objects. This can be done by following:

Construct a target class type object from the source class type and copy the results to the target object. This process is called the constructor-type conversion. Objects can also be converted by the user provided by the user.

When the standard conversion (described in Chapter 3 "Standard Conversion") Cannot be converted from a given type to a class type, the compiler selects user-defined conversions to help complete this. In addition to the explicit type conversion, the conversion also occurs:

* A initialization expression has different types of objects that are initialized. * The parameter type used in the function call does not match the parameters described in the function description.

* The returned type described in the function described in the function returned from the function does not match the return type described in the function description.

* Two expression operands must have the same type.

* An expression of a control review or selecting statement requires different types from the provided expression.

User-defined conversion is only used when it has no erriness, otherwise an error message will be generated. In the use point, the error will be checked, and thus, if the feature that can be caused, it can only indicate that a class of potential erliness does not generate any errors. Although there are many situations that cause an erliness, the following is the reason why it is most caused.

* A class that uses multiple inheritance derived, not to clear which base class selects this conversion (see Chapter 9, "Delivery Class").

* A explicit type conversion operator and the same intending function for this purpose exists (see "Conversion Functions" after this chapter).

* The conversion of the constructor and the conversion of the conversion function method must follow the access control rules described in Chapter 10 "Members Access Control". Access control is only detected only after the conversion discovery is nothing.

Conversion constructor

The constructor that can be called with a single parameter is used to convert the parameter type to class types. This constructor is called the conversion constructor. Consider the following example:

Class Point

{

PUBLIC;

Point ();

Point (int);

...

}

Sometimes there is a need to convert, but there is no conversion constructor in the class. This conversion cannot be done by the constructor, the compiler does not look for the intermediate type that can complete the conversion. For example: assume that there is a conversion from the Point type to the RECT type and a conversion from the int to Point type, but the compiler does not provide a conversion from int to RECT type by constructing a middle Point type object.

Conversion and constant

Although built-in types of constants such as (int, long, and double) can appear in the expression, the constant of class types is not allowed (part because the class is usually used to represent complex objects, and the symbol is not convenient to represent). However, if the conversion constructor for converting the built-in type is provided, these built-in types of constants can be used for expressions, and the conversion will lead the correct behavior. As such example, a Money class has a conversion from long and double types:

Class Money

{

PUBLIC;

Money (long)

Money (double)

...

Money Operator (const money &); // Overloaded plus operator

}

Therefore, the expression like the following can explain the constant value:

Money AccountBalance = 37.89;

Money newbalance = AccountBalance 14L;

The second example causes the call of the overloaded addition operator (discussed in the next chapter). Both examples will make the compiler to convert them into a Money type before expressing the constant.

Disadvantages of conversion constructor

Because the compiler will implies a conversion constructor, you will give up the control of the specific call function. If the full control is important, do not explain any constructor that accepts a single parameter. Instead, define a "Help" function to complete these conversions, see the following code:

#include

#include

// Description Money class

Class Money

{

PUBLIC;

Money ();

/ / Define the conversion function that can only be explicitly called

Static Money Convert (Char * CH) {RETURN MONEY (CH);

Static Money Convert (Double D) {Return Money (D);

Void Print () {Printf ("/ N% f", _ amount);

Private:

Money (char * ch) {_AMount = ATOF (CH);

Money (double d) {_amount = D;

Double _amount;

}

void main ()

{

/ / Complete a conversion from char * to MONEY

Money acct = Money :: Convert ("57.29"); acct.print ();

/ / Complete a conversion from Double to Money

Acct = Money :: Convert (33.29);

Acct.print ();

}

In the above code, the conversion constructor is private and cannot be used in type conversion. But they can be explicitly activated by calling the CONVERT function. Because the CONVERT function is static, their access does not require special objects.

Conversion function

In the previous section, a type of object in converting a type of object in a constructor can impose a special class type. This section describes a method that provides an explicit conversion method to convert a given class type into other types. Conversion from some type is often done using the conversion function. The conversion function uses the following syntax:

grammar

Conversion function name:

Operator Conversion Type Name ()

Conversion Type Name:

Type Indicator Table Pointer Operator OPT

The following example illustrates a conversion function to convert the Money type to a Double type:

Class Money

{

PUBLIC:

Money ();

Operator Double () {return_amount;}

Private:

Double _amount;

}

Once the previous class description is given, the following code can be written:

Money Account;

.

.double cashonhand = account;

Initializing CashonHand can cause conversion from type Account to Double. Conversion functions are often referred to as "model operators". Because they (like constructor are called) is a function called when the model is converted. The following example uses a model or explicit type to transform the current value of a Money type object:

Cout << (double) Account << Endl;

The conversion function can be inherited in the derived class. The conversion operator only hides the conversion operator of the transition in the base class. So a user-based Operator Int function is not hidden in a definition of the Operator Short function in the base class.

There is only one user-defined type conversion function when making hidden conversion. If there is no explicitly defined conversion function, the compiler will not look for an intermediate type to convert through it. If the required conversion causes an erliness, an error is generated. Embodiments are generated in multiple user-defined conversions, or generating erliness when user-defined conversions and built-in conversions.

The following example exemplifies a class description of a potential amplitude:

#include

Class String

{

/ / Define constructor from a CHAR * type conversion

String (char *) {strcpy (_Text, s);

/ / Define conversion of char *

Operator char * () {return_text,}

INT operator == (const string & s)

{return! strcmp (_text, s_text);

Private:

Char_text [80];

}

int main ()

{

String S ("abcd");

Char * ch = "efg";

/ / Select a conversion in the compiler

Return S == CH;

}

On the expression s == ch, the compiler has two options, and there is no way to determine which one is better. It can use the constructor to convert the CH to a String type object and then compare the user-defined Operator ==.

However, it can also convert S to a char * type pointer (using a conversion function) and then adopt a comparison between the pointers.

Because there is no better in the two methods, the compiler cannot determine the meaning of the comparison, so there is an error.

Describe the rules of the conversion function

The following four rules apply to explain the conversion constructor (see the conversion function syntax):

* Class, enumeration and TypeDef name cannot be explained in the Type Indicator, so the following code will generate an error:

Operator struct string {char string_storage;} (); Instead, the description of the structure string should be described in the description of the conversion function.

* The conversion function cannot be taken, and the parameters will cause an error.

* The conversion function has explained the return type of the conversion type name; so that the conversion function explains that any return class will generate an error.

* The conversion function can be explained as virtual.

New and delete operators

C supports dynamic allocation and recycle objects using the New and Delete operators, which assigns a memory from a pool called "free zone". The New operator calls the Operator New function, and the DELETE operator calls the Operator Delete function.

Operator new function

When the compiler encounters a statement as follows in the program, it translates into a call to Operator New.

Char * pch = new char [buffer_size]

For the requirements of the assignment 0 byte storage area, the Operator New returns a pointer to different objects (that is, repeated calling Operator New will return different pointers). If there is not enough memory to meet the requirements of the assignment, the OPERATOR NEW is usually returns NULL when the memory meets the assignment. Of course, you can change this default behavior by writing a customized exception process routine. Then call the _SET_NEW_HANDLER Run the time library function and make the name of your exception to handle the routine function as its parameters. See the details of the recovery mechanism See the next section "Treatment without a sufficient memory".

Two ranges of Operator New are described in Table 11.4.

Table 11.4 Scope of Operator New Function

Operator Range :: Operator New Global Class_name :: Operator New class

The first parameter of the Operator New function must be type size_t (defined in stddef.h), and its return value is always void *.

When assigns internal data type objects with a New operator, or when allocating class type objects that do not include user custom Operator New functions, and when allocating any type of array, call is a full Operator New function. When the Operator New is used to define class type objects of the Operator New function, call the class Operator New function.

The Operator New function defined for the class is a static member function (so it can't be virtual). It hides the global Operator New function for this class. Studies the following case, where NEW is used to dispense the memory and set the memory to a given value:

#include

#include

Class Blanks

{

PUBLIC:

Blanks () {}

Void * Operator New (size_t stallocateblock, char chinit);

}

Void * Blanks :: Operator New (size_t stallocateblock, char chinit);

{

Void * pvTemp = malloc (stallocateblock);

IF (pvTemp! = 0)

MEMSET (PVTemp, Chinit, StallocateBlock);

Return PVTEMP;

}

For different BLANKS types, the global Operator New function is hidden. So the following code assigns a Blanks type object and initializes 0xA5:

int main ()

{

Blanks * a5 = new (0xA5) Blanks;

Return A5! = 0;

}

The parameters provided to new in parentheses are passed to the Blank :: Operator New as chinit parameters. However, the global Operator New function is hidden, so the code that calls the global Operator New will cause an error.

Blanks * Someblanks = New Blanks:

In previous compiler versions, non-class types and all arrays (whether they are class type arrays) Use the New operator allocation memory always use the global Operator New function.

Starting from Visual C 5.0, the compiler begins to support member array new and delete operators in class descriptions.

E.g:

Class X

{

PUBLIC:

Void * Operator new [] (size_t);

Void Operator Delete [] (void *)

}

Void f () {

X * px = new x [5],

delete [] px;}

Processing without memory conditions

The following code can be used for failed memory allocation:

INT * pi = new int [BIG_NUMBER];

IF (pi == 0)

{

CERR << "insufficient memory" << Endl;

Return -1;

}

Of course, there are other ways to process failed memory allocation requests, that is, write a custom routine to deal with this failure. Then run the function to register your processing routine by calling the _SET_NEW_HANDLER. This method is introduced in the next section.

Use _SET_NEW_HANDLER

In some cases, some corrections can be taken in allocation memory to make allocation requirements can be met. Get control when the global operator new function fails, use the _SET_NEW_HANDLER function (defined in new.h) as follows:

#include

#include /

/ Define a function called when the NEW assignment memory failed

INT MynewHandler (size_t size)

{

Clog << "Allocation failed.coalescing Heap." << Endl;

// Call a tool function to restore some stacks of space

Return coalesceheap ();

}

void main ()

{

// Set the new failure process function to MyNewhandler

_SET_NEW_HANDLER (MyNewHandler);

INT * pi = new int [BIG_NUMBER];

}

In the above example, the first statement of the main function is to set the new process function to MyNewHandler. The second statement is to allocate a large block of memory using the New operator. When the assignment fails, the control is turned to mynewhandler.

Passing to MyNewHandler is the byte size of the memory that requires allocated memory. An identifier returned from MyNewHandler to indicate whether to perform one assignment operation. Non-0 value indicates that once again, and 0 values ​​indicate that the allocation failed. MyNewHandler prints a warning message and takes a correction step. If MyNewHandler returns a non-0 value, the New operator tries to assign once; when MyNewHandler returns 0 value, the New operation assigns an attempt to return an 0 value to the program.

_SET_NEW_HANDAL Returr is an address of an old NEW handler. So if a new New processing function is only used in a short time, the old handler can restore as follows:

#include

...

Pnh old_handler = _SET_NEW_HANDLER (MyNewHandler);

/ / Require code using MyNewHandler

... // Reinstall the previous processing function _SET_NEW_HANDLER (Old_Handler); use 0 paramet_new_handler to cause the new new handler, that is, there is no default processing function.

You can use any name to explain the new handler, but it must be a function that returns an int type (non-0 means the NEW processing function continues, 0 means failed).

If a user-defined Operator New function is provided, the NEW handler does not automatically call when fails.

_SET_NEW_HANDLER's function prototype and _PNH definition in new.h:

_PNH_SET_NEW_HANDLER (_PNH);

Type _PNH is a pointer to a function of the function, the type size_t as a unique parameter and returns the INT type.

Operator delete functions

Memory-allocated memory with new operation can be released by DELETE operation. The Delete operator calls the Operator Delete function to release the memory back into the available storage area. Use the delete operation, which will also cause calls for class destructor (if any). The Operator Delete function also has two types of global and class. For a given class, you can only define a Operator delete function for it; once it is defined, it hides the entire Operator Delete function. The global Operator Delete function can always be called for arbitrary types of arrays.

The global Operator Delete function is a single parameter of a VOID type in the description, which includes a pointer to release the object. Its return type is Void (the Operator Delete function does not have a return value). There are two forms of class members Operator delete functions:

Void Operator delete (void *);

Void Operator Delete (Void *, SIZE_T);

For a given class, it can only provide one of the above two different forms, and the first form is just like the global Operator Delete; two parameters have two parameters. The first parameter is to release the pointer of the memory block, and the second parameter is the memory byte size to be released. The second form is particularly useful when the OperatorDelete function in a base class is used to release the party object.

The Operator Delete function is static, so it can't be virtual, the Operator Delete function must follow the access control described in Chapter 10 "Members Access Control".

The following example shows the user-designed Operator New and Operator Delete functions used to record allocation and release memory:

#include

#include

INT flogmemory = 0; // is recorded (0 = no; non-0 = Yes)

INT CBLOCKSALLOCATED = 0; // Number of blocks allocated

// user-defined new operation

Void * Operator New (size_t stallocateblock)

{

Static FinopNew = 0, // Protective Sign

IF (FlogMemory &&! FinopNew)

{

FinopNew = 1;

Clog << "Memory Block" << CBLOCKSALLOCATED

<< "Allocated for" << stallocateblcok

<< "" bytes / n ";

FinopNew = 0;

}

Return Malloc (stallocateblock);

}

// User-defined Operator_Deletevoid Operator Delete (Void * PVMEM)

{

Static finopdelete = 0; // Protection Sign

IF (FlogMemory &&! Finopdelete)

{

Finopdelete = 1;

CLOG << "Memory Block" << - CBLOCKSALLOCATED

<< "deallocated / n";

Finopdelete = 0;

}

Free (PVMEM);

}

Int main (int Argc, char * argv [])

{

FLOGMEMORY = 1; // Open Log ID

IF (Argc> 1)

For (int i = 0; i

{

Char * pmem = new char [10];

Delete [] PMEM;

}

Return CBLOCKSALLOCATED;

}

The above code can be used to check "memory leakage", that is, the memory that is not released after allocating from the auto heap. To accomplish this, the global new and delete operations are redefined with a memory of statistical allocation and release. Starting with Visual C 5.0, the compiler supports the member array new and delete operations in the class description, for example:

Class X

{

PUBLIC:

Void * Operator new [] (size_t);

Void Operat Delete [] (void *);

}

Void f ()

{

X * px = new x [5];

Delete [] PX;

}

Initialize with special member functions

This section describes the initialization of special member functions, which is the extension of some initialization.

* Chapter 7 "Initialization Collection" in Chapter 7 describes how to initialize non-class type arrays and simple class type objects. These simple class types cannot be private and protected, and they cannot have base classes.

* Constructor. It explains how to initialize class type objects using a special constructor.

The default initialization method is to perform a copy of a bit mode, copy the initializer to the object to be initialized. This technology is only available:

* Internal type objects. E.g:

INT i = 100;

* Pointer. E.g:

INT IINT * PI = & i;

* Reference. E.g:

String sfilename ("file.dat");

String & = sfilename;

* Type object, this class does not protected or private members, can not have a virtual function, and if there is a base class, for example:

Struct Point

{

INT X, Y;

}

Point Pt = {10, 20}; // static storage Calss Only

By illustrating the constructor (see the "Constructor" starting in this chapter, see the "Constructor" starting in this chapter, the class can explain more accurate initialization. If an object's type is a class type with a constructor, the object will be initialized, otherwise there must be a default constructor. Objects without special initialization activate the default constructor of the class.

Explicit initialization

C supports two forms of explicit initialization.

* Support to provide an initial table in parentheses:

String sfilename ("file.dat);

The item of the initializer table in parentheses is a parameter as a class constructor. This form of initialization makes it possible to initialize an object using multiple values, and can also be used in combination with the New operator. Such as:

Rect * prect = New RECT (10, 15, 24, 97);

* Support to provide a single initializer using an equalization initialization syntax, for example:

String sfilename = "file.dat";

Although the previous example works in the same manner in the same manner in the first form, the grammar is not suitable for use with the object allocated in the free heap. The single expression on the right side of the equal sign is a parameter as a copy constructor of the class, so it must be some type of capable of converting into class types.

Note Because the alignment number (=) is different in the initialized context, the overload Operator = has no effect on initialization.

The equal number initialization syntax is different, although the code generated in most cases is the same. The difference between them is: when using the like, the behavior of the compiler is like a sequential event that has occurred:

* Create a temporary object that is the same type of object to be initialized.

* Copy the temporary object to the object to be initialized.

The constructor must be accessible before the compiler performs these steps. Although the compiler can ignore the creation and copy steps of the temporary object in most cases, an unacceptable copy constructor causes the failure of the equivalent initialization. Consider the following example:

Class Anint

{

Anint (const anint); // private copy constructor

PUBLIC:

Anint (int); // public INT constructor

}

...

Anint myint = 7; // destroyed access control, trying to reference private copy constructor

Anint Myint (7); / / correct; set with call copy constructor

In the function call, the type parameter of the pass value and the return object in the piped form is initialized on the following code. TYPE-NAME = Value

E.g:

String s = "c ";

Therefore, the parameter type must be a class type that can be converted into a parameter. The copy constructor of this class, as well as a custom conversion operator or a constructor that accepts the actual parameters must be public.

In the expression using the New operator, the object assigned from the free heap is conceptually initialized in the following form:

Type-name name (Initializer1, Initializer2, ... iniaAtialz)

E.g:

String * ps = new string ("C ");

The initialization of the base type member and class member object is also conceptually used to initialize this method (see "Initialization Base and Members" later in this chapter).

Initialization array

If a class has a constructor, the array of such an array is initialized by a structural function. If the number of items in the initializer table is less than the number of array elements, the default constructor will be used for the remaining array elements. If this class does not define the default constructor, the initializer table must be complete, that is, each element in the array must have an initializer.

Consider the Point class that defines two constructor:

Class Point

{

PUBLIC:

Point (); // default constructor

Point (int, int); // // from two INT type constructor

...

}

A POINT object array can be described below:

Point apoint [3] =

{POINT (3, 3) // use int, int constructor

}

The first element of the apoint array uses the constructor Point (int, int) to construct, and the remaining two elements are constructed using the default constructor.

Static member arrays (whether it is const) can initialize in their definition (outside the class description). E.g:

Class windowColors

{

PUBLIC:

Static const char * RGSZWindowPartList [7];

...

}

Const Char * WindowColors :: RgszWindowPartList [7] =

{"Active Title Bar", "Inactive Title Bar", "Title Bar Text", "Menu Bar", "WINDOW Background", "Frame"}

Initialization static object

Global static objects are initialized in the order in which they appear in the source code, they are removed in this reverse order. However, the order of initialization in the cross-conversion unit depends on how the connector organizes the target file, and the sequence of the sequence is still in the opposite order of the order in the object.

The initialization of local static objects occurs when they first appear in the program stream, and they are also removed in the reverse order at the end of the program. The sectors of local static objects only occur in the block found this object, and this object is initialized.

Initialization base class and member

A derived object consists of a component that represents each base class and a member of this special class. Class objects containing member objects can also contain other classes. This section describes how these components objects are initialized when this type of class object is created.

In order to complete the initialization, the syntax of the constructor initialization or CTOR initialization syntax.

grammar

CTOR-initializer

Member initializer table

Member initializer table:

Member initializer

Member initializer, member initializer table

Member initializer:

Complete class name (Expression Table OPT)

Identifier (Expression Table OPT)

This language used in the constructive function is more detailed in the next section "Initialization Member Object" and "Initialization Base".

Initialization member object

Category can contain class type member objects, but to ensure that the initialization of these members objects is met and the conditions are met.

* The class of the object contained does not require a constructor.

* The class containing an accessible default constructor is available.

* The constructor of the inclusive class explicitly initializes the object contained.

The following example gives how to complete this initialization:

/ / Description a Point class

Class point {

PUBLIC:

Point (int x, int y) {_x = x; _y = y;

Private:

INT _X, _Y;

}

/ / Description A Rectangle class containing a Point type object

Class Rect

{

PUBLIC:

RECT (int X1, int y1, int x2, int y2);

PRIVATE: POINT _TOPLEFT, _BOTTOMRIGHT;

}

/ / Define the constructor of the class RECT, this constructor explicitly initializes the Point object

Rect :: RECT (INT X1, INT Y1, INT X2, INT Y2):

_Topleft (x1, y1), _ bottomright (x2, y2)

{

}

The Rect class displayed in the previous example contains two Point class member objects. Its constructor explicitly initializes the object_topleft and _bottomright. Pay attention to the colon after the rear brackets behind the constructor. It is a member name and parameter behind the colon, which is used to initialize the object.

WARNING: The order in which the member initialization described in the constructor does not affect the order of these members being constructed. Members are constructed in order of their instructions in class description.

The reference and constant members must initialize the syntax (described in "Initialization Bastrics and Members"). There is no other way to initialize these objects.

Initialization

The initialization of the direct base class is carried out in the same manner in the same manner in the same manner. Consider the following code:

// Description class window

Class Window

{

PUBLIC:

WindoDw (Rect Rsize);

...

}

// Description class DialogBox directly derived from a class Window

Class Dialogbox: Public WINDOW

{

PUBLIC:

Dialogbox (Rect Rsize);

...

}

// Define the DialogBox constructor. This constructor explicitly initializes the Window child object

Dialogbox :: DialogBox (Rect Rsize): Window (Rsize)

{

}

Note In the Dialogbox constructor, the Windows base class is initialized using the parametric RSize. This initialization consists of a base class name to be initialized. The base class name followed by a parameter table that is passed to the base class constructor by incloating.

In the initialization of the base class, the object does not represent the sub-object of the base type member are referred to as a "complete object". The class of the "complete object" is considered as the "outer derived" (MOST Derid).

The child object representing the virtual base class is initialized by the constructor of the "outer exterior derivation class". This means that as long as the derived class of the virtual base class, the foreigner must explicitly initialize the virtual base class, otherwise the virtual base class must have a default constructor. The initialization of the virtual base class in other classes other than the foreigner class will be ignored.

Although initialization of the base class is usually limited to the initialization of the direct base class, a class of constructor can initialize a non-direct virtual base class.

The initialization of base classes and members

The base class and member objects are initialized as follows:

1. Initialization of Virtual Base Categories The order in which they appear in a to-ringless figure. See "Virtual Base Class" in Chapter 9, "Derived Class" in Chapter 9 (Note that sects of these sub-objects) is traversed in the back sequence. For how to traverse the situation of a ringless chart, see the "sequence of sequence" in this chapter.

2. Non-virtual base classes are initialized according to their order in the class description

3. The initialization of the member object is initialized in the order described in the class.

The order of the member initializer and base class initializer described in the member initializer table of the constructor does not affect the order of the base class and member objects.

Initialization range

The initialization value of the base class and member object is within the scope of the constructor that is described, therefore, they can implicitly reference classes.

Copy class object

Both operations can cause copies of objects:

* Assignment. When the value of an object is assigned to another object, the first object is copied to the second object. therefore:

Point A, B;

...

A = B;

The value of b will be guided to a.

* Initialization. Initialization occurs when a new object occurs, when the value is transmitted to the function, it is also born when returns a parameter in the path of the value.

Programmers can define copy of the copy of the class type object. Consider the following code: TextFile A,

B; A.Open ("file1.dat");

B.Open ("File2.dat");

B = a;

The above code can mean: "Copy file1.dat in file2"; or it can also mean: "Ignore file2.dat, and put B as a second handle of File1.dat". The programmer is responsible for assigning a suitable copy semantic for each class.

Copy by the following two methods:

* Assignment (using assignment operator, operator =)

* Initialization (using a copy constructor) (see the "rule of the constructor" starting in this chapter for details on the copy structure function).

Any given class can achieve one or more copies. If both methods are not implemented, the assignment will be assigned as a member mode, and initialization is also initialized as a member. Details of "Assignment and Initialization of Member Mode" will be discussed later in this chapter.

The copy constructor comes with a type of class-name & parameters, where class-name is the name of the class defining a copy constructor. E.g:

Class Window

{

PUBLIC:

Window (const window &); // Define copy constructor

...

}

Note: As long as it is possible, the parameters of the copy constructor should be Const Class-Name &. This prevents the copy constructor from being modified to copy objects to copy. This also makes copying const objects possible.

Compiler generated copy

The copy constructor generated by the compiler is like a user-defined copy constructor with a parameter type with a "type type reference". Only one exception is: When all of the base classes and member classes illustrate a copy constructor, and the function comes with a CONST CLASS-NAME & type parameter. In this case, the parameter of the copy constructor generated by the compiler is a const type.

When the parameter of the copy constructor is not a Const type, an error is generated by copying a const object. However, it will be different: If the parameter type is const type, the initialization of a non-Const type object does not generate an error.

The assignment operator generated by the compiler also follows the same way. They have a unique class-name & type parameter unless the parameter type used in all base clauses and members of the member is Const Class-Name &. In this case, the compiler uses a COUNT type parameter for the assignment operator generated by the class.

Note: When the virtual base class is initialized by a copy constructor (whether it is a compiler is generated or a custom), they are initialized once when it is constructed.

These meanings are similar to the copy constructor. When the parameter type is not a Const type, an error is assigned from a CONST type object. Again, different: If a const type is assigned to a non-Const type value, the value can be performed.

See Chapter 12 "Repeat" in Chapter 12 "Reserved" in Chapter 12.

Member method assignment and initialization

The method of default assignment and initialization is the assignment of "membership mode" and "initialization of member mode".

"Members' assignment" consists of a copy process from an object to another object. Each assignment is a member, as each member is assigned separately, "initialization of member mode" is also composed of copy processes copied from an object to another. An object is initialized each time, as each member is initialized separately. The main difference between these two methods is that the member mode assignment is activated by each member's assignment operator (Operator =), and the member mode initializes activation is the copy constructor of each member. The assignment of the member mode is only implemented by the assignment operator as follows.

TYPE & TYPE :: Operator = ([const | volatile] type &)

If any of the following conditions exist, the default operator assigned by the member mode cannot appear:

* There are const members in a member class.

* A member class has a reference member.

* A member class or its base class has a private assignment operator (Operator =).

* A member class or its base class has no assignment operator (Operator =).

If a class or its base class has a private copy constructor or there is any of the following conditions, the default constructor initialized by the class is not possible to generate: * A member class has a Const member.

* A member class has a reference member.

* A member class or its base class has a private copy constructor.

* A member class or base class has no copy constructor.

The assignment operator and copy functions for a given class are always explained. Unless the following two conditions are met, they are undefined.

* This class does not provide custom functions for this copy

* Program requirements provide this function. This requirement is present if you encounter an assignment operator or initializer that requires a member mode or the address of the class Operator = function.

If the above two conditions are not satisfied, the compiler does not have to generate code for the default assignment operator and copy constructor (MSC compiler can remove these code). In particular, a custom Operator = function is illustrated, and a reference to class type is referenced as a reference, the default assignment operator function is generated. If a copy constructor is described, the default copy constructor is not generated.

Therefore, for a given class A, the following description always exists.

// copy constructor and implicit instructions for assignment

A :: A (Const A &) A &

A :: Operator = (Const A &)

This definition is only available when needed. The copy constructor in the above example is considered a public member function of the class.

The default assignment operator enables a given class object to assign an object to its public base type. Consider the following code:

Class Account

{

PUBLIC:

// Public member function

.

Private:

Double _balance;

}

Class Checking: Public Account

{

Private:

INT _foverdraftprotect;

}

...

Accent account;

Checking checking;

Account = Checking;

In the above example, the selected assignment operator is Account: Operator =. Because the default Operator = function comes with a type of Acconut & parameters, checking Account type objects copy to Account; and FoverDraftProtect does not copy.

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

New Post(0)