Construction, analysis, and value assignment of Objective C ++

Source: Internet
Author: User

Construction, analysis, and value assignment of Objective C ++

Article 05: Understand the functions that C ++ has quietly compiled and called

The compiler will declare a copy constructor, a copy assignment operator in one destructor, all of which are public and inline functions.

If you want to support the assignment operation in a class containing reference members, you must define the copy assignment operator to respond to the classes compiler of the const member.

In another case, if a base class declares the assignment operator as a private compiler, it will reject the generation of a copy assignment operator for the derived class.

Remember

@ The compiler can secretly create default constructor, copy constructor, copy assignment operator, and destructor for the class.

Clause 06 if you do not want to use a function automatically generated by the compiler, you should explicitly reject it.

There is a class to describe the house for sale

Class HomeForSale {};

If any asset is unique, the class should not have a copy.

HomeForSale h1;

HomeForSale h2;

HomeForSale h3 (h1) // an attempt to copy h1 ---- compilation should not pass

H1 = h2;/compilation should not pass

To solve the above problems

The copy constructor and the copy assgiment operator can be declared as private to prevent the compiler from secretly creating its exclusive version. But this is not absolutely safe because member and friend functions can still call your private functions. The best way is not to define them to declare the member functions as private and deliberately not provide implementation for them.

Then HomeForSale can be rewritten in this way.

Class HomeForSale {

Private:

HomeForSale (const HomeForSale &); // just declare not to implement

HomeForSale & operator = (const HomeForSale &); // same as above

};

In many cases, we have designed a base class to block copying actions.

Class Uncopyable {

Proctected:

Uncopyable (){}

~ Uncopyable (){}

Private:

Uncopyable (const Uncopyable &);

Uncopyable & operator = (const Uncopyable &);

};

Other classes only need to inherit this class to get and block copying behavior (the boost Library provides class noncopyable to block copying behavior)

Remember:

@ To reject the functions provided by the compilation automation (secretly), the corresponding member functions can be declared as private and not implemented. Using base classes such as Uncopyable is also an approach

Cla07: declare virtual destructor for a multi-state base class

Class TimeKeeper {

Public:

TimeKeeper ();

~ TimeKeeper ();

};

Class AtomicClock: public TimeKerrper {...}

Class WaterClock: public TimeKeeper {...}

The object pointer is as follows:

TimeKeeper * getTimeKeeper (); // point to an object pointer dynamically allocated by a derived class

TimeKeeper * ptk = getTimeKeeper ();

Delete ptk;

The above will cause some problems. C ++ understands that when a derived object is deleted through a base class pointer, the base class carries a non-virtual destructor, and the result is not defined normally. release derive components

It is easy to eliminate the problem by providing a virual destructor for the base class.

However, if the class does not include the vitual function, then normally it is not intended to be treated as a base class. If the Destructor is virtual, the behavior will also be bad because the object containing the virtual function has its internal if a vptr pointer is maintained, its object will be larger than the object without the virual function.

Note the following:

Class SpecialString: public string // string has a non virual destructor.

{

 

};

If you accidentally convert a pointer to SpecialString to a pointer to string in the program and delete it, the behavior will be ambiguous.

String has a non virual destructor.

Sometimes it may be more convenient to bring a pure virtual destructor to the class (at the same time, a definition should be provided for the Destructor; otherwise, the compiler will complain)

Class AWOV

{

Public:

Virtual ~ AWOV () = 0;

};

AWOV ::~ AWOV (){}

The above situation applies only to base classes with polymorphism.

 

Remember:

@ Polymorphic (with polymorphism) base class should declare a virtual destructor. If the class has any virtual function, it should have a virtual destructor.

@ Classes should be declared as a virual destructor if it is not used as a base class or is not used for polymorphism.

Cla08: do not escape exceptions from destructor

C ++ does not encourage you to spit out exceptions in the destructor.

If your destructor must execute an action and the action may throw an exception when it fails, for example:

Class DBConnection {

Public:

Static DBConnection Create ();

Void close ();

}

To ensure that the customer calls close () on the DBConnection object, a reasonable idea is to create a class to manage BDconnection resources.

Class DBConn

{

~ DBConn ()

{Db. close ()}

Private:

DBConnection db;

}

The close () call is successful, but if the call causes an exception, DBConn will spread the exception, that is, allow him to leave the destructor, it will cause problems.

We usually try to improve it.

1. If close throws an exception, the program is usually finished using abort.

DBConn ::~ DBConn ()
{
Try
{
Db. close ()
}
Catch (...)
{
Std: abort ();
}
}

Force end program

2. Swallow the exception caused by calling close.

DBConn ::~ DBConn ()
{
Try {db. close ();}
Catch (...)
{
..........
}
}

Continue execution regardless of the exception.

