[In-depth explanation of C#] Chapter 4: Basics of Object-Oriented Programming: Constructors and Destructors

Constructor and destructor are two important concepts in object-oriented programming, which play a key role in the process of object creation and destruction.
A constructor is a special member function used to initialize an object's data members when the object is created. Its main function is to allocate memory space for the object and initialize the state of the object. A constructor has the same name as the class and has no return type. With constructors, you can ensure that an object has a valid initial state when it is created. Constructors can be overloaded, which means that multiple constructors with different parameters can be defined as needed.
A destructor is a special member function that performs the necessary cleanup when an object is destroyed. Its main function is to release resources occupied by objects, such as releasing dynamically allocated memory, closing open files, or releasing other external resources. The name of the destructor is the same as the class name, prefixed with a tilde (~). Destructors are called automatically when an object is destroyed and cannot be called manually.
Constructors and destructors play a key role in the life cycle of an object. Constructors ensure that objects are created in a proper initialization state, while destructors ensure that objects are cleaned up when they are destroyed. This process of object creation and destruction is very important for the correct operation of the program and resource management. Proper use of constructors and destructors can improve code readability, maintainability, and reliability, while avoiding problems such as memory leaks and resource leaks.

Tip: Constructors and destructors are integral to object-oriented programming, and they are crucial to properly manage object lifecycles and resources. Developers should reasonably design and use constructors and destructors according to specific needs, and follow best practices to ensure the correctness and reliability of programs.

1. Constructor

1.1 Definition and syntax of constructor

A constructor is a special member function used for initialization when an object is created. It has the same name as the class, has no return type, and can contain parameters. The syntax for defining a constructor is as follows:

访问修饰符 类名([参数列表]) {
    
    
    // 构造函数的实现代码
}

Among them, the access modifier can be public, private, protected or internal, which is used to control the access rights of the constructor. The class name has the same name as the constructor, and the parameter list is optional for passing parameters to the constructor. Constructors can be overloaded, that is, define multiple constructors with different parameters in the same class, so as to create objects according to different parameter lists. In the constructor, you can perform some initialization operations, such as initializing the data members of the object, allocating memory, calling other functions, and so on. Constructors are called automatically when an object is created, there is no need to call them manually. The following is a sample code showing the definition and use of a constructor with parameters:

public class Person {
    
    
    private string name;
    private int age;

    // 带有参数的构造函数
    public Person(string n, int a) {
    
    
        name = n;
        age = a;
    }

    // 其他成员函数

    // 示例代码:创建对象并使用构造函数进行初始化
    public static void Main() {
    
    
        // 使用构造函数创建对象并初始化
        Person person = new Person("John", 25);

        // 访问对象的数据成员
        Console.WriteLine("Name: " + person.name);
        Console.WriteLine("Age: " + person.age);
    }
}

In the above example, the Person class defines a constructor with two parameters to initialize the name and age data members. In the Main function, use the constructor to create a Person object, and output the property values ​​of the object.

Tip: The constructor can define different overloaded forms as needed to support different initialization methods.

1.2 The characteristics and purpose of the constructor

Constructors have the following characteristics and purposes:

  1. The same name as the class: The constructor has the same name as the class and is used for initialization when creating an object. It is called automatically when the object is created, no need to call it manually.
  2. No return type: Constructors have no return type, including void, because their main purpose is to initialize an object rather than return a value.
  3. Can be overloaded: In the same class, multiple constructors can be defined, which have the same name but different parameter lists, so as to initialize objects according to different situations.
  4. Can access members of the class: The constructor can access all members of the class, including properties, fields, and methods, in order to perform necessary operations during initialization.

The main purpose of the constructor is to initialize the object when it is created, to ensure that the object is in a suitable state before it is used. Through the constructor, you can set the initial value of the object, allocate memory, perform some necessary settings, and so on. They provide a convenient way to ensure that objects are created with the correct initial state to avoid errors or exceptions in subsequent code. Constructors can also be used to perform some additional initialization logic, such as connecting to a database, loading configuration files, initializing other objects, etc. This makes constructors an ideal place to initialize and prepare objects.

1.3 The difference between default constructor and custom constructor

The difference between default constructor and custom constructor is as follows:

  1. Definition method: The default constructor is a no-argument constructor automatically generated by the compiler. When the class does not explicitly define a constructor, the default constructor will be created implicitly. A custom constructor is a constructor that is explicitly defined by the developer as needed, and can specify a parameter list and implement logic as needed.
  2. Parameter list: The default constructor has no parameters, and the custom constructor can have a different parameter list, allowing the initialization of objects according to different situations.
  3. Implementation logic: The implementation logic of the default constructor is usually empty, that is, it does not perform any specific operations. The custom constructor can perform some initialization operations as needed, such as setting the initial value of the object, allocating memory, initializing member variables, and so on.
  4. Calling method: The default constructor will be called implicitly when creating an object, no need to call it manually. Custom constructors can be manually invoked as needed to implement specific initialization logic.
  5. Overloading: The default constructor does not have the concept of overloading, and each class can only have one default constructor. Custom constructors can be overloaded with different parameter lists, allowing different constructors to be used in different situations.

Overall, the difference is that the default constructor is a no-argument constructor automatically generated by the compiler without parameter list and implementation logic, while a custom constructor is explicitly defined by the developer, who can specify the parameter list and implementation as needed logic. The custom constructor provides greater flexibility and control, and can initialize and set objects according to specific needs.

1.4 Overloading of constructors

Constructor overloading refers to defining multiple constructors with different parameter lists in the same class. Through the overloading of the constructor, objects can be created according to different parameter combinations, and different initialization logics can be implemented. Constructor overloading needs to meet the following conditions:

  1. The name of the constructor must be the same as the name of the class.
  2. The parameter lists of the constructors must differ, either in the type, order, or number of parameters.
  3. Constructors can have different access modifiers such as public, private, or protected.

Here is an example showing overloading of multiple constructors in a class:

public class MyClass
{
    
    
    private string name;
    private int age;

    // 无参构造函数
    public MyClass()
    {
    
    
        name = "Default";
        age = 0;
    }

    // 带参数的构造函数
    public MyClass(string n, int a)
    {
    
    
        name = n;
        age = a;
    }

    // 带参数的构造函数重载
    public MyClass(string n)
    {
    
    
        name = n;
        age = 0;
    }

    // 带参数的构造函数重载
    public MyClass(int a)
    {
    
    
        name = "Default";
        age = a;
    }
}

In the above example, MyClassthe class defines multiple constructors, including no-argument constructors and constructors with parameters. Through different parameter combinations, different constructors can be selected to create objects and initialized according to the parameters passed in.
The overloading of the constructor makes the creation of the object more flexible, and the appropriate constructor can be selected according to the specific needs to initialize the object. It provides more options and convenience, making the code more readable and maintainable.

1.5 Constructor calling order and initialization list

The order in which constructors are called is determined by the object hierarchy. When creating a derived class object, the order in which the constructors are called starts from the base class and goes down level by level until the derived class object is finally created.
Initializer lists are special syntax for initializing fields in constructors. The initializer list allows fields to be assigned values ​​before the body of the constructor is executed. An initializer list follows the definition of a constructor using a colon (:) and lists initializations for fields after the colon. Here is an example showing the usage of constructor calling order and initialization list:

public class BaseClass
{
    
    
    private int baseValue;

    public BaseClass(int value)
    {
    
    
        baseValue = value;
        Console.WriteLine("BaseClass constructor");
    }
}

public class DerivedClass : BaseClass
{
    
    
    private int derivedValue;

    public DerivedClass(int baseValue, int derivedValue) : base(baseValue)
    {
    
    
        this.derivedValue = derivedValue;
        Console.WriteLine("DerivedClass constructor");
    }
}

public class Program
{
    
    
    static void Main()
    {
    
    
        DerivedClass obj = new DerivedClass(10, 20);
    }
}

In the above example, DerivedClassinheriting from BaseClass. When creating an object, the constructor of DerivedClassthe base class is called first , and then the constructor of the derived class is called. The initialization list uses the keyword in the constructor of the derived class to specify the parameters of the base class constructor, and initializes the fields of the derived class through the initialization list after the colon. In the preceding example, the constructor for invokes the base class constructor with and initializes the fields of the derived class with an initializer list. The order in which constructors are called and the use of initialization lists ensures the correct initialization order of objects and provides flexible initialization options for fields. This ensures that the state of the object is correct and consistent, avoiding potential bugs and logic problems.BaseClassDerivedClassbaseDerivedClassbase(baseValue)

Second, the destructor

2.1 Definition and syntax of destructor

A destructor is a special member function that is called automatically when an object is destroyed. Its function is to release the resources occupied by the object and perform cleanup operations to ensure that the object will not cause resource leaks or other problems when it is destroyed. In C#, the definition of a destructor follows the syntax:

~ClassName()
{
    
    
    // 析构函数的代码块
}

Among them, ~the symbol immediately follows the class name, has no return type, and does not accept any parameters.

It should be noted that C# does not support explicitly calling the destructor, but the garbage collector (Garbage Collector) is responsible for automatically calling the destructor when the object is destroyed. The garbage collector determines when to call the destructor based on the object's lifetime and memory management policy.
Here is a simple example showing the definition and use of a destructor:

public class MyClass
{
    
    
    public MyClass()
    {
    
    
        Console.WriteLine("Constructor called");
    }

    ~MyClass()
    {
    
    
        Console.WriteLine("Destructor called");
    }
}

public class Program
{
    
    
    static void Main()
    {
    
    
        MyClass obj = new MyClass();

        // 执行一些操作

        // 对象销毁时会自动调用析构函数
    }
}

In the above example, MyClassa destructor is defined in the class ~MyClass(). When an object is created MyClass, the constructor is called. At Main()the end of the method, MyClasswhen the object goes out of scope and is reclaimed by the garbage collector, the destructor will be called automatically.
The main function of the destructor is to release the resources of the object, such as closing files, releasing memory, disconnecting, etc. When writing destructors, care should be taken to ensure proper release and cleanup of resources to avoid potential resource leaks and errors. At the same time, the call of the destructor is controlled by the garbage collector, so it is impossible to determine the exact point in time when the destructor is called. Therefore, using destructors to release unmanaged resources is probably not the best practice in most cases. Preference should be given to using Disposemethods and usingstatements to manually manage the release of resources.

2.2 The characteristics and functions of the destructor

The destructor has the following characteristics and functions:

  1. Features:
    • The destructor is called automatically when the object is destroyed, there is no need to call it manually.
    • The destructor has no return type and does not accept any parameters.
    • A class can only define one destructor.
  2. effect:
    • Release the resources occupied by the object: The destructor is often used to release the resources used by the object, such as closing files, releasing memory, disconnecting, etc. It ensures that resources are properly released when objects are destroyed, avoiding resource leaks and memory leaks.
    • Perform cleanup operations: The destructor can perform some cleanup operations, such as unsubscribing events, destroying associations between objects, and so on.
    • Provide object life cycle management: Through the destructor, you can control the life cycle of the object to ensure proper cleanup when the object is no longer in use.

In actual development, destructors should be used with caution, and other ways to manually manage the release of resources should be given priority, such as implementing IDisposableinterfaces, using usingstatements, and so on. These methods are more flexible and controllable, can ensure timely release of resources, and improve code maintainability and performance. The use of destructors should be limited to specific scenarios where unmanaged resources need to be released, and the code execution efficiency of destructors should be ensured to avoid affecting system performance.

2.3 The calling order of the destructor when the object is destroyed

When an object is destroyed, the calling order of the destructor follows the following rules:

  1. The subclass destructor is called before the parent class destructor: If a class is a subclass of another class, then when the subclass object is destroyed, the subclass destructor will be called before the parent class destructor .
  2. Objects are created in reverse order of destruction: Within the same class hierarchy, objects are created in reverse order of destruction. That is, the object created last will be destroyed first, and the object created first will be destroyed last.
  3. The members of the object are called before the destructor of the object itself: in the destructor of a class, the destructors of the members of the object (such as properties, fields, object references, etc.) will be called before the destructor of the object itself .

Tip: The garbage collector (Garbage Collector) is responsible for invoking the destructor. The specific timing and order of invocation may be affected by the garbage collector algorithm and memory management strategy. Therefore, there is no way to fully control the order in which destructors are called. In actual development, you should try to avoid relying on the calling order of destructors for logical operations, but use other methods to manage the life cycle of objects and the release of resources.

2.4 Precautions for manually calling the destructor

In C#, you cannot directly call the destructor (Finalizer) manually. The destructor is called by the garbage collector (Garbage Collector) to clean up and release resources when the object is destroyed. The garbage collector will automatically determine the appropriate time to call the destructor to ensure that the object's resources are properly released.
Since the garbage collector is already responsible for managing the lifecycle of objects and the release of resources, manually calling the destructor is not recommended, or even allowed. Therefore, there is no need to explicitly call the destructor in the code.
In some cases, you can use IDisposableinterfaces and Disposemethods to explicitly release unmanaged resources, but this is not a replacement for manually calling the destructor. DisposeMethods should be called explicitly by the caller, not by the destructor.

Tip: C# provides syntax for destructors (using ~symbols), but in fact they are called automatically by the garbage collector and do not require manual intervention. Therefore, when writing code, you should follow the best practice of using IDisposableinterfaces and Disposemethods to release resources, rather than relying on destructor calls.

3. Application scenarios and best practices of constructors and destructors

Constructors and destructors play an important role in object-oriented programming, and they have different application scenarios and best practices.
Application scenarios of constructors:

  1. Object initialization: The constructor is used to initialize the member variables of the object to ensure that the object is in a usable state when it is created.
  2. Parameter passing: The constructor can accept parameters, which are used to pass the data required to initialize the object.
  3. Instantiate an object: Create an instance of a class by calling a constructor.

Best practices for constructors:

  1. Provide a default constructor: Provide a default constructor with no parameters for the class so that no parameters need to be explicitly provided when creating the object.
  2. Reasonable use of constructor overloading: According to the requirements of the object, different constructor overloading is provided so that different initialization requirements can be met when creating an object.
  3. Initialize member variables: initialize member variables in the constructor to ensure that the object has the correct initial state when it is created.
  4. Avoid performing time-consuming operations: Constructors should try to avoid performing time-consuming operations to ensure that the object creation process is not too cumbersome and resource-intensive.
  5. Use constructor chains: Use constructor chains in multiple constructors of a class to avoid repetitive code logic and improve code reusability.

Application scenarios of destructors:

  1. Release of resources: The destructor is used to release the resources occupied by the object, such as closing files, releasing database connections, and so on.
  2. Cleanup operations: The destructor can perform some cleanup operations, such as freeing memory, unsubscribing events, etc.

Best practices for destructors:

  1. Use IDisposableinterfaces and Disposemethods: For situations where resources need to be released manually, IDisposableinterfaces should be implemented and Disposeresources released in methods.
  2. Call Disposemethod: When using an object that implements IDisposablean interface, its Disposemethod should be called in time to ensure that resources are released correctly.
  3. Do not call the destructor directly: It is not recommended to call the destructor manually, and you should rely on the garbage collector to automatically call the destructor to release resources.

By judiciously using constructors and destructors, and following best practices, you can improve code readability, maintainability, and ensure correct behavior of objects during creation and destruction.

Four. Summary

Constructors and destructors are important concepts in object-oriented programming. Constructors are used to initialize member variables of an object and ensure that the object is in the correct state when it is created. They play a key role in the creation of objects. The destructor is used to release the resources occupied by the object and perform cleanup operations. They play an important role in the process of object destruction, ensuring that the resources of the object are released correctly, avoiding resource leaks and memory leaks.

Guess you like

Origin blog.csdn.net/gangzhucoll/article/details/131368153