C ++ Reading Notes Objective C ++ (2)

Source: Internet
Author: User

18. Good interfaces are easy to use correctly and cannot be misused. You should try to achieve these properties in all your interfaces. "Promoting correct use" includes interface consistency and compatibility with built-in behaviors. The methods to prevent misuse include creating new types, limiting operations on types, binding object values, and eliminating customers' resource management responsibilities. Tr1: shared_ptr supports custom delimiters. This prevents DLL problems and can be used to automatically remove the mutex lock wait.
19. The design of Class is the design of type. Before defining a new type, make sure that you have considered all the topics covered by these terms.
20. replace pass-by-reference-to-const with pass-by-value instead of pass-by-reference-to-const. the former is usually relatively efficient and can avoid cutting problems. The above rules do not apply to built-in types, as well as STL iterators and function objects. For them, pass-by-value is often more appropriate. 21. when an object must be returned, do not think about returning its reference. Do not return pointer or reference pointing to a local stack object, or return reference pointing to a heap-allocated object, or return pointer or reference pointing to a local static object, which may require multiple such objects at the same time.
22. remember to declare the member variables as private. this gives the customer the consistency of access data, the ability to slightly divide access control, the promise of constraints to be guaranteed, and the class author to fully implement elasticity. Protected is not more encapsulated than public.
23. If you need to perform type conversion for all parameters of a function (including the parameter metaphor parameter referred to by this pointer), the function must be non-member.

Note: If the member variable is not public, the only way the customer can access the object is through the member function. If everything in the public interface is a function, you do not need to try to remember whether to use parentheses when you plan to access the class members. If you use a function to access a member variable, you can replace the member variable with a certain calculation in the future, and the class client will not change until the internal implementation of the class has changed, which encapsulates the features. If you do not hide the member variables, even if you have the class primitive code, the ability to change any public object is still in extreme constraint, because it will damage too many customer codes. Public means no encapsulation, but not encapsulation means that it cannot be changed, especially for classes that are widely used in heap. The widely used class is a group that needs to be encapsulated most, because they are most able to benefit from the encapsulation of something from "using a better implementation version" is inversely proportional to the amount of code corruption that can be caused when their content changes. Suppose we have a protected member variable. When we want to cancel it, all derived classes inherited from it will be affected. The protected member variable lacks encapsulation just like the public member variable, because in both cases, if the member variable is changed, a large amount of unpredictable code will be damaged. Too many codes need to be rewritten, re-tested, re-compiled, and re-compiled. In terms of encapsulation, there are actually only two types of access permissions: private (providing encapsulation) and others (not providing encapsulation ).
24. if all parameters require type conversion, use the non-member function. If you need to convert all parameters of a function (including the metaphor parameter referred to by this pointer, so this function must be a non-memeber.25. consider writing a swap function that does not throw an exception. When std: swap is inefficient at your type, provide a swap member function and make sure this function does not throw an exception. If you provide a memeber swap, you should also provide a non-member swap to call the former. For class, you can specialize in std: swap. It is good to fully specialize std templates for "User Type", but never try to add something new to std. When swap is called, the using declarative form is used for std: swap, and then the called swap does not contain any "namespace qualification modifier". 26. The variable definition format appears as soon as possible. In this way, the definition of the program can be increased and the efficiency of the program can be improved. 27. If possible, try to avoid transformation, especially in efficiency-focused code to avoid dynamic_casts. If there is a design that requires transformation, try to develop an alternative design that does not require transformation. If transformation is necessary, try to hide it behind a function. The customer can then call and modify functions without putting the transformation into their own code. We would rather use the C ++ style (New style) transformation than the old style transformation. The former is easy to identify and has a different role. 28. Avoid returning handlers (including references, pointers, and iterators) to the object. Compliance with this clause can increase encapsulation, help const member functions behave like a const, and minimize the possibility of a "virtual hanging number plate. 29. Exception-safe functions do not leak resources or allow any data structure corruption even if an Exception occurs. Such functions are classified into three possible guarantees: basic type, strong type, and no exception type. "Strong assurance" is often implemented using copy-and-swap, but "strong assurance" is not practical for all functions. The "exception security guarantee" provided by the function is usually the weakest among the "exception security guarantee" provided by each function called by the function. Note: a small amount of code is good code, because there are fewer opportunities for errors, and there are fewer opportunities for misunderstanding once there is a change. Basic Type: if an exception is thrown, everything in the program remains in a valid state. No object or data structure is corrupted, and all objects are in a consistent internal state. Strong type: If a constant is thrown, the program State does not change. To call such a function, you need to know that if the function is successful, it is completely successful. If the function fails, the program will return to the status before the function is called. Do not throw exception type: Promise not to throw exceptions because they can always fulfill their original commitments. All operations acting on the built-in types provide the nothrow guarantee. However, it is difficult for users to meet the requirement. If dynamic memory cannot be found to meet the requirement, a bad_alloc exception is usually thrown. For most functions, the choice usually falls between the basic guarantee and the strong guarantee.
Resource management with objects is the root of a good design. There is a general design that typically leads to a strong guarantee and deserves to be familiar with it. This policy is called copy and swap. The principle is simple: Make a copy of the object you intend to modify (the original), and then make all necessary modifications on the copy. If any modification action throws an exception, the original object remains unchanged. After all the changes are successful, replace the modified copy with the original object without throwing an exception (swap ).
If one (the only one) function in the system does not have exceptional security, the entire system does not have exceptional security, because calling that function may cause resource leakage or data structure corruption. How to Make code written by yourself more secure: 1. Managing resources with objects can prevent resource leakage. 2. Select three exceptions to ensure that one of them is implemented on each function you write.

I personally like the last paragraph in the book: "forty years ago, code loaded with goto was considered a good practice, but today we are committed to writing structured control flows. Two decades ago, global data was regarded as a good practice, but now we are committed to Data encapsulation. A decade ago, writing a function "not taking exceptions into consideration" was considered a good practice. Now we are committed to writing "exceptional security code "".
30. restrict most inlines to small and frequently called functions. This makes the debugging process and binary upgrade easier in the future, and minimizes potential code expansion problems, maximizing the program's speed increase. The general idea of declaring function templates as inline.31. to support "minimal compilation dependency" is not dependent on declarative statements. The two methods given to this idea are Handle classes and Interface classes. Library header files should exist in the form of "completely and only declarative. This method applies regardless of whether templates is involved. Note: # include <string> # include "date. h"
# Include "address. h"

Class Person
{
Public:
Person (const std: string & name, const Date & birthday, const Address & addr );
Std: string name () const;
Std: string birthday () const;
Std: string address () const;

Private:
Std: string theName;
Date theBirthday;
Address theAddress;
} Compile the class person to contain the corresponding header files of the string Date and Address classes. In this way, a compilation dependency relationship is formed between the Person definition file and Its included files. If any of these header files is modified or the other header files on which these files depend are changed, each file containing the Person class must be re-compiled, any file that uses the Person class must be re-compiled. Such dependencies can cause unspeakable disasters to many projects. Two methods can be used to remove the coupling relationship between interfaces and implementations: Handle classes and Interface classes)
Method 1 // Person. h
# Include <string>
# Include <memory>

