Classes
A class is an extension of a structure, which can have not only member elements but also member functions.
In object-oriented programming (OOP), an object is an instance of a class, i.e., a variable.
In C++, the struct keyword also defines a class; the definition of structure mentioned earlier comes from C. Due to certain historical reasons, C++ retains and extends struct.
Defining a Class
Classes are defined using the keyword class or struct. The following examples use class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
This is similar to using struct. This example defines a class named Object. The class has two member elements: weight and value; and after the }, an array e of this type is defined.
Defining pointers to a class is the same as for struct.
Access Specifiers
Unlike the example in struct, this example includes public, which is an access specifier.
public: Members following this access specifier can be accessed publicly, meaning they can be accessed both inside and outside the class.protected: Members following this access specifier can be accessed by members inside the class, derived classes, or friends, but cannot be accessed from outside the class.private: Members following this access specifier can only be accessed by members inside the class or friend members, and cannot be accessed from outside the class or from derived classes.
For struct, all members are public by default. For class, all members are private by default.
Basic Concepts of Friends and Derived Classes
Friend (friend): Use the friend keyword to modify a function or class. This allows the modified entity to access the private (private) or protected (protected) members of the class without becoming a member function or member class. In simple terms, any entity marked with friend for this class can access its private or protected members.
Derived class (derived class): C++ allows using a class as a base class and deriving a derived class from it. The derived class inherits (according to specific rules) member variables and member functions from the base class. This improves code reusability.
A derived class represents an "is" relationship. For example, a cat (derived class) "is" a mammal (base class).
Regarding the difference between private and protected, a derived class can access protected elements of the base class (same as public), but cannot access private elements.
Accessing and Modifying Member Element Values
The method is the same as for struct.
- For variables, use the
.symbol. - For pointers, use the
->symbol.
Member Functions
Member functions, as the name suggests, are functions contained within a class.
Common Examples of Member Functions
1 2 3 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
This class has a function to print the member elements of Object and a function to change the member element weight.
Similar to functions, member functions can also be declared first and defined later, as in line 14 (declaration) and after line 17 (definition).
To call the print member function of var, use var.print().
Overloading Operators
What is Overloading?
C++ allows programmers to specify different definitions for functions or operators with the same name. This is called overloading.
If the parameter types or numbers of overloaded functions differ in one or more ways, these functions with the same name are considered distinct.
Note: If two functions with the same name differ only in their return type, they cannot be overloaded, and the compiler will refuse to compile!
If no ambiguity arises during the call (i.e., when calling certain overloaded functions, it is impossible to uniquely determine which function to call based on the provided parameter types and numbers, which often occurs with functions having default parameters), the compiler will determine which function to call based on the parameters provided.
This process is called overload resolution.
Overloading operators can partially replace functions and simplify code.
Below is an example of overloading operators.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
This example defines a vector class and overloads the *, +, and - operators to represent vector dot product, vector addition, and vector subtraction, respectively.
The template for overloading operators can be roughly divided into the following parts.
1 2 3 | |
For custom classes, if certain operators are overloaded (generally only the < comparison operator needs to be overloaded), corresponding STL containers or algorithms can be used, such as sort.
For more information, refer to "Reference 4".
Operators That Can Be Overloaded
1 2 3 4 5 6 | |
Setting Initial Values When Instantiating Variables
To achieve this, you need to define a default constructor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
This example defines the default constructor for Object, which initializes all member elements to 0 when we instantiate a variable of type Object.
If no explicit constructor is defined, the compiler assumes the class has an implicit default constructor. In other words, if no constructor is defined, the compiler automatically generates a default constructor and initializes member elements based on their types (similar to defining built-in type variables).
In this case, member elements are uninitialized, and accessing uninitialized variables results in undefined behavior (i.e., it is unknown what value will be returned).
If custom initialization values are needed, you can define (or overload) constructors.
About Defining (or Overloading) Constructors
Generally, a default constructor takes no parameters, which distinguishes it from other constructors. The definition of constructors and default constructors is similar, differing only in the number of parameters.
Constructors can be overloaded (though the first definition is simply called defining). Note that if a constructor is defined, the compiler will no longer generate a parameterless default constructor. This may cause compilation to fail when attempting to construct variables using the default method (i.e., without providing initialization parameters).
When using C++11 or later, you can use {} to initialize variables.
About {}
Using {} for initialization involves the lightweight proxy object std::initializer_list.
The initialization steps are roughly as follows:
- Attempt to find a default constructor with
std::initializer_listin its parameters; if found, call it (after this, no further searches are performed, same below). - Attempt to fill the elements in
{}into other constructor parameters. If the parameters can be filled in order (including default parameters), call that default constructor. - If there are no
privatemember elements, attempt to assign values in order of element definition or subscript order outside the class.
The above process is a simplified version of the complete process. For details, refer to "Reference 9".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
About Implicit Type Conversion
Sometimes code like the following is written:
1 2 3 4 5 6 7 8 | |
This seems illogical, as an int type cannot be converted to a node type. However, the compiler does not give an error prompt.
The reason is that during assignment, 1 is first used as a parameter to call node::node(int), and then the default copy function is called for assignment.
However, in most cases, the programmer would want the compiler to report an error. In such cases, the explicit keyword can be added before the constructor. This tells the compiler that explicit invocation is required.
1 2 3 4 5 6 | |
This means node a = 1 will cause an error, but node a = node(1) will not, because the latter explicitly calls the constructor. Of course, most people would not write the latter code, but this example suffices to illustrate the role of explicit.
However, in algorithm competitions, the common practice to avoid such situations is to "strengthen code standardization," preventing it at the source.
Destruction
This is an unavoidable issue. Every variable will be destroyed when it goes out of scope.
However, for pointers that already point to dynamically allocated memory, the pointer does not automatically release the memory it points to when destroyed; manual release of dynamic memory is required.
If a structure's member elements include pointers, the same problem arises. A destructor is needed to manually release dynamic memory.
The destructor will be called when the variable is destroyed. The overloading method is similar to constructors but requires a ~ prefix.
The default destructor is usually sufficient for algorithm competitions. Typically, we only overload the destructor when member elements include pointers.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Assigning Values to Class Variables
By default, assignment follows the rules for assigning corresponding member elements. You can also use class_name() or class_name{} as temporary variables for assignment.
The former only calls the copy constructor, while the latter calls the default constructor before calling the copy constructor.
Additionally, by default, assignments perform shallow copy between corresponding elements. If member elements include pointers, after assignment, the member pointers of both variables will have the same address.
1 2 3 4 | |
To resolve pointer issues or perform more operations, you need to overload the corresponding constructors.
For more on constructors, refer to "Reference 6".
References
- cppreference class
- cppreference access
- cppreference default_constructor
- cppreference operator
- cplusplus Data structures
- cplusplus Special members
- C++11 FAQ
- cppreference Friendship and inheritance
- cppreference value initialization
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用