6. C++ constructor (Part 1)

1. Why do we need a constructor?

#include <stdio.h>

class Person {
private:
char *name;
int age;
char *work;

public:
void setName(char *name)
{
this->name = name;
}
int setAge(int age)
{
if (age < 0 || age > 150)
{
this->age = 0;
return -1;
}
this->age = age;
return 0;
}
void printInfo(void)
{
printf("name = %s, age = %d, work = %s\\
", name, age, work);
}
};

int main(int argc, char **argv)
{
Person per;

//per.name = "zhangsan";
per.setName("zhangsan");
per.setAge(200);
per.printInfo();
\t
return 0;
}

After defining Person per, you need to set Name and Age. Calling the function twice is inefficient, so we have a constructor.

2. Introduction

The constructor is a function with the same name as the class. It can take parameters or not.

#include <iostream>
using namespace std;

class Person {
private:
char *name;
int age;
char *work;

public:

Person() {cout <<"Pserson()"<<endl;}
Person(char *name)
{
cout <<"Pserson(char *)"<<endl;
this->name = name;
}

Person(char *name, int age)
{
cout <<"Pserson(char*, int)"<<endl;
this->name = name;
this->age = age;
}
\t
void setName(char *n)
{
name = n;
}
int setAge(int a)
{
if (a < 0 || a > 150)
{
age = 0;
return -1;
}
age = a;
return 0;
}
void printInfo(void)
{
//printf("name = %s, age = %d, work = %s\\
", name, age, work);
cout<<"name = "<<name<<", age = "<<age<<", work = "<<work<<endl;
}
};

int main(int argc, char **argv)
{
Person per("zhangsan", 16);
Person per2;

per.printInfo();
\t
return 0;
}

In C language ( ) generally corresponds to the call of a function. An object of the Person class is defined. Which function will it cause to be called?

Causes the corresponding constructor in the class to be called,

int main(int argc, char **argv)
{
Person per("zhangsan", 16); /* Call the constructor with two parameters */
Person per2; /* Call the constructor without parameters */
Person per3(); /* int fun(); is just a function declaration and will not call the constructor
                      Equivalent to Person fun() */

per.printInfo();
return 0;
}

Person per2; /* Call the constructor without parameters */

Person per3(); /* int fun(); is just a function declaration and will not call the constructor Person fun() */

3.Default parameters

The above code does not work,

a. You can implement a constructor with 3 parameters and call it when Person per(“zhangsan”, 16, “teacher”);

b. You can implement a constructor with 2 parameters, specify work as the default parameter, Person per(“zhangsan”, 16); will be called, Person per(“zhangsan”, 16, “teacher\ “); will also be called when

#include <iostream>
using namespace std;

class Person {
private:
char *name;
int age;
char *work;

public:

Person() {cout <<"Pserson()"<<endl;}
Person(char *name)
{
cout <<"Pserson(char *)"<<endl;
this->name = name;
}

Person(char *name, int age, char *work = "none") //Default parameter char *work = "none"
{
cout <<"Pserson(char*, int)"<<endl;
this->name = name;
this->age = age;
this->work = work;
}

\t
void setName(char *n)
{
name = n;
}
int setAge(int a)
{
if (a < 0 || a > 150)
{
age = 0;
return -1;
}
age = a;
return 0;
}
void printInfo(void)
{
//printf("name = %s, age = %d, work = %s\\
", name, age, work);
cout<<"name = "<<name<<", age = "<<age<<", work = "<<work<<endl;
}
};

int main(int argc, char **argv)
{
Person per("zhangsan", 16); //No work is passed in, the default is none
Person per2;
Person per3();

Person *per4 = new Person;
Person *per5 = new Person();

Person *per6 = new Person[2];

Person *per7 = new Person("lisi", 18, "student");
Person *per8 = new Person("wangwu", 18);

per.printInfo();
per7->printInfo();
per8->printInfo();

delete per4;
delete per5;
delete []per6;
delete per7;
delete per8;

return 0;
}

4. Instantiate objects – operate with pointers

 Person *per4 = new Person;
Person *per5 = new Person();
    //These two methods have exactly the same effect. They will call the no-argument constructor of the Person class to instantiate the object.

Person *per6 = new Person[2]; //The array should call the parameterless constructor twice? ? ? ? ?

Person *per7 = new Person("lisi", 18, "student");//Call the constructor with 2 parameters
Person *per8 = new Person("wangwu", 18); //work is none, calling the constructor with 2 parameters

