Effective C ++ 2e Item16

zhaozj2021-02-11  206

Terms 16: Assign all data members in Operator =

Terms 45 illustrate that if you don't write an assignment, the compiler will generate one for you. Terms 11 describes why you often don't like the compiler to generate this assignment operator, so you will want to have Two, the United States, let the compiler generate a default assignment operator, and then you can selectively rewrite the parts that don't like. This is impossible! As long as you want to control a part of the assignment process, you must be responsible for all things in the assignment process.

In actual programming, this means writing assignment operators, must assign each data member of the object:

Template Class Namedptr {// (originating Terms 12) PUBLIC: Namedptr (Const Namedptr); NamedPtr & Operator = (Const Namedptr & RHS);

PRIVATE: STRING NAME; T * PTR;

Template Namedptr & Namedptr :: Operator = (Const Namedptr & RHS) {if (this == & r Hs) Return * this; // See clause 17

// Assign to all data members name = rhs.name; // assignments to NAME

* ptr = * rhs.ptr; // For PTR, the value assigned is the value referred to by the pointer, / / ​​is not the pointer itself

Return * this; // see clauses 15}

When you write this class, it is of course easily remembered above, but it is also important to remember the update assignment operator when adding new data members. For example, intend to upgrade the NamedPTR template allows the name to change a time tag, then add a new data member while need to update constructor and assignment operators. But in reality, this is often easily forgotten because of the specific functions of the upgrade class and add new member functions.

When it comes to inherits, the situation is more interesting, because the assignment operator of the derived class must handle the assignment of its base class member! Take a look at:

Class base {public: base (int initialvalue = 0): x (InitialValue) {}

PRIVATE: INT X;

Class Derived: Public Base {public: Derived (INT InitialValue): Base (InitialValue), Y (InitialValue) {}

Derived & Operator = (const derived & rhs);

PRIVATE: INT Y;

Logically, Derived assignment operators should like this:

// Erroneous Assignment OperatRDerived & Derived :: Operator = (const Derived & r Hs) {if (this == & r Hs) Return * this; // See clause 17

Y = rhs.y; // Give only // data members of Derive Return * this; // See clause 15}

Unfortunately, it is wrong because the DeriveD object's base section is not affected in the assignment operator. For example, consider the following code segment:

Void assignmenttester () {Derived D1 (0); // D1.x = 0, D1.Y = 0 Derived D2 (1); // d2.x = 1, d2.y = 1

D1 = d2; // D1.x = 0, D1.Y = 1!}

Note that the BASE portion of D1 is not assigned to change.

The most obvious way to solve this problem is to assign the X in Derived :: Operator =. But this is not legal because X is private member of Base. So you must explicitly assign a value to the Derive's base part in the Deerive's assignment operator.

That is to do:

// Correct assignment operator Derived & Derived :: Operator = (const derived & r Hs) {if (this == & r Hs) Return * this

Base :: Operator = (rhs); // Call this-> base :: operator = y = rhs.y;

Return * this;}

Here is just explicitly calling Base :: Operator =, this call and in general, call additional member functions in the member function, as its implicit left value. Base :: Operator = Perform all the works of the BASE part of * this - just as what you want.

However, if the base class assignment operator is generated by the compiler, some compilers will reject this call for the base class assignment operator (see Terms 45). In order to adapt to this compiler, we must implement Derived :: operator =:

Derived & Derived :: Operator = (const derived & rhs) {if (this == & r Hs) return * this

STATIC_CAST (* this) = rhs; // The BASE section // of * this calls Operator = y = rhs.y;

Return * this;}

This weird code will be converted to BASE references, and then assign values ​​for its conversion results. Here is just to assign a value for the BASE part of the DeriveD object. It is important to pay attention to that conversion is a reference to the Base object, not the base object itself. If * this is enforced to the Base object, it is necessary to cause the copy constructor to call the base, and the new object (see Terms M19) becomes the target of assignment, while * this remains unchanged. This is not the result you want.

Regardless of the method used, after assigning the base part of the DeriveD object, it is followed by the assignment of the derived itself, that is, all the data members of Derived are assigned.

Another similar problem related to frequently occurring and inheritance is to achieve a copy constructor of the derived class. Take a look at the constructor, its code and the above-mentioned similar: Class base {public: base (int initialvalue = 0): x (const base & rhs): x (rhs.x) {}

PRIVATE: INT X;

Class Derived: Public Base {public: Derived (INT InitialValue): Base (InitialValue), Y (InitialValue) {}

Derived (const derived & rhs) // Error copy: y (rhs.y) {} // constructor

PRIVATE: INT Y;

Class Derived exhibits a bug generated in all C environments: When DeriveD is created, there is no copy of the base class. Of course, this DeriveD object's base section is still created, but it is created with the BASE default constructor, member X is initialized to 0 (the default parameter value of the default constructor), and does not take care of the copy object What is the x value!

To avoid this problem, the Derive copy constructor must ensure that the call is the base constructor of the base instead of the BASE default constructor. This is easy to do, as long as the member initialization list is specified for the base in the Member initialization list of Derived:

Class Derived: Public Base {public: Derived (const derived & rhs): base (rhs), y (rhs.y) {}

...

}

Now, when you copy an existing same type of object to create a DeriveD object, its base section will also be copied.

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

New Post(0)