Google C ++ programming style guide (1): header file [this article]
Google C ++ programming style guide (2): Scope
Google
C ++ programming style guide (III): c ++ class
Google C ++ programming style guide (4): Smart pointers and other C ++ features
Google
C ++ programming style guide (5): naming conventions
Google C ++ programming style guide (6 ):CodeNote
Google
C ++ programming style guide (7): Format
Google C ++ programming style guide (8): Rule exceptions
Background
Google's open-source projects are mostly developed using C ++. Every C ++ProgramAs we all know, C ++ has many powerful language features, but this powerful will inevitably lead to its complexity. This complexity will make the code more prone to bugs, difficult to read and maintain.
The purpose of this Guide is to elaborate on how to write and not write in C ++ encoding to avoid its complexity. These rules allow code to effectively use the C ++ language features while making it easy to manage.
Style, also known as readability, mainly refers to the habit of managing C ++ code. The term style is a bit inappropriate, because these habits are far moreSource codeThe file format is so simple.
One of the ways to make code easy to manage is to enhance code consistency, so that others can understand your code, maintaining a unified programming style means that you can easily deduce the meaning of various symbols based on the pattern matching rule. Creating common and necessary idioms and patterns can make the code easier to understand. Changing the programming style may be a good choice in some cases, but we should still follow the consistency principle, try not to do this.
Another point in this guide is the bloated nature of C ++. C ++ is a giant language that contains a large number of advanced features. In some cases, we may restrict or even prohibit the use of certain features to simplify the code and avoid possible problems, the Guide lists these features and explains why these features are restricted.
Open-source projects developed by Google will comply with the provisions of this Guide.
Note: This guide is not a C ++ tutorial. We assume that you are familiar with C ++.
Header file
Generally, every. CC files (C ++ source files) have a corresponding one. h file (header file), there are some exceptions, such as unit test code and only include main. CC file.
Correct use of header files can greatly improve code readability, file size, and performance.
The following rules will guide you to avoid various troubles when using header files.
1.
# Define protection
All header files should be used # define to prevent the header files from being contained (multiple
Permission sion). The naming format is <project >_< path >_< file >_h _
To ensure uniqueness, the header file name should be based on the full path of the project's source code tree. For example, the header file Foo/src/BAR/Baz. h In project foo is protected as follows:
# Ifndef
Foo_bar_baz_h _
# Define foo_bar_baz_h _
...
# Endif //
Foo_bar_baz_h _
2. header file dependency
Use a forward statement
Declarations) Minimize the number of # include files in. H files.
When a header file is included and a new dependency is introduced, the code will be re-compiled as long as the header file is modified. If your header file contains other header files, any changes to these header files will also lead to code recompilation that contains your header files. Therefore, we would rather include as few header files as possible, especially those contained in other header files.
Using the pre-declaration can significantly reduce the number of header files to be included. Example: If the class file is used in the header file, but you do not need to access the file declaration, you only need to predeclare the class in the header file.
File; # include "file/base/file. H" is not required ".
In the header file, how do I use the class Foo without the definition of the category class?
1)
Declare the data member type as Foo * or Foo &;
2) The function with the parameter and return value type foo is declared (but not implemented );
3)
The type of the static data member can be declared as Foo, because the definition of the static data member is out of the class definition.
On the other hand, if your class is a subclass of Foo or contains non-static data members of the type Foo, you must include the header file.
Sometimes, use the pointer member (pointer
Members, if it is scoped_ptr better) replace object members (Object
Members) is indeed more meaningful. However, this approach will reduce code readability and execution efficiency. If you only want to include fewer header files, do not replace them.
Of course, the. CC file requires the definition of the class in any way, and naturally contains several header files.
Note: If the Declaration can be relied on, do not rely on the definition.
3. inline functions
The function is defined as an inline function only when there are 10 or even fewer rows.
Function ).
Definition: After a function is declared as an inline function, the compiler may expand it inline without calling the inline function according to the common function call mechanism.
Advantage: When the function body is small, inline function can make the target code more efficient. For access functions (accessor and mutator) and other short key execution functions.
Disadvantage: Misuse of inline will lead to program slowdown. inline may be the amount of target code or increase or decrease, depending on the size of the function to be inline. Inline short and small access functions usually reduce the amount of code, but inline a large function will dramatically increase the amount of Code if the compiler permits. In modern processors
Cache), small code is often executed faster.
Conclusion: A proper processing rule is to avoid inline functions with more than 10 rows. You should be careful with the destructor. The Destructor usually looks longer than its surface because some implicit members and basic class destructor (if any) are called!
Another useful processing rule: inline functions that contain loops or switch statements are not worth the candle unless in most cases these loops or switch statements are never executed.
Importantly, virtual and recursive functions are not necessarily inline functions even if declared as inline functions. Generally, recursive functions should not be declared as inline (note: the expansion of the recursive call stack is not as simple as a loop. For example, the number of recursive layers may be unknown during compilation, most compilers do not support inline recursive functions ). The main reason for inline destructor is that they are defined in the class definition to facilitate or document their behavior.
4.
-InL. h file
The definition of complex inline functions should be placed in the header file with the suffix-inL. h.
Define inline functions in the header file so that the compiler can expand them inline at the call. However, the implementation code should be fully put into the. CC file. We do not want too much implementation code in the. h file unless it has obvious advantages in readability and efficiency.
If the definitions of inline functions are short and the logic is simple, the implementation code can be placed in. H files. For example, the implementation of the access function is put in the class definition. For the convenience of implementation and call, more complex inline functions can also be placed. in the H file, if you think this will make the header file seem bulky, you can also separate it into a separate-inL. h. In this way, the implementation and class definition are separated. When necessary, the-inL. H of the implementation can be included.
-The inL. h file can also be used for defining function templates to enhance the readability of template definitions.
One thing to note is that-inL. H, like other header files, also requires # define protection.
5.
Function parameter Order (function parameter
Ordering)
When defining a function, the parameter order is: the input parameter is in the front, and the output parameter is in the back.
C/C ++ function parameters are divided into two types: input parameters and output parameters. Sometimes input parameters are output (NOTE: When the value is modified ). Input parameters are generally passed as values or constant references (const
References), the output parameter or the input/output parameter is not a constant pointer (non-const
Pointers ). When sorting parameters, all input parameters are placed before the output parameters. Do not put the newly added parameter at the end, but before the output parameter.
This is not a rule that must be followed. Mixing input/output parameters (usually class/struct variables) makes it difficult to follow the rules.
6. Names and order of files contained
Standardizing the inclusion order enhances readability and avoids hiding dependencies (hidden)
Dependencies. Note: hidden dependency mainly refers to the compilation of included files. The order is as follows: C library, C ++ library, and other libraries. h. h.
The header files in the project should be arranged in the tree structure of the project source code directory, and the Unix File paths (current directory) and (parent directory) should be avoided ). For example, Google-awesome-Project/src/base/logging. H should be included as follows:
# Include
"Base/logging. H"
DIR/Foo. CC is mainly used to execute or test the dir2/foo2.h function. Foo. CC contains the following header file order:
Dir2/foo2.h (priority, details are as follows)
C System File
C ++ System File
Other library header files
Header files in this project
This sorting method can effectively reduce hidden dependencies. We hope that each header file can be compiled independently. The simplest implementation method is to include the first. h file in the corresponding. CC file.
DIR/Foo. CC and dir2/foo2.h are usually located in the same directory (such as base/basictypes_unittest.cc and base/basictypes. h), but they can also be located in different directories.
The header files in the same directory are in alphabetical order.
For example, Google-awesome-Project/src/Foo/Internal/fooserver. CC contains the following order:
# Include
"Foo/public/fooserver. H" // priority
# Include
<Sys/types. h>
# Include <unistd. h>
# Include
<Hash_map>
# Include <vector>
# Include
"Base/basictypes. H"
# Include "base/commandlineflags. H"
# Include
"Foo/public/bar. H"
______________________________________
Translator: English is not very good and translation is not very good. This article mainly mentions some rules for header files, which are summarized as follows:
1. avoiding multiple inclusion is the most basic requirement for programming;
2. The pre-declaration aims to reduce compilation dependencies and prevent the domino effect caused by modifying a header file;
3. Proper Use of inline functions can improve code execution efficiency;
4.-inL. h can improve code readability (generally not used)
);
5.
The order of standardized function parameters can improve readability and Maintainability (it has a slight impact on the stack space of function parameters. I used to put the same type together );
6.
The name of the contained file is used. and .. although convenient but confusing, the use of a complete project path looks clear and organized, including the order of files in addition to appearance, the most important thing is to reduce hidden dependencies, make each header file "requires compilation most" (corresponding to the source file
), Some people put the library file at the end, so that errors are first the files in the project, the header files are placed at the beginning of the corresponding source files, this is enough to ensure that internal errors are detected in a timely manner.
Google C ++ programming style guide (2): Scope
Scope
1.
Namespaces)
In the. CC file, we recommend that you use an unnamed namespace (unnamed
Namespaces, Translator's note: An unnamed namespace is like an unnamed class and seems to be rarely introduced :-(). When using a namespace, its name can be based on the project or path name. Do not use the using indicator.
Definition: The namespace divides global scopes into different and named scopes, effectively preventing name conflicts in global scopes.
Advantage: The namespace provides (nesting) named Axis (name
Axis, Translator's note: naming is divided into different namespaces), of course, the class also provides (can be nested) nameaxis (Translator's note: divides names into different classes ).
For example, the global scopes of two different projects have a class Foo, which causes conflicts during compilation or running. If each project places the code in a different namespace, project1: Foo and project2: Foo will not conflict with each other as different symbols.
Disadvantage: namespaces are confusing because they provide additional (nested) Naming axes like classes. Using an unspecified space in the header file is easy to violate the unique definition principle of C ++ (one
Definition rule (ODR )).
Conclusion: The namespace can be reasonably used according to the policy described below.
1)
Unnamed
Namespaces)
In the. CC file, you can or even advocate using an anonymous namespace to avoid name conflicts during the runtime:
Namespace
{//. CC File
// The namespace content does not need to be indented
Enum {
Unused, eof, error}; // frequently used symbol
Bool ateof () {return POS _ = EOF;
} // Use the EOF symbol in this namespace
} // Namespace
However, the file scope declaration associated with a specific class is declared as a type, static data member, or static member function in this class, rather than an anonymous namespace member. As shown in the preceding figure, the namespace is ended with a comment //
Namespace ID.
You cannot use an anonymous namespace in A. H file.
2) namespace (named
Namespaces)
The namespace can be used as follows:
The namespace encapsulates all the source files except file inclusion, global identity Declaration/definition, and class pre-declaration to distinguish them from other namespaces.
//
. H file
Namespace mynamespace {
// All declarations are placed in the namespace
// Do not use indentation
Class
Myclass {
Public:
...
Void Foo ();
};
} // Namespace
Mynamespace
//. CC File
Namespace mynamespace {
//
All function definitions are placed in namespaces.
Void myclass: Foo (){
...
}
} // Namespace
Mynamespace
Common. CC files contain more and more complex details, including references to classes in other namespaces.
# Include "A. H"
Define_bool (someflag, false, "dummy flag ");
Class C ;//
Predeclaration of class C in the global namespace
Namespace A {Class A;} // predeclaration of Class A: A in namespace
Namespace B {
... Code for B... // code in B
} // Namespace
B
Do not declare anything under the namespace STD, including the pre-declaration of the standard library class. Declaring the entity under STD will lead to ambiguous behaviors, for example, cannot be transplanted. Declare the entity under the standard library and contain the corresponding header file.
It is best not to use the using indicator to ensure that all names in the namespace can be used normally.
//
Prohibit-contaminated namespace
Using namespace
Foo;
You can use using in functions, methods, or classes of. CC files and. H files.
// Allow: In the. CC File
//
. H files must be used inside functions, methods, or classes.
Using
: FOO: bar;
In the. CC file and. h file functions, methods, or classes, you can also use namespace aliases.
// Allow: In the. CC File
//
. H files must be used inside functions, methods, or classes.
Namespace fbz =
: FOO: bar: Baz;
2. nested class (nested
Class)
When exposing Nested classes as part of interfaces, although they can be directly stored in the global scope, it is better to place the declaration of Nested classes in the namespace.
Definition: You can define another class in one class. A nested class is also called a member class (member ).
Class ).
Class Foo {
PRIVATE:
// Bar is a member class nested in Foo.
Class
Bar {
...
};
};
Advantage: When a nested (member) class is only
Class) is useful when used. placing it in the scope of the nested class as a member of the nested class will not pollute other classes with the same name in the scope. You can declare a nested class in the nested class. define Nested classes in the CC file to avoid including the definition of Nested classes in the nested classes, because the definition of Nested classes is usually only related to the implementation.
Disadvantage: The nested class can be pre-declared only in the definition of the nested class. Therefore, any header file that uses the foo: bar * pointer must contain the entire Foo declaration.
Conclusion: do not define Nested classes as public unless they are part of an interface. For example, a method uses a series of options for this class.
3.
Nonmember, static member, and global functions)
Use non-member or static member functions in a namespace. Do not use global functions whenever possible.
Advantage: in some cases, non-member functions and static member functions are very useful. placing non-member functions in a namespace can avoid global scope pollution.
Disadvantage: it may be more meaningful to use non-member and static member functions as members of the new class, especially when they need to access external resources or have important dependencies.
Conclusion:
Sometimes it is helpful not to limit a function to the entity of the class, or even to do so, either as a static member or as a non-member function. Non-member functions should not depend on external variables and should be placed in a namespace as much as possible. It is better to use a namespace than to create a class simply to encapsulate a number of static member functions that do not share any static data.
Functions defined in the same compilation unit may introduce unnecessary coupling and connection dependencies when called directly by other compilation units. static member functions are especially sensitive to this. You can consider extracting the function to a new class or placing the function in the namespace of an independent library.
If you really need to define a non-member function and only use it in the. CC file, you can use an unnamed namespace or static Association (such as static int Foo ()
{...}) Limits its scope.
4. Local Variables)
Place function variables in the smallest possible scope and initialize them when declaring variables.
C ++ allows variables to be declared anywhere in the function. We advocate declaring variables in the smallest possible scope. The closer we are to the first use, the better. This makes the code easy to read and easily locates the declared position, type, and initial value of the variable. In particular, initialization should be used instead of Declaration + assignment.
Int
I;
I = f (); // bad -- initialization and declaration Separation
Int J = g ();//
OK -- declare during initialization
Note: GCC can correctly execute for (INT I = 0; I <10;
++ I) (I only applies to for loops), so I can be reused in other for loops. If and while statements, scope Declaration (Scope
Declaration) is also true.
While (const char * P = strchr (STR, '/') STR = P +
1;
Note: If a variable is an object, its constructor must be called every time it enters the scope, and its destructor must be called every time it exits the scope.
// Inefficient implementation
For
(INT I = 0; I <1000000; ++ I ){
Foo F ;//
Constructor and destructor call 1000000 times respectively!
F. dosomething (I );
}
It is much more efficient to put variables out of the circular scope:
Foo
F; // constructor and destructor are called only once.
For (INT I = 0; I <1000000; ++ I)
{
F. dosomething (I );
}
5. global variables (Global
Variables)
Global variables of the class type are forbidden, and built-in global variables are allowed. Of course, non-constant global variables in multi-threaded Code are also forbidden. Never use function return values to initialize global variables.
Unfortunately, the calling sequence of the constructor, destructor, and initialization operations of global variables is only partially specified. Each generation may change, resulting in hard-to-find buckets.
Therefore, global variables of the class type (including STL string,
Vector and so on), because their initialization sequence may cause structural problems. Built-in types and struct composed of built-in types without constructors can be used. If you must use global variables of the class type, use Singleton
Pattern ).
For global string constants, use a C-style string instead of an STL string:
Const char
Kfrogsays [] =
"Ribbet ";
Although global variables can be used in the global scope, you must think twice. Most global variables should be static data members of the class, or. when used in the CC file, it is defined in an unnamed namespace, or the static Association is used to restrict the scope of the variable.
Remember, static member variables are regarded as global variables, so they cannot be of the class type!
______________________________________
Translator: This article mainly mentions some of the scope rules, which are summarized as follows:
1.
The namespace in. CC can avoid naming conflicts and limited scopes, and avoid directly using the using prompt to pollute the namespace;
2.
The nested class complies with the local usage principle, but it cannot be pre-declared in other header files. Try not to use public;
3.
Try not to use global functions and global variables, consider the scope and namespace restrictions, and try to form a separate compilation unit;
4.
Do not use the class type (including STL containers) for global variables (including static member variables) in multithreading to avoid bugs caused by ambiguous behaviors.
In addition to name contamination and readability, the scope is mainly used to reduce coupling and improve compilation and execution efficiency.Google C ++ programming style guide (III): c ++ class
Class
Class is a basic unit of code in C ++ and is naturally widely used. This section lists what to do and what not to do when writing a class.
1.
Constructor's Responsibilities
The constructor only performs those that have no practical significance (trivial). Note: simple initialization has no practical logic significance for program execution, because most of the "meaningful" values of the member variables are not determined in the constructor) initialization. If possible, use the init () method to initialize the non-trivial data in a centralized manner.
Definition: Perform initialization in the constructor.
Advantage: convenient layout, no need to worry about class initialization.
Constructor:
1)
It is not easy to report errors in constructors and cannot be used.
2) An operation failure may result in an object initialization failure and an uncertain state.
3)
When a constructor calls a virtual function, the call is not distributed to the subclass implementation. Even if there is no subclass implementation, it will remain a hidden danger in the future.
4)
If someone creates a global variable of this type (although it violates the rules mentioned above), the constructor will be called before Main, it may damage the assumptions implied in the constructor. For example, gflags has not been initialized.
Conclusion: if the object requires meaningful (non-trivial) initialization, consider using another Init () method and (or) adding a member tag to indicate whether the object has been initialized successfully.
2.
Default constructor
Constructors)
If a class defines several member variables and no other constructor, You need to define a default constructor. Otherwise, the compiler will automatically generate the default constructor.
Definition: when a new object without parameters is created, the default constructor is called. When new [] (array) is called, the default constructor is always called.
Advantage: by default, the struct is initialized to an "impossible" value, making debugging easier.
Disadvantage: it is unnecessary for code writers.
Conclusion:
If a member variable is defined in the class and no other constructor is provided, You need to define a default constructor (No parameter ). The default constructor is more suitable for initializing objects so that the object's internal state (internal
State) is consistent and valid.
The default constructor is provided because: if you do not provide other constructor and do not define the default constructor, the compiler will automatically generate one for you, the constructor generated by the compiler does not initialize the object.
If the class you define inherits the existing class without adding new member variables, you do not need to define the default constructor for the new class.
3.
Explicit Constructor
Constructors)
Use the C ++ keyword to explain a single parameter constructor.
Definition: Generally, only one constructor can be used for conversion (conversion). Note: It mainly refers to implicit conversion, which can be seen below). For example, foo: Foo (string
Name). When you pass in a string to a function that needs to pass in a foo object, the constructor FOO: Foo (string
Name) is called and the string is converted into a foo temporary object to be passed to the call function. It looks very convenient, but if you don't want to generate a new object through conversion, the trouble will also come. To avoid implicit conversions caused by constructors, you can declare them as explicit.
Advantage: Avoid out-of-date changes.
Disadvantage: none.
Conclusion:
All single-parameter constructors must be clear. In the class definition, add the keyword explicit before the single-parameter constructor: explicit Foo (string name );
Exception: in rare cases, the copy constructor can not be declared as explicit; It is specially used as a class of transparent wrapper for other classes. Similar exceptions should be explicitly stated in the notes.
4. copy constructor (copy
Constructors)
Use the copy constructor only when you need to copy a class object in the Code. Use disallow_copy_and_assign if you do not need to copy the class object.
Definition: When copying a new object, you can use the copy constructor (especially when the object is passed in ).
Advantage: The copy constructor makes it easier to copy objects. The STL container requires that all content can be copied and assigned values.
Disadvantages: Implicit copying of objects in C ++ is the root cause of many performance problems and bugs. The copy constructor reduces the readability of the Code. Compared with passing by reference, it is more difficult to track objects passing by value, and the modification of objects becomes unpredictable.
Conclusion:
A large number of classes do not need to be copyable, nor need a copy constructor or value assignment operation (assignment
Operator ). Unfortunately, if you do not manually declare them, the compiler will automatically generate them for you and make them public.
You can consider adding an empty (dummy) copy constructor and assign values to the private class. Only declarations are required and are not defined. Since these empty programs are declared as private, the compiler reports an error when other code tries to use them. For convenience, you can use the macro disallow_copy_and_assign:
//
Prohibit the use of macros for copying constructors and assigning values.
// Should be used in private: of the class
# Define
Disallow_copy_and_assign (typename )/
Typename (const typename &);
/
Void operator = (const typename &)
Class foo
{
Public:
Foo (int f );
~ Foo ();
PRIVATE:
Disallow_copy_and_assign (FOO );
};
As mentioned above, disallow_copy_and_assign should be used in most cases. If the class does need to be copyable, the reason should be stated in the Class header file, and the copy constructor and value assignment operations should be properly defined, note that self-assignment is detected in operator =.
When you think of classes as STL containers, you may have the urge to make the classes copyable. In a similar case, the actual thing to do is to use pointers to objects in the STL container. You can consider using STD: tr1: shared_ptr.
5.
Struct and class (structs.
Classes)
Use struct only when there is only data, and use class for others.
In C ++, the keywords struct and class have almost the same meaning. We add semantics to them so that we can reasonably choose which keyword to use for the defined data type.
Struct is used in passive
Objects) may include associated constants, but it does not have function functions other than data members. The access function is implemented through direct access without calling the method, the method mentioned here is only used to process data members, such as constructors, destructor, initialize (), reset (), and validate ().
If more function functions are required, the class is more suitable. If you are not sure, use the class directly.
If combined with STL, you can use struct instead of class for functions and features.
Note: The member variables of classes and struct use different naming rules.
6.
Inheritance)
The use of Composition
In patterns, it is often more suitable than inheritance. If inheritance is used, only public inheritance is used.
Definition: When a subclass inherits the base class, it contains the definition of all data and operations of the parent base class. In C ++ practice, inheritance is mainly used in two scenarios: implementation
Inheritance), subclass inherits the implementation code of the parent class; interface inheritance
Inheritance), subclass only inherits the method name of the parent class.
Advantage: inheritance reduces the amount of code by reusing the base class code. Because the inheritance is a compile-time Statement (compile-time)
Declaration), the coders and compilers can understand the corresponding operations and find errors. Interface inheritance can be used to enhance the function of a specific API of the class in the program. When the class does not define the necessary implementation of the API, the compiler can also detect errors.
Disadvantage: for implementation inheritance, it is more difficult to understand its implementation because the code of the implementation subclass extends between the parent class and the Child class. Sub-classes cannot override non-virtual functions of the parent class, and of course they cannot be modified. The base class may also define some data members and distinguish the physical outlines of the base class (physical
Layout ).
Conclusion:
All inheritance must be public. If you want to perform private inheritance, you should replace it with a base-class instance as a member.
Do not use implementation inheritance too much. combinations are usually more appropriate. Try to use inheritance only when "is a" ("is-a", the Translator's note, and other "has-a" cases, use a combination: if bar is indeed "a Type" Foo, bar is a subclass of foo.
If necessary, make the Destructor Virtual. If the class has virtual functions, the Destructor should be virtual functions.
Note: In special circumstances where the child class does not have any additional data members or even the parent class does not have any data members, is it necessary to call the Destructor as a semantic argument, from the perspective of programming design specifications, it is absolutely necessary to define virtual destructor in the parent class containing virtual functions.
The member function accessed only in the subclass is protected. Note that the data member should always be private.
When you redefine a derived virtual function, it is explicitly declared as virtual in the derived class. Root Cause: If the virtual function is omitted, the reader needs to retrieve all the ancestors of the class to determine whether the function is a virtual function (the Translator's note, although it does not affect its nature ).
7. Multiple inheritance
Inheritance)
Multiple implementation
Inheritance). Multiple inheritance is used only when one base class contains at most implementations and other base classes are pure interface classes suffixed with interfaces.
Definition: Multi-inheritance allows sub-classes to have multiple base classes, which must be different from the base classes with implementations as pure interfaces.
Advantage: compared to single inheritance, multi-implementation inheritance allows you to reuse more code.
Disadvantages: there are very few times when multi-implementation inheritance is really needed. Multi-implementation inheritance seems to be a good solution. Generally, you can find a more clear and different solution.
Conclusion: multiple inheritance can be used only when all superclasses except the first one are pure interfaces. To ensure they are pure interfaces, these classes must be suffixed with interfaces.
Note: For this rule, there is an exception in Windows (note, as described in the rule exception in the last article of this translation ).
8.
Interface)
An interface is a class that meets certain conditions. These classes are suffixed with interfaces (not required ).
Definition: When a class meets the following requirements, it is called a pure interface:
1)
Only pure virtual functions ("= 0") and static functions (except the Destructor mentioned below );
2) No non-static data member;
3)
No constructor is defined. If yes, it does not include the parameter and is protected;
4)
If it is a subclass, it can only inherit classes that meet the preceding conditions and are suffixed with interfaces.
The interface class cannot be directly instantiated because it declares pure virtual functions. To ensure that all implementations of the interface class can be correctly destroyed, virtual destructor must be declared for it (except for the 1st rules, the Destructor cannot be pure virtual functions ). For more information, see
C ++ programming language, 3rd
Section 12.4 of edition.
Advantage: using an interface as the suffix can make others know that they cannot add implementation functions or non-static data members to the interface class. This is especially important for multi-inheritance. In addition, for Java programmers, the concept of interfaces has been deeply rooted in the hearts of the people.
Disadvantage: The Class Name Length is added to the interface suffix, which makes reading and understanding inconvenient. At the same time, the interface features should not be exposed to the customer as implementation details.
Conclusion :. Classes end with interfaces only when the preceding requirements are met. However, classes that meet the preceding requirements may not end with interfaces.
9.
Operator
Overloading)
Except for a few specific environments, Do not overload operators.
Definition: A class can define operators such as + and/so that they can be used directly like built-in types.
Advantage: Make the Code look more intuitive. Just like the built-in type (such as INT), the overload operator makes the equals (), add () and other quiet function names much more fun. To make some template functions work correctly, you may need to define operators.
Disadvantage: although Operator Overloading makes the code more intuitive, there are also some shortcomings
1)
Obfuscation intuition makes you mistakenly think that some time-consuming operations are as lightweight as built-in operations;
2)
It is more difficult to find the call location of the overload operator. It is much easier to find equals () than to call equal =;
3) Some operators can operate on pointers, which may easily lead to bugs, foo +
4. One thing is done, while & Foo + 4 may be done in a completely different way. For both, the compiler will not report errors, making it difficult to debug;
4)
Overload also has side effects that surprise you. For example, the overload operator and class cannot be pre-declared.
Conclusion:
Generally, Do not overload operators, especially assignment operations (operator =). avoid overloading. If necessary, you can define functions such as equals () and copyfrom.
However, in rare cases, You Need To overload operators to connect to templates or "standard" C ++ classes (such as operator <(ostream &,
Const
T &). If it turns out to be justified, it is acceptable, but you should avoid doing so as much as possible. In particular, do not just use operator = or operator as the key in the STL container. Instead, when declaring the container, create a similar function type for equal judgment and size comparison.
Some STLAlgorithmYou do need to reload operator = to do this. Do not forget to provide documentation to explain the cause.
Refer to copy constructors and function overloading.
10. Access Control
Control)
Privatize data members and provide related access functions, such as defining the variables Foo _, value functions Foo (), and value assignment functions set_foo ().
The definition of the access function is usually inline in the header file.
Refer to inheritance and function naming.
11.
Declaration Order (Declaration
Order)
Use a specific declaration order in the class: public: Before PRIVATE:, the member function is before the data member (variable.
The definition order is as follows: public:, protected:, private:. If there is no such item, ignore it.
In each piece, the Declaration Order is generally as follows:
1)
Typedefs and enums;
2) constants;
3) constructor;
4) destructor;
5)
Member functions, including static member functions;
6)
Data member, including static data member.
Macro disallow_copy_and_assign is placed after the private: block and serves as the last part of the class. Refer to copy constructor.
The function definition in the. CC file should be consistent with the declaration order as much as possible.
Do not inline large functions into the class definition. Generally, only functions that have no special significance or have high performance requirements and are short functions are defined as inline functions. For more details, refer to the inline function in the first article of the translation.
12.
Write short
Functions)
Tend to select short and concise functions.
Long functions are sometimes appropriate, so there is no strict limit on the function length. If the number of functions exceeds 40, you can split the functions without affecting the program structure.
Even if a long function is currently working very well, once modified, new problems may occur, or even difficult to find the bugs. Make the function as short and simple as possible, so that others can read and modify the code.
When processing code, you may find complex long functions. Do not be afraid to modify the existing code. If you confirm that the code is difficult to use or debug, or you need to use a small part of the code, consider dividing it into several shorter and easier-to-manage functions.
______________________________________
Note:
1. Do not perform too many logic-related initialization in the constructor;
2.
The default constructor provided by the compiler does not initialize the variables. If other constructor is defined, the compiler does not provide the default constructor. You must provide the default constructor by yourself;
3.
To avoid implicit conversion, you must declare the single-parameter constructor as explicit;
4.
To avoid misuse of the copy constructor and value assignment operations and automatic generation by the compiler, you can declare it private without implementation;
5. Use struct only when used as a dataset;
6. Combination> implement inheritance> interface inheritance> private inheritance. Virtual keywords must be declared for virtual functions that are overloaded by subclasses, although the compiler does not allow this;
7. Avoid using multi-inheritance. in use, except a base class that contains implementations, other base classes are pure interfaces;
8.
The Interface Class Name Is suffixed with "interface". Except virtual destructor and static member functions with implementations, all others are pure virtual functions and do not define non-static data members, no constructor is provided. If it is provided, it is declared as protected;
9. To reduce complexity and avoid overloading operators as much as possible, documents are provided for use in templates and standard classes;
10. The access function is usually inline in the header file;
11. Declaration Order: Public-> protected-> private;
12.
The function body should be as short and compact as possible, with a single function.