Detailed Explanation of Constructor and Destructor Usage Examples in C

  • 2021-10-25 07:42:07
  • OfStack

This article illustrates the use of constructors and destructors in C #. Share it for your reference, as follows:

Constructor and destructor are two seemingly simple functions in a class, but there will always be some unexpected running errors in the actual application process. This article will systematically introduce the principle of constructor and destructor and its application in C #, as well as some matters needing attention in the use process.

1. Principles of constructors and destructors

As a more advanced language than C, C # provides better mechanisms to enhance program security. The C # compiler has strict type-safety checking, and it can find almost all syntax problems in the program, which really helps programmers a lot. However, the program passed the compile check does not mean that the error no longer exists. In the big family of "errors", the status of "grammatical errors" can only be regarded as the tip of the iceberg. High-level errors are usually hidden deep and not easy to find.

According to experience, many imperceptible program errors are caused by variables not being initialized or cleared correctly, and the initialization and clearing work is easily forgotten. When designing C # by using the concept of object-oriented, Microsoft fully considered this problem and solved it well: the initialization of objects is put in the constructor, and the cleaning is put in the destructor. When the object is created, the constructor is executed automatically. When the object dies, the destructor is executed automatically. In this way, you don't have to worry about forgetting the initialization and cleanup of objects.

2. The application of constructor in C #

The name of the constructor can't be named casually, and it must be recognized by the compiler before it can be automatically executed. Its naming method is simple and reasonable: let the constructor have the same name as the class. In addition to the name, another special feature of the constructor is that it has no return value type, which is different from functions with a return value type of void. If it has a return value type, the compiler will be at a loss. Before you can access the methods, properties, or anything else of a class, the statement executed in Number 1 is the constructor that contains the corresponding class. Even if you don't write a constructor yourself, there will be a default constructor for you.

Several types of constructors are listed below

1) Default constructor


class TestClass
{
    public TestClass(): base() {}
}

As described above, it is provided by the system (CLR).

2) Instance constructor

An instance constructor is a method member that implements initialization of an instance in a class. Such as:


using System;
class Point
{
public double x, y;
public Point()
{
this.x = 0;
this.y = 0;
}
public Point(double x, double y)
{
this.x = x;
this.y = y;
}
 … 
}
class Test
{
static void Main()
{
Point a = new Point();
Point b = new Point(3, 4); //  Initialize an object with a constructor 
 … 
}
}

Declares a class Point, which provides two constructors. They are overloaded. 1 is an Point constructor with no arguments and 1 is an Point constructor with two double arguments. If these constructors are not provided in the class, CLR will automatically provide a default constructor. However, if custom constructors are provided in the 1-denier class, such as Point () and Point (double x, double y), the default constructor will not be provided.

3) Static constructor

A static constructor is a method member that implements initialization of a class. It is generally used to initialize static data. Static constructors cannot have parameters, can't have modifiers, and can't be called. When the class is loaded, the static constructor of the class is automatically called. Such as:


using System.Data;
class Employee
{
private static DataSet ds;
static Employee()
{
ds = new DataSet(...);
}
...
}

Declared a class Employee with a static constructor. Note that static constructors can only initialize static data members, not non-static data members. However, non-static constructors can either assign values to or initialize non-static data members.

If the class contains only static members, you can create a constructor for private: private TestClass () {…}, but private means that it is impossible to access the constructor from outside the class. Therefore, it cannot be called, and no object can be instantiated by the class definition.

The above is a simple use of several types of constructors. The following will focus on the use of constructors for base classes and derived classes in the class hierarchy (that is, inheritance structure) under 1. Derived class objects are initialized by both base class and derived class: members of base class are initialized by base class constructors, and members of derived class are initialized by derived class constructors.

When you create an object of a derived class, the system calls the constructor of the base class and the constructor of the derived class. The constructor is executed in the order of executing the constructor of the base class first and then the constructor of the derived class. If the derived class has object members, the constructor of the base class is executed first, then the constructor of the member object class, and finally the constructor of the derived class.

As for what constructor to execute for the base class, the default is to execute the parameterless constructor of the base class. If you want to execute the parameterized constructor of the base class, you must indicate it in the member initialization table of the derived class constructor. Such as:


class A
{
private int x;
public A( ) { x = 0; }
public A( int i ) { x = i; }
}
class B : A
{
private int y;
public B( ) { y = 0; }
public B( int i ) { y = i; }
public B( int i, int j ):A(i) { y = j; }
}
B b1 = new B(); // Execute base class A Constructor of A() And then execute the constructor of the derived class B()
B b2 = new B(1); // Execute base class A Constructor of A() And then execute the constructor of the derived class B(int)
B b3 = new B(0,1); // Execute the execution base class A Constructor of A(int)  And then execute the constructor of the derived class B(int,int)

Here, the order of execution of the constructor is 1, which must be analyzed clearly. In addition, if the parameterless constructor public A () {x = 0;} is not provided in the base class A, the parameterized constructor A (i) of the base class A must be indicated in all constructor member initialization tables of the derived class, as follows:


class A
{
private int x;
public A( int i ) { x = i; }
}
class B : A
{
private int y;
public B():A(i) { y = 0; }
public B(int i):A(i) { y = i; }
public B(int i, int j):A(i) { y = j; }
}

3. Application of destructor and garbage collector in C #

A destructor is a method member that destroys an instance of a class. Destructors cannot have arguments, can't have any modifiers, and can't be called (automatically called by the system). Because the purpose of destructor is opposite to that of constructor, prefix '~' is added to show the difference.

Although C # (more specifically, CLR) provides a new memory management mechanism-automatic memory management mechanism (Automatic memory management), the release of resources can be automatically completed through the "garbage collector", 1 generally does not need user intervention, but in some special cases, it is necessary to use destructors, such as the release of unmanaged resources in C #.

The release of resources is generally done automatically through the garbage collector, but specifically, there are still some places to pay attention to:

1. References of value types and reference types actually do not need any "garbage collector" to release memory, because when they are out of scope, they will automatically release the occupied memory, because they are all stored in the stack (Stack);

2. Only the object instance pointed to by the reference type is stored in the heap (Heap), and because the heap is a free storage space, it does not have the lifetime like the "stack" (the ejection of the elements of the "stack" means the end of the lifetime, which means the release of memory), and it should be noted that the "garbage collector" only works for this area;

However, in some cases, when unmanaged resources need to be released, it must be solved by writing code. Usually, destructors are used to release unmanaged resources, and code segments written by users to release unmanaged resources are placed in destructors. It should be noted that if an unmanaged resource is not used in a class, then 1 must not define a destructor, because the object executes a destructor, so the "garbage collector" must call the destructor before releasing the managed resource, and then actually release the managed resource for the second time, so that the cost of two deletions is much higher than that of one. The following is a piece of code to show how the destructor is used:


public class ResourceHolder
{
 … 
~ResourceHolder()
{
//  Here is the user code snippet for cleaning up unmanaged resources 
}
}

4. Summary

Although constructor and destructor are simple functions in a class, their use is by no means as simple as it seems. Therefore, flexible and correct use of constructor and destructor can help you better understand the memory management mechanism of CLR and better manage the resources in the system.

Note: CLR

CLR (Common Language Runtime) and Java Virtual Machine 1 are also a runtime environment, which is responsible for resource management (memory allocation and garbage collection) and ensures the necessary separation between applications and the underlying operating system.

In order to improve the reliability of the platform and achieve the stability level required by transaction-oriented e-commerce applications, CLR is also responsible for other tasks, such as monitoring the operation of programs. According to. NET, programs running under the supervision of CLR belong to "managed" (managed) code, while applications or components not running directly on bare metal under CLR belong to "unmanaged" (unmanaged) code.

CLR monitors a wide variety of common programming errors that have been a major source of software failures for many years, including access to array elements out of bounds, access to unallocated memory space, memory overflows due to oversized data, and so on.

For more readers interested in C # related content, please check the topics on this site: "Summary of thread usage skills in C # programming", "Summary of C # operating Excel skills", "Summary of XML file operation skills in C #", "Tutorial on common control usage of C #", "Tutorial on control usage of WinForm #", "Tutorial on data structure and algorithm of C #", "Tutorial on array operation skills of C #" and "Introduction to C # object-oriented programming"

I hope this article is helpful to everyone's C # programming.


Related articles: