Effective c++18-25 terms "interface design and declaration" collation

Source: Internet
Author: User

First, make the interface easy to use correctly, not easy to misuse

The principle of interface design is to facilitate the use of future and other users, do not leave the problem to the interface users

(1) A "specially" designed interface is called with regular usage. So it is necessary to make your own design as much as possible: the behavior of the data object should conform to the behavior of the built-in object (such as int) as much as possible, and the name and meaning of the interface should be as consistent as possible (for example, the container in the STL basically has an interface called size to return the container) ... This encourages the user to look at and use your interface correctly.

(2) forgot to deal with the legacy issues after invoking the interface. So don't let the user "remember" to do something.
If an interface is designed to return a pointer to a new object, the user of the interface needs to "remember" to release the object that the pointer refers to: if the user forgets to release or release several times, the consequence is SB.
One solution is to have the interface return a smart pointer so that the user can "forget" the pointer by running out of it: it will handle the funeral itself.

(3) The so-called "Cross DLL Problem" (problem): A DLL in a new object, and then the object is passed to another DLL is deleted. The master recommends using shared_ptr because it solves the problem.
Cost: the creation and destruction of additional objects takes time space. For example, the boost shared_ptr is twice times the size of the normal pointer, there are additional object operation time + process dynamic memory allocation and so on.

Second, the design class is like the design type

(1) Carefully design the method of creation and destruction of the class, as well as the constructors and destructors.
(2) Seriously consider how to classify the constructors and copy constructors, assignment (Assignment) operators. That is, the difference between initialization and assignment.
(3) Note the pass-through value of the implementation class (passed by value). This is actually about paying attention to the implementation of the copy constructor.
(4) The inheritance system in which the class is located needs to be examined.
If the class has a parent class, it must be limited by the parent class, especially if the function is fictitious, if the class has subclasses, then consider whether some functions need to be defined as virtual functions, such as destructors.
(5) Implement the conversion of class objects with other types of objects with care. This is slightly more complicated: if there is a need to convert T1 to T2, there are two ways of implicit and explicit conversions.
For the former, you can write an (implicit) conversion function, or by writing an additional T2 constructor to implement the T1-to-T2 transformation.
For the latter, Scott says to write a (explicit) conversion function.
(6) • You need to consider which operations the class needs to participate in. Obviously, if you need to participate in a operation, you define the Class A operator function accordingly. The other thing that the master is mentioning here is that some of these operational symbolic functions should be member functions, and some should not.
(7) Do not provide standard functions that should not be exposed. The standard function here refers to the constructor/destructor/copy, and so on may be generated by the compiler "voluntarily" for you, if you do not want some of them to be called by the outside, it is declared as private (private).
(8) Notice the access rights of the design class members. Which should be used for public, protection (protected), private (privately)? Is there a need to define friends? Or is it simply a class class? All need to be considered.

Third, pass by Referrence to const replace pass by value

C + + passes the object by default (Pass-by-value), which is naturally expensive: This includes the construction/destruction of temporary objects, as well as the construction/destruction of objects in temporary objects, and perhaps the construction/destruction of objects in objects in an object by the point of luck.

(1) A better alternative is to pass a "const reference" (PASS-BY-REFERENCE-TO-CONST) relative to the "value".
(2) A difference between a pass and a pointer is that the object passed by the value is not the original object, but a copy, so you can beat it to scold it, the flesh will not be affected.
(3) The object that passes the pointer and the original object is the same guy, and the other one is affected by the same thing. And this is sometimes not the result we want.
(4) Given that the value of the transfer is too high, a "const reference" is a good substitute.
(5) Another advantage of "const reference" is to avoid the "skinning problem" (slicing problem, Houtie master version is "Object cutting problem", I use this Chinese name is to make it easier to remember:))
A function that passes a parameter, if the type of an argument is a parent class object, and the actual passed parameter is a subclass object, only the parent part of the object is constructed and passed to the function, the member of the subclass part, as the "skin" of the parent object, is stripped off by the bloody ...
And if you use the "Const reference" way, there is no such inhuman situation: the parent class pointer can be used to point to a subclass object, natural.

Exception: For built-in type (bulit-in type) objects, as well as iterators and function objects in the STL, it is recommended to use the pass-through method because they are originally designed to be passed as pass-through values.

Iv. do not return the reference of the object when it is swapped back

If a function may return a reference to an object that does not exist , then the function will create the object itself: either on the stack (stack) or on the heap (heap).

(1) In the first case, a local object is defined in the function and then a reference to the object is returned. The object is automatically destroyed after the function ends, and the reference points to an invalid address.
(3) In the second case, the function creates an object using new dynamically, and then returns a reference to the object. It's fine to look at it, because the return reference is still valid.
But think about it: can we make sure that the object is properly retracted (delete)?

Rethinking: Overloading an operator in a class, calling its overloaded operator by default with an object of that class, returns no problem with referencing a reference to an already existing object, so it does not match the article description.


V. Declaring a member variable as private

Members of the public are completely open to the outside of the class, while the protected members are completely open to the inheritors of the class. From an encapsulation perspective, there are only two levels of access: private, and so on. Not much else to say.

Replace the member function with Non-member and non-friend

Compared to Java and c#,c++ allow non-member functions to be defined outside the class, the existence is reasonable, if necessary, can be sacrificed
In terms of flexibility, non-member functions are less compiler dependent (compilation dependency), which is more beneficial for class extensions.
Example: A class may have more than one member function, there may be one function that requires A.h, and another function to contain B.h, so when compiling this class you need to include both A.h and B.h, which means that the class is dependent on two header files at the same time.
If you use a non-member function, you can write these different functions of the dependencies in different header files at this time, it is possible that this class will not need to rely on A.h or B.h at compile time.
When you define these non-member functions in different header files, you need to use the namespace keyword to put them together with the classes that need to be accessed.

Code in Class_a.h  namespace  allaboutclassa  {     class  ClassA  {//...};     // ..  }  Code in Utility_1.h  //.  Namespace  Allaboutclassa  {     void  wrapperfunction_1 () {//...};     // ..  }  // ..  Code in Utility_2.h  //.  Namespace  Allaboutclassa  {     void  wrapperfunction_2 () {//...};     // ..  }  // ..

If there is a need to add new non-member functions, all we have to do is define these functions in the same namespace, and that class is not affected at all, that is, the so-called extensibility.
for the user of the class, this implementation (referring to non-member functions) has greater degrees of freedom


Effective c++18-25 terms "interface design and declaration" collation

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.