C ++ collection (5)-class, Collection
Class is the most important feature in C ++. Early versions of the C ++ language were named "C (Cwith Classes)" to emphasize the central role of the class mechanism. With the evolution of languages, supporting classes are also increasing. The main goal of language design is to provide features that allow programs to define their own types, which are as easy and intuitive to use as built-in types.
Class Definition and Declaration
- The basic idea behind classes is:Data abstractionAndEncapsulation.
- Data abstraction is a programming (and Design) technique that relies on interface and implementation separation. Class designers must care about how classes are implemented, but programmers who use these classes do not have to understand these details. On the contrary, programmers who use a type only need to understand the type interface. They can abstract and consider what the type does, instead of how the type works.
- Encapsulation is a combination of low-level elements to form a new, high-level entity beads technology. A function is a form of encapsulation: The detailed behavior executed by a function is encapsulated in the larger entity of the function itself. Encapsulated elements hide their implementation details-you can call a function but cannot access the statements it executes. Similarly, a class is an encapsulated entity: it represents the focus of several Members, and most (well-designed) class types hide the members that implement this type.
- Vector of the standard library type has the characteristics of data abstraction and encapsulation. In terms of usage, It is abstract. You only need to consider its interfaces, that is, the operations it can perform. It is encapsulated because we cannot understand how the type is represented or access any of its implementations. On the other hand, arrays are conceptually similar to vectors, but they are neither abstract nor encapsulated. You can directly manipulate the array by accessing the memory that stores the array.
- Not all types must be abstract. The pair class in the standard library is a practical and well-designed concrete class rather than an abstract class. A specific class exposes rather than hiding its implementation details. Some classes, such as pair, do not have abstract interfaces. The pair type only binds two data members into a single object. In this case, hiding data members is unnecessary and has no obvious benefits. Hiding data members in a class like pair can only complicate the use of data types.
- Data abstraction and encapsulation provide two important advantages: 1. Avoid unintentional user-level errors that may damage the object state in the class. 2. Over time, perfect class implementation can be implemented based on demand changes or defect (bug) reports without changing user-level code.
Implicit this pointer
- A member function has an additional implicit parameter, that is, a pointer to the class object. This implicit parameter is named this and bound to the object that calls the member function. A member function cannot define this parameter, but is implicitly defined by the compiler. The function body of the member function can use the this pointer explicitly, but this is not required. If there is no limit on the reference of class members, the compiler will process this reference as a reference through the this pointer.
- Although explicit reference to this in a member function is usually unnecessary, this is required in one case: when we need to reference an object as a whole instead of referencing a member of the object. The most common case is to use this in a function: this function returns a reference to the object that calls the function.
- In a common non-const member function, the type of this is a const pointer pointing to the class type. You can change the value pointed to by this, but cannot change the address saved by this. In a const member function, this is a const pointer to a const class object. You cannot change the object that this points to or the address that this stores. Note that normal references to class objects cannot be returned from the const member function. The const member function can only return * this as a const reference ..
- Sometimes, we want the data member of the class (even in the const member function) to be able to be modified. This can be achieved by declaring them as mutable. Mutable data member cannot be a const, even if it is a member of a const object. Therefore, the const member function can change the mutable member. To declare a data member as mutable, you must put the keyword mutable before the member declaration.
Constructor
- Constructor is a special member function. If you create a new object of the class type, you must execute the constructor. The function of constructor is to ensure that each object's data member has an appropriate initial value. The constructor name is the same as the class name, and the return type cannot be specified. Like any other function, they can have no parameters or define multiple parameters. The constructor can be overloaded. The real parameter determines which constructor to use. Automatically execute the constructor.
- Const cannot be declared as const. When a const object of the class type is created, a common const is run to initialize the const object. A constructor initializes an object. Whether the object is const or not, a constructor is used to initialize the object.
- The constructor initialization list starts with a colon, followed by a list of data members separated by commas (,). Each data member is followed by an initialization formula in parentheses. Like any member function, constructor can be defined inside or outside the class. The initialization of the constructor is only specified in the definition of the constructor, rather than in the Declaration.
- If no initialization type is provided for class members, the compiler implicitly uses the default constructor of the member type. If the class does not have a default constructor, the compiler will fail to use the default constructor. In this case, Initialization is required to initialize data members. Some members must be initialized in the constructor initialization list. For such members, assigning values to them in the constructor body does not work. The class members without the default constructor, And the const or reference type members must be initialized in the constructor initialization list.
- The default constructor is used as long as the initialization type is not provided when an object is defined. The constructor that provides default real parameters for all parameters also defines the default constructor. Even if only one constructor is defined for a class, the compiler will not generate a default constructor. This rule is based on the fact that if a class needs to control object initialization under certain circumstances, the class may need to be controlled under all circumstances. The compiler automatically generates a default constructor only when no constructor is defined for a class. Built-in and composite Members, such as pointers and arrays, are initialized only for objects defined in the global scope. When an object is defined in a local scope, built-in or composite Members are not initialized. If a class contains members of the built-in or composite type, the class should not depend on the default constructor of the synthesis. It should define its own constructor to initialize these members.
Static class member
- Unlike common data members, static data members exist independently of any objects of the class. Each static data member is an object associated with the class and is not associated with the objects of the class. Just as a class can define shared static data members, a class can also define static member functions. The static member function does not have this parameter. It can directly access the static member of the class, but cannot directly use non-static members.
- Using static members instead of Global Objects has three advantages. 1. The static member name is in the scope of the class, so it can avoid conflicts with other class members or global object names. 2. encapsulation can be implemented. Static members can be private members, but global objects cannot. 3. The reading program shows that static members are associated with specific classes. This visibility clearly shows the programmer's intent.
One instance
To improve your understanding of the above text, we provide an example from exercise 12.13 in C ++ Primer: extend the Screen class to include the move, set, and display operations. Test the class by executing the following expressions:
// Move the cursor to the specified position, set characters, and display the Screen Content
MyScreen. move (4,0). set ('#'). display (cout );
The answer is as follows:
1 # include <iostream> 2 # include <string> 3 4 using namespace std; 5 6 class Screen {7 public: 8 typedef string: size_type index; 9 char get () const {return contents [cursor];} 10 inline char get (index ht, index wd) const; 11 index get_cursor () const; 12 Screen (index hght, index wdth, const string & cntnts); 13 14 // Add three member functions 15 Screen & move (index r, index c); 16 Screen & set (char ); 17 Screen & display (ostream & OS); 18 19 private: 20 std: string contents; 21 index cursor; 22 index height, width; 23}; 24 25 Screen :: screen (index hght, index wdth, const string & cntnts): 26 contents (cntnts), cursor (0), height (hght), width (wdth) {} 27 28 char Screen: get (index r, index c) const 29 {30 index row = r * width; 31 return contents [row + c]; 32} 33 34 inline Screen: index Screen: get_cursor () const 35 {36 return cursor; 37} 38 39 // added definition of the three member functions 40 Screen & Screen: set (char c) 41 {42 contents [cursor] = c; 43 return * this; 44} 45 46 Screen & Screen: move (index r, index c) 47 {48 index row = r * width; 49 cursor = row + c; 50 return * this; 51} 52 53 Screen & Screen: display (ostream & OS) 54 {55 OS <contents; 56 return * this; 57} 58 59 int main () 60 {61 // create 62 Screen myScreen (5, 6, "aaaaa \ naaaaa \ n"); 63 64 // move the cursor to the specified position, set characters, and display the Screen Content 65 myScreen. move (4, 0 ). set ('#'). display (cout); 66 67 return 0; 68}View Code
This solution has met the requirements of the question, but has some defects:
(1) When creating a Screen object, a string must be provided to indicate the content of the entire Screen, even if there is no content in some locations.
(2) The displayed screen content is displayed consecutively instead of being properly distributed. Therefore, the '#' At the position () is not necessarily displayed on the screen) location, poor display effect.
(3) If the created Screen object is a const object, the display function cannot be used for display (because the const object can only use the const member ).
(4) If the target position of the move operation exceeds the boundary of the screen, a running error occurs.
To solve the first defect, you can modify the constructor as follows:
1 Screen: Screen (index hght, index wdth, const string & cntnts = ""): cursor (0), height (hght), width (wdth) 2 {3 // set the entire Screen Content to Space 4 contents. assign (hght * wdth, ''); 5 // set the corresponding character 6 if (cntnts. size ()! = 0) 7 contents. replace (0, cntnts. size (), cntnts); 8}
To solve the second defect, you can modify the display function as follows:
1 Screen& Screen::display(ostream &os) 2 { 3 string::size_type index = 0; 4 while (index != contents.size()) 5 { 6 os << contents[index]; 7 if ((index+1) % width == 0) 8 { 9 os << '\n'; 10 } 11 ++index; 12 } 13 return *this; 14 }
To solve the third defect, you can add the following function declaration to the Screen class definition body: const Screen & display (ostream & OS) const; declare an overloaded version of the display function, used by the const object.
To solve the fourth defect, you can modify the move function as follows:
1 Screen & Screen: move (index r, index c) 2 {3 // The row and column number start from 0. 4 if (r> = height c> = width) 5 {6 cerr <"invalid row or column" <endl; 7 throw EXIT_FAILURE; 8} 9 10 index row = r * width; 11 cursor = row + c; 12 return * this; 13}
As mentioned above, the robustness and robustness of the entire program have been improved. The Code is as follows:
1 # include <iostream> 2 # include <string> 3 4 using namespace std; 5 6 class Screen {7 public: 8 typedef string: size_type index; 9 char get () const {return contents [cursor];} 10 inline char get (index ht, index wd) const; 11 index get_cursor () const; 12 13 Screen (index hght, index wdth, const string & cntnts); 14 15 Screen & move (index r, index c); 16 Screen & set (char); 17 Screen & display (ostream & OS); 18 const Screen & display (ostream & OS) const; 19 20 private: 21 std: string contents; 22 index cursor; 23 index height, width; 24 }; 25 26 Screen: Screen (index hght, index wdth, const string & cntnts = "1"): 27 cursor (0), height (hght), width (wdth) 28 {29 contents. assign (hght * wdth, '1'); 30 31 if (cntnts. size ()! = 0) 32 contents. replace (0, cntnts. size (), cntnts); 33} 34 35 36 char Screen: get (index r, index c) const 37 {38 index row = r * width; 39 return contents [row + c]; 40} 41 42 inline Screen: index Screen: get_cursor () const 43 {44 return cursor; 45} 46 47 Screen & Screen :: set (char c) 48 {49 contents [cursor] = c; 50 return * this; 51} 52 53 Screen & Screen: move (index r, index c) 54 {55 if (r> = Height | c> = width) 56 {57 cerr <"invalid row or column" <endl; 58 throw EXIT_FAILURE; 59} 60 61 index row = r * width; 62 cursor = row + c; 63 64 return * this; 65} 66 67 Screen & Screen: display (ostream & OS) 68 {69 string: size_type index = 0; 70 71 while (index! = Contents. size () 72 {73 OS <contents [index]; 74 if (index + 1) % width = 0) 75 {76 OS <'\ n '; 77} 78 ++ index; 79} 80 return * this; 81} 82 83 const Screen & Screen: display (ostream & OS) const 84 {85 string :: size_type index = 0; 86 87 while (index! = Contents. size () 88 {89 OS <contents [index]; 90 if (index + 1) % width = 0) 91 {92 OS <'\ n '; 93} 94 + + index; 95} 96 return * this; 97} 98 99 int main () 100 {101 Screen myScreen (102); // Screen myScreen (5, 6. "aaaaa \ naaaaa \ n"); 103 myScreen. move (4, 0 ). set ('#'). display (cout); 104 105 system ("pause"); 106 107 return 0; 108}View Code