Class PersonImpl;
Class Date;
Class Address;

Class Person
{
Public:
Person (const std: string & name, const Date & birthday, const Address & addr );
Std: string name () const;
Std: string birthday () const;
Std: string address () const;

Private:
Std: tr1: shared_ptr <PersonImpl> pImpl;
}

// Person. cpp
# Include "Person. h"
# Include "PersonImpl. h"

Person: Person (const std: string & name, const Date & birthday, const Address & addr)
: PImpl (new PersonImpl (name, birthday, addr ))
{
}
Std: string Person: name () const
{
Return pImpl-> name ();
}
In the above Code, the Person class contains a Pointer member pointing to its implementation class. This design is called "Pointer to implementation ". In this design, the customer of Person is completely separated from the Implementation Details of Dates, Address, and Person. Any implementation changes to those classes do not require the Person client to be re-compiled. In addition, because the customer cannot see the Implementation Details of Person, it is impossible to write "depends on those details" code. This is actually "separation of interfaces and implementations "! The key to this separation is to replace "defined dependency" with "declared dependency", which is the essence of minimizing compilation dependency: In reality, let the header file satisfy itself as much as possible, in case it cannot be done, so that it is dependent on the declarative type (rather than the definition type) of other files. You can use the following policies to achieve this purpose: 1. if you use object reference or object pointerrs to complete tasks, do not use objects 2. if possible, replace the class definition with the class declaration. Note: When you declare a function and use a class, you do not need to define the class, even if the function Passes parameters of this type (or return values) by value ). However, once anyone calls those functions, the Date definition must be exposed before calling.

Method 2 # include <string>
# Include <memory>

Class PersonImpl;
Class Date;
Class Address;

Class Person
{
Public:
Static std: str1: shared_ptr <Person> create (const std: string & name,
Const Date & birthday,
Const Address & addr );
Virtual std: string name () const = 0;
Virtual std: string birthday () const = 0;
Virtual std: string address () const = 0;
Virtual ~ Person ();
};
Class RealPerson: public Person
{
Public:
RealPerson (const std: string & name, const Date & birthday, const Address & addr)
: TheName (name), theBirthday (birthday), theAddress (addr)
{
}
Std: string name () const;
Std: string birthday () const;
Std: string address () const;
Virtual ~ Person ();
Private:
Std: string theName;
Date theBirthday;
Address theAddress;
};
Std: tr1: shared_ptr <Person> Person: create (const std: string & name,
Const Date & birthday,
Const Address & addr)
{
Return std: tr1: shared_ptr <Person> (new RealPerson (name, birthday, addr ));
}
// Use the client
Std: string name;
Date dateOfBirth;
Address address;

Std: tr1: shared_ptr <Person> pp (Person: create (name, dateOfBirth, address ));
Std: cout <pp-> name ()
<Pp-> birthday ()
<Pp-> address ();

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.