Effective C + + reading notes (clause 30-34)

Source: Internet
Author: User
Tags class definition

(v). Implementation

_______________________________________________________________________________________________________________ _____________________

Article 30: A thorough understanding of the inside and outside of inlining

#1. Inline replaces every call to this function with the function body, so the inline function
You should ensure that the function body is short so that it can lead to a smaller target code and can lead to higher instruction
Cache concentration rate.

#2Most build environments are inlining during compilation, so the inline function is always placed in the header file.
Templates is usually also placed in the header file, because the compiler will present it during compilation.

#3Whether an inline function is really inlined depends on the build environment, but mainly on the compiler.
(most compilers will not be able to give you a warning message when the function you require is not inline.) )
(1)All calls to the virtual function will cause inlining to fail because virtual means that the run-time
Before deciding which function to call.
(2)The compiler generally does not "call through function pointers" inlining, for example:
inline void F () {...}   Suppose the compiler has the intention of inline "call to F" void (*PF) () =f;           PF points to F...f ();                   This call will be inlined because it is a normal call PF ();                   This call may not be inlined, as it is achieved through a function pointer
(3)Sometimes the compiler generates copies of constructors and destructors so that they can get pointers
Points to those functions, which are used in the construction and destruction of elements within an array.
(4). The Derived class constructor may not be inlined, because even if it is an empty construct, it will call
The base classes constructor and an exception security check cause the code block to grow so that it does not fit inline.

#4Do not declare the function templates as inline because it appears in the header file.

#5To limit the inline to a function that is bland to only one sentence or simply not inline, you can
Easy to debug in the future, but this also equals to the manual optimization of the road, but after all, it is more
Conforms to the 80-20 rule.
(although some build environments are struggling to support debugging of the inlined function, many other build environments can only
"Disable inlining in Debug Programs".)

#6One drawback of inline is that once the inline function is modified, the client that relies on it must re-
Compile, after all, inline inserts the function body, so make sure that inline is used in short, unambiguous code, which
Can be used to facilitate future upgrades.
_______________________________________________________________________________________________________________ _____________________
Article 31: Minimize compilation dependencies between files
#1The standard library should not make a predecessor declaration, but should use #includes to accomplish the purpose.
Reason 1: The pre-declaration of a standard library is complex and does not actually require you to do so.
Reason 2: The standard library means that it becomes a common standard, so it is rarely changed to
Requires recompilation, especially if it is used as a precompiled header, so be sure to use #includes.

#2The general idea of supporting "compile dependency minimization" is that it is dependent on the declarative, not on the definition. Because
The compiler needs to determine the size of its implementation for the definition, so that it increases compilation dependency.
(If you can, make the header file as self-sufficient as possible, do not consider declarative)
three simple, declarative strategies:
(1)If you can complete a task using object references or object pointers, do not use
Objects
(2)If possible, replace the class definition with a class declaration.
Note that when you declare a function and it uses a class, you do not need the class definition;//Even though the function passes the parameter (or return value) of the type by value: Class Date;            Date-Declarative date today (); void clearappointments (date D); Date-defined
(3). provide different header files for declarative and defined expressions (for the same object)
(For the unification of the organizational structure for more declarative purposes) For example: #include "datefwd.h"       //which declares class date;date today (), void clearappointments (Date D);//" Datefwd.h "naming depends on the <iosfwd>,<iosfwd> of C + + standard library files///Another manifestation is that this clause is also used for templates, after all, there are some built environments which allow the templates// The definition is placed in a "non-header file" so that only the header file containing the declaration can be provided to the templates-

#3The two methods based on declarative expressions are Handle classes and Interface classes.
Handle Classes Example: #include <string> #include <memory>//person.hclass personimpl;class address;class    Person{public:person (const std::string& name, const date& birthday, const address& addr);    std::string name () const;    std::string birthDate () const;    std::string address () const; ...private:std::tr1::shared_ptr<personimpl> pimpl;};/ /person.cpp#include "PersonImpl.h" person (const std::string& name, const date& birthday, const address& Addr    ):p Impl (new Personimpl (name, birthday, addr)) {}std::string person::name () const{return Pimpl->name ();}    Interface Classes Example: Class Person{public:virtual ~person ();    Virtual std::string name () const = 0;    Virtual std::string birthDay () const = 0;    Virtual std::string address () const = 0; Static std::tr1::shared_ptr<person>//Factory function (or virtual constructor) create (const std::string& name,//create a derived class Object and returns the base class pointer const date& birthday, the const ADdress& addr);    Return std::tr1::shared_ptr<person> (New Realperson (name, birthday,addr)); ...}; Class Realperson:public Person{public:realperson (const std::string& name, const date& birthday, const addre ss& addr): thename (name), Thebirthdate (birthday), theaddress (addr) {} virtual ~realperson () std::string name    () const;    std::string BirthDay () const;    std::string address () const;private:std::string thename;    Date thebirthdate; Address theaddress;}; {}//Customers can use this: std::string name;date dateOfBirth; Address address;...//creates an object that supports the person interface std::tr1::shared_ptr<person> pp (person::create (name, dateOfBirth, Address): Std::cout<<pp->name (), << "was born on" <<pp->birthday () << "And now lives at" <<pp->address ();..//pp leaving the scope object will automatically eliminate
evaluation of the handle classes and interface classes:
Using handle classes or Interface classes, although the compilation dependencies between files are reduced,
However, the code and target codes are increased, the simplicity is reduced, and the dynamic memory allocation brings in additional
Cost, and the possibility of encountering Bad_alloc. In addition, the virtual function in Interface classes
Indirect jump cost, in addition to the VPR, the presence of the
objects become larger, and their size depends on the different virtual classes in base and Dervied classes
The number of functions. Therefore, you should consider using these techniques in an evolutionary way.
_______________________________________________________________________________________________________________ _____________________