3. The best practice is to redesign the DBConn interface so that users have the opportunity to respond to possible problems as follows:

Class DBConn
{


Public:
//...
Void close () // used by the customer, which is a chance for the customer to catch exceptions
{
Db. close ();
Close = true;
}
~ DBConn ()
{
If (! Close)
{
Try {db. close ();}
Catch (...)
{
// Record exceptions close programs or swallow exceptions
}
}
}
Private:
DBConnection db;
Bool close ();
};

Remember:

@ Destructor do not spit out exceptions. If a function called by the Destructor may throw an exception, the Destructor should capture any exceptions and then spit it out or end the program.

@ If you need to respond to an exception thrown during the running of an operation function, the class should provide a common function (not in the destructor) to execute this operation.

09 virtual functions are never called during construction and analysis.

Assume that you have the following class hierarchy

Class Transaction

{

Public:

Transaction ();

Virtual void LogTransaction () const = 0; // log records vary depending on different types.

....

};

 

Transaction: Transaction (){

LogTransaction ();

}

Class BuyTransaction: public Transaction {

Public:

Virtual void LogTransaction () const; // transaction log Buy

}

Class SellTransaction: public Transaction

{

 

Public:

Virtual void LogTransaction () const; // transaction log volume

 

}

If the following statement is used for BuyTransaction, The called version of LogTransaction is the version in the base class and not in the BuyTransaction, the virtual function during base class construction will never fall to the derived class (during base class construction, the virtual function is not a virtual function)

One solution: Change the logTransaction function to the non-virtual function in class Transaction, and then require the derived class constructor to pass the necessary information to the logTransaction constructor.

Clss Transaction {

Public:

Explict Transaction (const std: string & loginfo );

Void LogTransaction (const std: string & loginfo) const;

};

Transaction: Transaction (const std: string & loginfo)

{

....

LogTransaction (loginfo)

}

Class BuyTransaction: public Transaction

{

Public:

BuyTransaction (prameter): Transaction (CreateString (praneter )){...}

Private:

String CreateString (parameters)

}

Remember:

@ Virtual functions cannot be called during constructor and destructor because such calls never fall to derived class.

Clause 10: Make operator = return a reference to * this

Shape: Widget & operator = (const Widget & rhs)

{

Return * this;

}

Remember:

Returns a reference to * this;

Clause 11: handle "self-assignment" in operator ="

Assume that you create a class to save a bitmap with a pointer pointing to the dynamic allocation)

Class Bitmap {...}

Class Widget {

Private: Bitmap * pb;

}

Operator = implementation code:

The traditional method is to test the self-assignment by adding the test of identity verification.

Widget & Widget: operator = (const Widget & rhs)

{

If (this = & rhs)

Return * this;

Delete pb;

Pb = new BitMap (* rhs. pb );

Return * this;

}

If you are very concerned about program efficiency, you can put the same test at the beginning of the function again, but you have a general idea about the frequency of Self-assignment, because the same test requires the same cost.
Similarly, we can use the copy and swap technology to replace the manual sorting code to solve the problem of self-assignment.
Class wightet {};
Void swap (Widget & rhs)
{
.......
}
Wiget & Widget: operator = (const Widget & rhs)
{
Widget temp (rhs );
Swap (temp );
Return * this;
}
More efficient code: (1: The copy assigment operator of a class can be declared to accept the parameter in the by value method. 2: passing something in the by value method will result in a replica)
Wiget & Widget: operator = (Widget rhs)
{

Swap (rhs );
Return * this;
}

Remember:
@ Ensure that operator = has good behavior when the object is assigned a value. The technology includes comparing the addresses of "source object" and "target object", and carefully following the order of statements, and copy-and-swap
@ Confirm that any object operates on more than one object. When multiple objects are the same object, the behavior is still correct.

Clause 12 do not forget to assign values to every component of an object when assigning values to objects.

Class Date {};
Class {
Public:
A (const &);
A & operator (const A & );
Private:
String m_strname;
Date m_Date;
};
Do not forget to copy every component of the object without using the constructor provided by the compiler.
Class B: public
{
Public:
B (const B & B );
B & operator = (const B & B );
Int m_p;
};

B: B (const B & B): A (B), m_p (B. m_p) // call the constructor of
{
Logcall ("copying ");
}
B & B: coperator = (const B & B)
{
Logcall ("copying assignment ");
A: operator = (B );
M_p = B. m_p;
Reutrn * this;
}
It makes no sense for the copy constructor to call the copy assignment operator or the copy assignment operator to call the copy constructor!
If two similar codes are generated, the third function is introduced to reduce code duplication.
Remember:
The @ copying function should ensure that the value "all member variables of the object" has base class components.
@ Do not try to implement another copying function using a copying function. You should put the common functions into the third function and call them together by the two functions.


 

 

 

 

 

Zookeeper

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.