    //How to release dynamically created objects?
    //The program will be automatically released after execution.
    //Manual release, use delete

delete per4;
delete per5;
delete []per6; //For array
delete per7;
delete per8;

5.Improvements

In the previous program, name and work both point directly to a string.

Modify the constructor, allocate space, and save these variables

#include <iostream>
#include <string.h>

using namespace std;

class Person {
private:
char *name;
int age;
char *work;

public:

Person() {cout <<"Pserson()"<<endl;}
Person(char *name)
{
cout <<"Pserson(char *)"<<endl;
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
}

Person(char *name, int age, char *work = "none")
{
cout <<"Pserson(char*, int)"<<endl;
this->age = age;

this->name = new char[strlen(name) + 1];
strcpy(this->name, name);

this->work = new char[strlen(work) + 1];
strcpy(this->work, work);
}

\t
void setName(char *n)
{
name = n;
}
int setAge(int a)
{
if (a < 0 || a > 150)
{
age = 0;
return -1;
}
age = a;
return 0;
}
void printInfo(void)
{
//printf("name = %s, age = %d, work = %s\\
", name, age, work);
cout<<"name = "<<name<<", age = "<<age<<", work = "<<work<<endl;
}
};

int main(int argc, char **argv)
{
Person per("zhangsan", 16);
Person per2;
Person per3();

Person *per4 = new Person;
Person *per5 = new Person();

Person *per6 = new Person[2];

Person *per7 = new Person("lisi", 18, "student");
Person *per8 = new Person("wangwu", 18);

per.printInfo();
per7->printInfo();
per8->printInfo();

delete per4;
delete per5;
delete []per6;
delete per7;
delete per8;

return 0;
}

6. Defect, introduction of destructor

The heap space was allocated using the new function in the constructor, but it was not released.

Instantiate the object in the main function. After the program exits, the system will help release the space.

But what if the object is instantiated in a sub-function?

Put the above main function code into a test function

void test_fun()
{
Person per("zhangsan", 16);
Person per2;
Person per3();

Person *per4 = new Person;
Person *per5 = new Person();

Person *per6 = new Person[2];

Person *per7 = new Person("lisi", 18, "student");
Person *per8 = new Person("wangwu", 18);

//per.printInfo();
//per7->printInfo();
//per8->printInfo();

delete per4;
delete per5;
delete []per6;
delete per7;
delete per8;

}

int main(int argc, char **argv)
{
for (int i = 0; i < 1000000; i + + )
test_fun(); //Executed 1,000,000 times, it will consume about 200M memory
cout << "run test_fun end"<<endl;
sleep(10);
return 0;
}

free -m View memory

a. Check the remaining 2538M of memory before execution.

b. After execution, print “run test_fun end”, and the remaining memory is 2356M.

c.sleep(10); The memory automatically restores to 2538M

Note: After the program exits, the system will help release the space allocated by the new function.

However, during the continuous execution of test_fun, the space allocated by new is not released.

a. Calling per7.freebuff(); per8.freebuff(); in test_fun is not a good way

void freebuff()
{
    delete this->name;
    delete this->work;
}

b. Destructor, do some cleanup work

 ~Person()
{
cout << "~Person()"<<endl;
if (this->name)
cout << "name = "<<name<<endl;
delete this->name;
if (this->work)
cout << "work = "<<work<<endl;
delete this->work;
}

In this way, too much memory is not consumed during the hibernation process, and there is no need to wait for the program to exit before releasing the memory.

When does it work? Moments before the instantiated object is destroyed, the system helps call the destructor

There are many constructors and only one destructor with no parameters

7. Experiment a

void test_fun()
{
Person per("zhangsan", 16);

Person *per7 = new Person("lisi", 18, "student");
delete per7;

}

int main(int argc, char **argv)
{
test_fun();
cout << "run test_fun end"<<endl;
sleep(10);
return 0;
}

Output result:
?
~Person()
name = lisi
work=student
?~Person()
name=zhangsan
work=none
run test_fun end

Delete first

7. Experiment b

void test_fun()
{
Person per("zhangsan", 16);

Person *per7 = new Person("lisi", 18, "student");
//delete per7;

}

int main(int argc, char **argv)
{
test_fun();
cout << "run test_fun end"<<endl;
sleep(10);
return 0;
}

Output result:
?
?~Person()
name=zhangsan
work=none
run test_fun end

Only Zhangsan’s destructor was executed. After the entire program exited, lisi’s destructor was not called.

Indicates that the space allocated by the new function must be manually released using the delete function.

If there is no manual release, the system will help release, but the destructor will not be called.

Recommendation: The object instantiated by the new function must be manually released using the delete function.