(vi). Inheritance and object-oriented design

_______________________________________________________________________________________________________________ _____________________

Article 32: Determine the is-a relationship that your public inheritance has molded
#1." Public inheritance "means is-a. Every thing that applies to base classes must also apply
On derived classes, because each derived class object is also a base class
Object.
For example:
Class Bird{public:    virtual void fly ();//bird Can fly    ...}; Class Penguin:public bird{//Penguin is a kind    of bird ...};//here the penguin is a kind of bird used the public inheritance,//But there is still a problem, "Penguins will not fly!" ",//And the inheritance here indicates that penguins can fly, and the reason/error is that not all birds will fly. We can change the interface to make it run with an error: void error (const std::string& msg); Defined somewhere else class Penguin:public Bird{public:    virtual void Fly () {error ("Attempt to make a Penguin fly!");}    ...};//so you can show at run time that "penguins can fly, but trying to do this is a mistake!" "//And the good interface should be able to prevent invalid code from compiling, so we should take//another in the" The compiler rejects Penguin flight "design, as follows: Class bird{...    }; Class Flyingbird:public Bird{public:    virtual void fly ();    ...}; Class Penguin:public bird{...    };//at this point, because the behavior is right and reasonable, you let the penguin fly, the compiler will certainly complain: Penguin p;p.fly ();//compile-time error

#2The. Public inheritance is appropriate for derived class that does not bind the original form and behavior of base classes:
For example:
Consider the following code: Class renctangle{public:virtual void setheight (int newheight);    virtual void setwidth (int newwidth);        virtual int height () const;    Returns the current value virtual int width () const; ...};    void Makebigger (rectangle& R)//This function is used to increase the area of R {int oldheight = R.height ();        R.setwidth (R.width () + 10); Add ten assert (r.height () = = OldHeight) for the width of R, or determine if the height of R has not changed}//obviously, the above assert result is always true. Because Makebigger only changes the width of R, the//height of R never changes. Now consider this code, which uses public inheritance to allow a square to be treated as a rectangle: class Square:public Rectangle {...};    Square S;...assert (s.width () = = S.height ());                        This pair of squares must be true makebigger (s); Because of inheritance, S is a (is-a) rectangle,//So we can increase its area.    ASSERT (s.width () = = S.height ()); To all squares should still be true. But we have a problem, when Makebigger (s), the second assert is not true//The reason is that square has changed the form of base Class-rectangle, has constrained the behavior,//because it requires a length equal to width, This is also a validation of these terms: public inheritance is suitable for//does not bind the original form and behavior of base classes derived class//from another point of view, any application of the base class should be applied to the Dervid class The base class requires a length that is not equal to the width, but the Dervid class cannot accommodate the requirement, soLook, squares and rectangles should be inherited by public, but not in reality. 
_______________________________________________________________________________________________________________ _____________________
Article 33: Avoid hiding the inherited name
#1. The only thing that the C + + name masking rule does is to obscure the name. As for the name type is not the same
is not important. (meaning to look at only the name, ignoring the name type, parameter type, number of arguments, etc.) )

#2. The C + + compiler follows a name lookup rule that is local to global.
For example, find a function whose order is:
Class->base class-> contains the base class namespace (s)->global
If you find the name somewhere, you will not continue looking down.

