C++ basic syntax: constructors and destructors

  • 2020-04-02 01:44:39
  • OfStack

One. Constructor

Similar to Java,C++ also has the concept of constructor, related usage is as follows:

1.1 constructor definition


#include <iostream>
using namespace std;

class Student{
private:
  char *m_name;
  int m_age;
  float m_score;
public:
  //Declaration constructor
  Student(char *name, int age, float score);
  //Declare ordinary member functions
  void show();
};

//Define the constructor
Student::Student(char *name, int age, float score){
  m_name = name;
  m_age = age;
  m_score = score;
}
//Define normal member functions
void Student::show(){
  cout<<m_name<<" The age is "<<m_age<<" , the result is "<<m_score<<endl;
}

int main(){
  //Passing arguments to the constructor when an object is created
  Student stu(" Xiao Ming ", 15, 92.5f);
  stu.show();
  //Passing arguments to the constructor when an object is created
  Student *pstu = new Student(" Li hua ", 16, 96);
  pstu -> show();

  return 0;
}

Operation results:

Xiao Ming's age is 15 and his score is 92.5
Li hua is 16 years old and gets 96

1.2 overloaded constructor

The constructor also supports overloaded operations:


#include <iostream>
using namespace std;

class Student{
private:
  char *m_name;
  int m_age;
  float m_score;
public:
  Student();
  Student(char *name, int age, float score);
  void setname(char *name);
  void setage(int age);
  void setscore(float score);
  void show();
};

Student::Student(){
  m_name = NULL;
  m_age = 0;
  m_score = 0.0;
}
Student::Student(char *name, int age, float score){
  m_name = name;
  m_age = age;
  m_score = score;
}
void Student::setname(char *name){
  m_name = name;
}
void Student::setage(int age){
  m_age = age;
}
void Student::setscore(float score){
  m_score = score;
}
void Student::show(){
  if(m_name == NULL || m_age <= 0){
    cout<<" The member variable has not been initialized "<<endl;
  }else{
    cout<<m_name<<" The age is "<<m_age<<" , the result is "<<m_score<<endl;
  }
}

int main(){
  //Call constructor Student(char *, int, float)
  Student stu(" Xiao Ming ", 15, 92.5f);
  stu.show();

  //Call the constructor Student()
  Student *pstu = new Student();
  pstu -> show();
  pstu -> setname(" Li hua ");
  pstu -> setage(16);
  pstu -> setscore(96);
  pstu -> show();

  return 0;
}

Operation results:

Xiao Ming's age is 15 and his score is 92.5
The member variable has not been initialized
Li hua is 16 years old and gets 96

1.3 default constructor

Similar to Java, if the user does not define a constructor himself, the compiler automatically generates a default constructor whose body is empty.

Note: calling constructors with no arguments can also omit the parenthesis.

Student *stu = new Student;

Student *stu = new Student();

These two ways are equivalent.

1.4 constructor parameter initialization table

The main purpose of a constructor is to initialize member variables. To do this, you can assign member variables one by one in the body of the constructor, and you can also initialize the table with parameters. The specific writing method is as follows:


#include <iostream>
using namespace std;

class Student{
private:
  char *m_name;
  int m_age;
  float m_score;
public:
  Student(char *name, int age, float score);
  void show();
};

//Initialize the table with parameters
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
  //TODO:
}
void Student::show(){
  cout<<m_name<<" The age is "<<m_age<<" , the result is "<<m_score<<endl;
}

int main(){
  Student stu(" Xiao Ming ", 15, 92.5f);
  stu.show();
  Student *pstu = new Student(" Li hua ", 16, 96);
  pstu -> show();

  return 0;
}

Operation results:

Xiao Ming's age is 15 and his score is 92.5
Li hua is 16 years old and gets 96

1.5 initialize the const member variables using the parameter initialization table

Parameter initialization tables also play an important role in initializing const member variables. The only way to initialize a const member variable is to initialize the table with parameters. Ex. :


class VLA {
private:
  const int m_len;
  int *m_arr;
public:
  VLA(int len);

};



VLA::VLA(int len):m_len(len) {
  m_arr = new int[len];
}

Two. Destructor

When an object is created, the system will automatically call the constructor to initialize it. Likewise, when the object is destroyed, the system will automatically call a function to clean it up, such as freeing allocated memory, closing open files, etc. This function is the destructor.

Destructor is also a special member function that does not return a value and does not need to be called explicitly by the programmer (which the programmer cannot), but instead is executed automatically when an object is destroyed. The constructor name is the same as the class name, while the destructor name is preceded by a ~ symbol.

