Here are the notes I made after reading the 6th edition of C + + Primer Plus, as a memo to facilitate review later.
Why is C + + const better than C # # #?
First, it can explicitly specify a type and have type checking capabilities.
Second, you can restrict a definition to a specific function or file by using a scope rule for C + +.
Third, you can use the const for more complex types, such as arrays and structs.
The C language also has a const, which differs from the const in C + +: First, the scope rules are different, and the other is that in C + + you can declare the length of the array with a const value.
You cannot simply assign an integer to a pointer, as follows:
int *ptr;ptr = 0xB8000000; // type mismatch
Here, on the left is a pointer to int, so you can assign it to an address, but to the right is an integer. As you may know, 0xb8000000 is the combined segment offset address of video memory in an old computer system, but this statement does not tell the program that this number is an address. The C language allows this assignment before the C99 standard is released. But C + + is more stringent in terms of type consistency, and the compiler displays an error message with a mismatch in the advertisement type. To use a numeric value as an address, you should convert the number to the appropriate address type by forcing the type conversion:
int *ptr;ptr = (int *) 0xB8000000; // type now match
This way, both sides of the assignment statement are the addresses of integers, so the assignment is valid.
Note that PT is the address of an int value and does not mean that the PT itself is of type int. For example, in some platforms, the int type is a 2-byte value, and the address is a 4-byte value.
-
In summary, there is no difference in which format is used for built-in types, but for user-defined types, the prefix format is more efficient if you have user-defined increment and decrement operators.
Comma operator
So far, the most common use of the comma operator is to put two or more expressions in a For loop expression. The following are the attributes of the comma operator:
- It ensures that the first expression is evaluated first, and then the second expression is evaluated;
i = +, j = 2 * i; I set to and then J set to 40
- The value of the comma expression is the value of the second part. For example, the value of the above expression is 40.
- In all operators, the precedence of the comma operator is the lowest. For example:
Cats = 17, 240;
Be explained to me:
(cats = 17), 240;
That is, the cats is set to 17, and the subsequent 240 does not work. If it is cats = (17, 240), then cats is 240.
Useful Character Library Cctype
Inherited from the C language, the old format is ctype.h, commonly used are:
Middle value selection in the Quick row:
Each group of 5 elements is taken as a median. The median value is found in the N/5 value, as the pivot of the partition.
Why * Not every 3 groups? Ensure that the left right side of the pivot is at least 3N/10 elements, so the worst O (n).
-
Automatic Storage Persistence : The storage continuity of variables declared in a function definition (including function parameters) is automatic. They are created when the program starts executing functions or blocks of code that it belongs to, and the memory that they use is freed when the function or block of code is executed. C + + has two variables for which storage persistence is automatic.
static storage persistence : Variables defined outside the function definition and stored persistence for variables defined with the keyword static are statically. They are present throughout the process of the program's operation. C + + has 3 variables for which storage persistence is static.
Thread Storage Persistence (C++11) : Currently, multicore processors are common, and these CPUs can handle multiple execution tasks at the same time. This allows the program to place computations in different threads that can be processed in parallel. If a variable is declared with the keyword thread_local, its life cycle is as long as the thread it belongs to. This book does not discuss parallel programming.
Dynamic Storage Persistence : Memory allocated with the new operator will persist until it is disposed with the delete operator or until the program ends. This memory is dynamically stored and is sometimes called a free store or heap.
Write your own string considerations:
- About recording an existing number of objects Object_count
Do not initialize a static member variable in a class declaration (that is, a header file) because the declaration describes how to allocate memory, but does not allocate memory. For static class members, you can use separate statements for initialization outside of the class declaration, because static class members are stored separately, not part of an object. Note that the initialization statement indicates the type int (which is indispensable) and uses the scope operator, but does not use the keyword static.
Initialization is done in the method file, not in the class declaration file, because the class declaration is in the header file and may be included multiple times so that if static members are initialized in the header file, multiple initialization statement copies will occur, causing an error.
An exception to the fact that a static member cannot be initialized in a class declaration is that the static data member is an integer or enum-type Const. That is, if the static data member is an integer or enum type, it can be initialized in the class declaration.
- Note The rewrite copy constructor and assignment operator, where the prototype of the assignment operator is:
Class_name & class_name::operator= (const class_name &);
It accepts and returns a reference to the class object, which is intended to be useful in tandem.
When to invoke copy (copy) constructors:
StringBad ditto (motto); StringBad metoo = motto; StringBad also = StringBad(motto); StringBad * pStringBad = new StringBad (motto);
The above 4 methods are called: Stringbad (const Stringbad &)
- The intermediate two declarations may use the copy constructor to create MeToo and also objects directly, or you might use a copy constructor to generate a temporary object, and then assign the contents of the temporary object to MeToo and also, depending on the implementation. The last declaration initializes an anonymous object with motto and assigns the address of the new object to the Pstringbad pointer.
- The compiler uses the copy constructor whenever the program generates a copy of the object. Specifically, the copy constructor is used when the function returns an object by value. Remember, passing by value means creating a copy of the original variable.
- The copy constructor is also used when the compiler generates a temporary object. For example, when you add 3 vector objects, the compiler may generate a temporary vector object to hold the intermediate results.
- In addition, string sailor = sports; equivalent to String sailor = (string) sports; So the copy constructor is called
When to invoke the assignment operator:
Like the copy constructor, the implicit implementation of the assignment operator also replicates the members individually. If the member itself is a class object, the program copies the member using the assignment operator defined for the class, but the static data member is not affected.
The difference between the assignment operator and the copy constructor is implemented:
- Because the target object might reference the previously allocated data, the function should use delete[] to release the data.
- The function should avoid assigning the object to itself, otherwise releasing the memory operation may delete the object's contents before the object is re-assigned.
- The function returns a reference to the calling object (which is convenient for concatenation), and the copy constructor does not return a value.
The following code shows how to write an assignment operator for the Stringbad class:
stringbad & stringbad::operator= (const Stringbad & st) {if (this = = & st) return * this; delete [] str; len = St.len; str = new Char [len + 1]; strcpy (STR,ST.STR); return *this;}
The code first checks for self-replication, which is done by looking at whether the address on the right of the assignment operator (&s) is the same as the address of the receiving object (this), and if the same, the program returns *this and ends.
If it is different, the memory that Str points to is freed, because the address of a new string will be assigned to STR later. If you do not first use the delete operator, the above string will remain in memory. Because the program no longer contains pointers to strings, the memory is wasted at one time.
The next action is similar to the copy constructor, which is to allocate enough memory space for the new string and then copy the string.
The assignment operation does not create a new object, so you do not need to adjust the value of the static data member Num_strings.
Overloaded operators are best declared as friends
For example, comparing a function as a friend helps to compare a string object to a regular C string. For example, suppose answer is a string object, the following code:
if ("love" = = Answer)
will be converted to:
if (operator = = ("Love", Answer))
The compiler will then use a constructor to convert the code to:
if (operator = = (String ("Love"), answer))
This is compatible with the prototype.
Note When you use brackets to access characters when overriding the String class:
(1) Why is the overloaded [] return value a char & instead of char?
(2) Why are there two overloaded [] versions and the other is the const version?
Answer (1):
The return class is declared as Char &, and a value can be discovered computers to a particular element. For example, you could write code like this:
String means ("might");
means [9] = ' R ';
The second statement is converted to an overloaded operator function call:
Means.operator[][0] = ' R ';
Here the R discovered computers to the return value of the method, and the function returns a reference to Means.str[0], so the above code is equivalent to the following code:
Means.str[0] = ' R ';
The last line of code accesses private data, but because operator is a method of the class, it is able to modify the contents of the array. The end result was that "might" was changed to "right".
Answer (2):
Suppose you have the following constant object:
Const String Answer ("futile");
If only the above operator definitions are available, the following code will make an error:
cout << answer[1]; Compile-time Error
The reason is that answer is a constant, and the above method cannot ensure that the data is not modified (in fact, sometimes the work of the method is to modify the data, so you cannot ensure that the data is not modified).
In the case of overloading, however, C + + distinguishes between constants and the signature of a very scalar function, so that it can provide another version of operator that is used only by the Const string object:
For use with const String objects
const char & string::operator Const {
return str[i];
}
With the above definitions, you can read/write regular string objects: and for const siring objects, only their data is read.
Static member functions can no longer add the static keyword when defining implementations outside of a class declaration, as with static member variables.
Two ways to implement has-a relationships:
- The combination (or inclusion) method. This is the method we usually use.
C + + has another way to implement has-a relationships-private inheritance. With private inheritance, the public and protected members of the base class are referred to as private members of the derived class. This means that the base class methods will not be referred to as part of the derived object public interface, but can be used in the member functions of the derived class. With public inheritance, the public method of the base class is called the public method of the derived class. In short, the derived class inherits the interface of the base class: This is part of the is-a relationship. With private inheritance, the public method of the base class is called the private method of the derived class, that is, the derived class does not inherit the interface of the base class. As seen from the contained object, this partial inheritance is part of the has-a relationship.
With private inheritance, the class inherits the implementation. For example, if you derive the student class from the String class, the latter will have a string class component that you can use to hold the string. In addition, the student method can use the String method class to access the string component.
Contains the addition of an object to a class as a named member object, and private inheritance adds the object to the class as an unnamed inherited object. We use the term sub-object to represent the same inheritance or inclusion of the added object.
As a result, private inheritance provides the same attributes as inclusions: Get implementations, but do not get interfaces. Therefore, private inheritance can also be used to implement has-a relationships .
Use the include or use private inheritance?
Since you can use both inclusion and private inheritance to establish a has-a relationship, which way should you use it? most C + + programmers tend to use inclusions.
- First, it's easy to understand. A class declaration contains an explicit named Object that represents the contained class, and the code can refer to those objects by name, and using inheritance will make the relationship more abstract.
- Second, inheritance can cause many problems, especially when inheriting from multiple base classes, which may have to deal with many problems, such as the independent base class of a separate base class or communist ancestor that contains a method of the same name.
In short, using inclusion is less likely to encounter such trouble.
- In addition, inclusions can include multiple homogeneous sub-objects. If a class requires 3 string objects, you can use a string member that contains declaration 3 independent. Inheritance can only use one such object (which is difficult to distinguish when the object has no name).
However, private inheritance does provide more features than is included. For example, if a class contains a protected member (which can be a data member or a member function), such a member is available in the derived class, but not outside of the inheritance hierarchy. If you use a combination to include such a class in another class, the latter is not a derived class, but is located outside the inheritance hierarchy and therefore cannot access the protected member. However, by inheriting it will be a derived class, so it has access to the protected member.
Another case where private inheritance is required is the need to redefine the virtual function. A derived class can redefine a virtual function, but the containing class cannot. With private inheritance, the redefined function will be used only in the class, not the public.
- In general, you should use inclusions to establish has-a relationships, or you should use private inheritance if the new class needs to access the protected members of the original class, or if you need to redefine the virtual function.
About Protection inheritance
Protection inheritance is a variant of private inheritance, and protection inheritance uses the keyword protected when listing base classes;
class Student : protected std::string, protected std::valarray<double>{...}
When you use protection inheritance, the public and protected members of the base class become protected members of the derived class, and as with private inheritance, the interface of the base class is also available in the derived class, but outside of the inheritance hierarchy is unavailable. When you derive another class from a derived class, private inheritance and protection inheritance
The main difference between them is presented. With private inheritance, the third generation will not be able to use the interface of the base class, because the common method of the base class becomes private in the derived class, and when protected inheritance is used, the public methods of the base class are programmed in the second generation to be protected, so that the third generation of derived classes can use them.
The following table summarizes public, private, and protected inheritance. Implicit up-conversion means that you can point a base-class pointer or reference to a derived class object without explicit type conversions.
Smart pointer Correlation
Please refer to: simple analysis of C + + smart pointers, recommended must see.
- Types of containers in C + +:
- Sequence container (7)
- Associative containers
- 4 ordered associative containers: Set, Multiset, map, and Multimap, based on the tree structure of the underlying
- C++11 added 4 more unordered associative containers: unordered_set, Unordered_multiset, Unordered_map, and Unordered_multimap, and the bottom based on hash.