#3The name inside the. Derived classes will obscure the name within the base classes. Under public inheritance, you never
No one wants this. (This is a special case in # #)

#4In order to make the name of the Veil goodbye to Daylight, you can use
(1). Using declarative (exposing all the names within a scope)
(2). Transfer function (forwarding functions).
(enables a specific name within a scope to continue within another scope)
For example:
Class Base{private:int x;public:virtual void mf1 () = 0;    virtual void mf1 (int);    virtual void mf2 ();    void Mf3 ();    void Mf3 (double); ...};    Class derived:public base{public:virtual void Mf1 ();    void Mf3 ();    void Mf4 ();    ...};D erived d;int x;...d.mf1 ();    No problem, call DERIVED::MF1D.MF1 (x);    Mistake! Because the dervid::mf1 obscured the base::mf1d.mf2 ();    No problem, call BASE::MF2D.MF3 ();    No problem, call DERIVED::MF3D.MF3 (x); Error!        Because derived::mf3 obscured the base::mf3//"use using declarative methods": Class Derived:public base{public:using base::mf1;        Let all things named Mf1 and Mf3 in the Base class be using BASE::MF3;    virtual void Mf1 () is visible within the Derived scope (and public);    void Mf3 ();    void Mf4 ();    };//now look at the following changes: D.mf1 ();    No problem, call DERIVED::MF1D.MF1 (x);    Now no problem, call BASE::MF1D.MF2 ();    No problem, call BASE::MF2D.MF3 ();    No problem, call DERIVED::MF3D.MF3 (x);    Now, no problem, call base::mf3//now assumes we only want to inherit BASE::MF1 ()//So we can make it visible by means of a "transfer function"//and use that particular technique: class Derived:private {public: virtual void Mf1 () {BASE::MF1 ()}//Transfer function secretly becomes inline ...};Derived d;int x;d.mf1 ();    Well, the call is DERIVED::MF1D.MF1 (x); Error! BASE::MF1 (x) is obscured.
_______________________________________________________________________________________________________________ _____________________
Article 34: Differentiating between interface inheritance and implementation inheritance
#1. Interface inheritance differs from implementation inheritance. Under public inheritance, derived classes always inherits
The interface of the base classes.

#2. Three methods of function inheritance:
<1>The purpose of declaring a pure virtual function is to allow derived classes to inherit only the function interface.
(with mandatory implementation meaning, but its implementation code has reference meaning.) )
<2>The purpose of declaring a simple (non-pure) impure virtual function is to let derived classses inherit
The interface and default implementation of the function. (The interface and default implementation can be inherited by default.) )
<3>The purpose of declaring the Non-virtual function is to make the interface of the derived classes inheritance function and a copy of the
Mandatory implementation.
(The Non-vritual function means that its invariance overrides its specificity.) )
Consider the following code: Class Shape {public:    virtual void draw () const = 0;    The form of the <1>    virtual void error (const std::string& msg);//<2> form    int ObjectID () const;    The form of <3> ...    }; Class Rectangle:public shape{...}; Class Ellipse:public shape{...};

The design idea of <1> is: You must provide a draw function, but I do not interfere with how you implement it.
The design idea of <2> is: You must support an error function, but if you do not want to write one yourself,
You can use the version provided by the Shape class.
The design idea of <3> is: Objectid for base class and anyone who wants to use it
Derived class, if necessary, you just have to inherit and use it.

#3The. Pure virtual function can be implemented, but the only purpose for invoking it is "to explicitly indicate its class when called
Type ", the benefit is that you can avoid the default inheritance errors by using errors that are explicitly stated in the compile period.
Consider the following code: Class airport{...};    Class airplane{public:virtual void Fly (const airport& destination); ...}; void Airplane::fly (const ariport& destination); {//default implementation, fly the aircraft to the specified destination}class modela:public airplane{...}; Class Modelb:public airplane{...};//Now assume that the airport has introduced a C-type aircraft, but the C-type aircraft does not take the default route,//But to take a new route, so the airline programmer to add some code,//, but because of a momentary impatience, But forgot to add a new fly function: Class Modelc:public airplane{...}; The fly function is not declared//But this code compiles the line, run also no problem, so the C-type aircraft still take the default route,//So it became the airline's credit tragedy//that if we switch to pure virtual function, and to implement the code?    Like this: Class airplane{public:virtual void Fly (const airport& destination) = 0; ...}; void Airplane::fly (const airport& destination) {...};//the programmer must provide the implementation function for the new type of aircraft coercion,//and its implementation code becomes the default reference version class Modela:    Public airplane{public:virtual void Fly (const airport& destination) {ariplane::fly (destination); }}class modelb:public airplane{public:virtual void Fly (const airport& destination) {ariplane::fly (desti    Nation); }}class modelc:public airplane{public:virtual void Fly (const airport&Amp destination);} void Modlec::fly (const airport& destination) {//C-plane to the destination on a new route}//this way, if the programmer does not provide a fly function for each model of aircraft,//The compiler will issue a warning, This avoids committing such errors, although it lowers//some brevity, but adds some clarity. In addition, because the class containing pure//virtual can only become abstract class, can not be instantiated, therefore, its//use occasions have been added some restrictions.

_______________________________________________________________________________________________________________ _____________________

Effective C + + reading notes (clause 30-34)

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.