Note: destructors have no arguments and cannot be overloaded, so a class can only have one destructor. If the user does not define it, the compiler automatically generates a default destructor.


class VLA {
public:
  VLA(int len);
  ~VLA(); //The destructor
private:
  const int m_len;
  int *m_arr;
};

VLA::VLA(int len):m_len(len) { //Constructor initialization
  if (len > 0) {m_arrz = new int[len];};
  else {m_arr = NULL;};
}

VLA::~VLA() {
  delete []m_arr; //Frees the memory requested by the heap area in the destructor
}

New and delete in C++ are used to allocate and free memory, respectively. The biggest difference between them and malloc() and free() in C is that the constructor is called when memory is allocated with new and destructor is called when memory is freed with delete. Constructors and destructors are integral to classes, so we encourage the use of new and delete in C++.

Here are some other comments

To tell the truth, c++ is used in school before, from graduation to now has been using c embedded programming, now to move out of c++ grammar, if there is a mistake in the understanding, also please passing friends more correction ~ ~ ~

Constructor is used to construct an object, mainly to do some initialization work, if the class does not provide a constructor, the compiler will provide a default constructor by default (the constructor with an empty parameter is the default constructor); Destructors are implicitly called, and the delete object is automatically called to clean up the object.

Now let's focus on the constructor and destructor calls in inheritance:


class A  {}   ; 
class B : public A
{};
class C : public B
{} ; 

c  *  ptr  =  new C() ;
delete ptr ;

In general, the code above is the constructor calls the root of the parent class constructor, then the parent class constructor is a level, and in turn to until the constructor of a derived class itself, but also to the parent class constructor calls are the parent class's default constructor (of course also can display the calling the default constructor of the parent), that is to say, derived classes before the structure itself will first turn on the inheritance to the parent of the component to construct good;

A call to a destructor is a call to the destructor of the derived class itself, followed by the parent destructor at the next level up to the root parent destructor, which is how the destructor is called when there is no polymorphism.

Change the code above:

A * PTR = new C();
The delete PTR.

In the case of polymorphism, if the destructor in base class A is not an imaginary function, the destructor in A will only be called when delete PTR, and the destructor in B and C will not be called. If the destructor in A is imaginary then all destructors will be called in the same order as usual.

Change the above code again:

B * PRT = new C();
The delete PTR.

In the case of polymorphism, if the destructors in A and B are not virtual destructors, then when delete PTR, the destructor in B will be called first, and then the destructor in A will not be called. If at least one of A or B is virtual destructor, the destructor will be called as usual.

So to summarize the rule:

CA * PTR = new CB();
The delete PTR.

CB is a subclass of CA, the constructor call is always the same, when with polymorphism:
If neither CA nor its parent class has A virtual destructor, the destructor of A is first called, then the destructor of A's parent class is called to the root parent destructor, and the destructor of A's parent class is not called until the derived class. If only one of the CA and its superclasses has a virtual destructor, the destructor call is the same as usual.

Therefore: A base class with polymorphism should declare a virtual destructor, which generally has other virtual functions.
Destructors should not be declared virtual destructors if the class is not designed for the base class and is not polymorphic

Test code:


#include<iostream>
using namespace std ;

class A
{
public:
A(){cout<<"A constructor"<<endl;}
A(char * arp) { cout <<"not default " ;}

~CA(){cout<<"A desstructor"<<endl;}

};

class B:public A
{
public:
B(){cout<<"B constructor"<<endl;}

~B(){cout<<"B desstructor"<<endl;}
};

class C:public B
{
public:
C(char * arp){cout<<"C constructor"<<endl;}

~C(){cout<<"C desstructor"<<endl;}
};
int main()
{
C * ptr = new C("hello world") ;
delete ptr ;
}

In addition, as mentioned in effective C++ :

1. Destructors cannot spit out abnormal, if the destructor function abnormalities may be produced, have to be captured within the destructor for processing, because if the destructor exceptions, such as vector, when all the object's destructor is called to delete may lead to more than throw exceptions, so as to make the program into the uncertainty.

2, If the user needs to react to an exception thrown during the run of an action function, class should provide a normal function to perform the action.

3, In the constructor and destructor should call virtual functions, that is because when the object calls the constructor structure, will first calls the superclass constructor, the object types to the compiler is a superclass object (the actual subclass members at this time also is in a state of uncertainty), virtual function will call the parent class, and do not call a subclass of virtual functions.


Related articles: