C++面向工具编程入门:结构函数与析构函数
副标题#e#
请留意,这一节内容是c++的重点,要出格留意!
我们先说一下什么是结构函数。
上一个教程我们简朴说了关于类的一些根基内容,对付类工具成员的初始化我们始终是成立成员函数然后手工挪用该函数对成员举办赋值的,那么在c++中对付类来说有没有更利便的方法可以或许在工具建设的时候就自动初始化成员变量呢,这一点对操纵掩护成员是至关重要的,谜底是必定的。关于c++类成员的初始化,有专门的结构函数来举办自动操纵而无需要手工挪用,在正式讲授之前先看看c++对结构函数的一个根基界说。
1.C++划定,每个类必需有默认的结构函数,没有结构函数就不能建设工具。
2.若没有提供任何结构函数,那么c++提供自动提供一个默认的结构函数,该默认结构函数是一个没有参数的结构函数,它仅仅认真建设工具而不做任何赋值操纵。
3.只要类中提供了任意一个结构函数,那么c++就不在自动提供默认结构函数。
4.类工具的界说和变量的界说雷同,利用默认结构函数建设工具的时候,假如建设的是静态可能是全局工具,则工具的位模式全部为0,不然将会是随即的。
我们来看下面的代码:
#include <iostream>
using namespace std;
class Student
{
public:
Student()//无参数结构函数
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
};
void Student::show()
{
cout<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
cin.get();
}
在类中的界说的和类名沟通,而且没有任何返回范例的Student()就是结构函数,这是一个无参数的结构函数,他在工具建设的时候自动挪用,假如去掉Student()函数体内的代码那么它和c++的默认提供的结构函数等价的。
#p#副标题#e#
结构函数可以带任意多个的形式参数,这一点和普通函数的特性是一样的!
下面我们来看一个带参数的结构函数是如何举办工具的始化操纵的。
代码如下:
#include <iostream>
using namespace std;
class Teacher
{
public:
Teacher(char *input_name)//有参数的结构函数
{
name=new char[10];
//name=input_name;//这样赋值是错误的
strcpy(name,input_name);
}
void show();
protected:
char *name;
};
void Teacher::show()
{
cout<<name<<endl;
}
void main()
{
//Teacher a;//这里是错误的,因为没有无参数的结构函数
Teacher a("test");
a.show();
cin.get();
}
我们建设了一个带有字符指针的带有形参的Teacher(char *input_name)的结构函数,挪用它建设工具的利用类名加工具名称加扩号和扩号内参数的方法挪用,这和挪用函数有点雷同,但意义也有所差异,因为结构函数是为建设工具而设立的,这里的意义不光纯是挪用函数,而是建设一个类工具。
一旦类中有了一个带参数的结构函数而又没无参数结构函数的时候系统将无法建设不带参数的工具,所以上面的代码
Teacher a;
就是错误的!!!
这里尚有一处也要留意:
//name=input_name;//这样赋值是错误的
因为name指是指向内存堆区的,假如利用name=input_name;会造成指针指向改变不是指向堆区而是指向栈区,导致在后头挪用析构函数delete释放堆空间堕落!(析构函数的内容我们后头将要先容)
假如需要挪用可以或许执行就需要再添加一个没有参数的结构函数
对上面的代码改革如下:
#include <iostream>
using namespace std;
class Teacher
{
public:
Teacher(char *input_name)
{
name=new char[10];
//name=input_name;//这样赋值是错误的
strcpy(name,input_name);
}
Teacher()//无参数结构函数,举办函数重载
{
}
void show();
protected:
char *name;
};
void Teacher::show()
{
cout<<name<<endl;
}
void main()
{
Teacher test;
Teacher a("test");
a.show();
cin.get();
}
建设一个无叙述的同名的Teacher()无参数函数,一重载方法区分挪用,由于结构函数和普通函数一样具有重载特性所以编写措施的人可以给一个类添加任意多个结构函数,来利用差异的参数来举办初始话工具。
#p#分页标题#e#
此刻我们来说一下,一个类工具是别的一类的数据成员的环境,假如有点以为饶人那么可以简朴领略成:类成员的界说可以彼此嵌套界说,一个类的成员可以用另一个类举办界说声明。
c++划定假如一个类工具是别的一类的数据成员,那么在建设工具的时候系统将自动挪用谁人类的结构函数。
下面我们看一个例子。
代码如下:
#include <iostream>
using namespace std;
class Teacher
{
public:
Teacher()
{
director = new char[10];
strcpy(director,"王大力大举");
}
char *show();
protected:
char *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student()
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher;//这个类的成员teacher是用Teacher类举办建设并初始化的
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
Student b[5];
for(int i=0; i<sizeof(b)/sizeof(Student); i++)
{
b[i].show();
}
cin.get();
}
上面代码中的Student类成员中teacher成员是的界说是用类Teacher举办界说建设的,那么系统遇到建设代码的时候就会自动挪用Teacher类中的Teacher()结构函数对工具举办初始化事情!
这个例子说明类的分工很明晰,只有遇到本身的工具的建设的时候才本身挪用本身的结构函数。
一个类大概需要在结构函数内动态分派资源,那么这些动态开发的资源就需要在工具不复存在之前被销毁掉,那么c++类的析构函数就提供了这个利便。
析构函数的界说:析构函数也是非凡的类成员函数,它没有返回范例,没有参数,不能随意挪用,也没有重载,只有在类工具的生命期竣事的时候,由系统自动挪用。
析构函数与结构函数最主要大差异就是在于挪用期差异,结构函数可以有参数可以重载!
我们前面例子中的Teacher类中就利用new操纵符举办了动态堆内存的开发,由于上面的代码缺少析构函数,所以在措施竣事后,动态开发的内存空间并没有跟着措施的竣事而小时,假如没有析构函数在措施竣事的时候逐一排除被占用的动态堆空间那么就会造成内存泄露,使系统内存不绝淘汰系统效率将大大低落!
那么我们将如何编写类的析构函数呢?
析构函数可以的特性是在措施竣事的时候逐一挪用,那么正好与结构函数的环境是相反,属于互逆特性,所以界说析构函数因利用"~"标记(逻辑非运算符),暗示它为腻结构函数,加上类名称来界说。
看如下代码:
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
Teacher()
{
director = new char[10];
strcpy(director,"王大力大举");
//director = new string;
// *director="王大力大举";//string环境赋值
}
~Teacher()
{
cout<<"释放堆区director内存空间1次";
delete[] director;
cin.get();
}
char *show();
protected:
char *director;
//string *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student()
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher;
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
Student b[5];
for(int i=0; i<sizeof(b)/sizeof(Student); i++)
{
b[i].show();
}
cin.get();
}
上面的代码中我们为Teacher类添加了一个名为~Teacher()的析构函数用于清空堆内存。
发起各人编译运行代码调查挪用环境,措施将在竣事前也就是工具生命周期竣事的时候自动挪用~Teacher()
~Teache()中的delete[] director;就是排除堆内存的代码,这与我们前面一开始提到的。
name=input_name;//这样赋值是错误的
有直接的干系,因为delete操纵符只能清空堆空间而不能清楚桟空间,假如强行排除栈空间内存的话将导致措施瓦解!
#p#分页标题#e#
前面我们已经简朴的说了类的结构函数和析构函数,我们知道一个类的成员可以是别的一个类的工具,结构函数答允带参数,那么我们大概会想到上面的措施我们可以在类中把Student类中的teacher成员用带参数的形式挪用Student类的结构函数,不须要再在Teacher类中举办操纵,由于这一点构思我们把措施修改成如下形式:
#include <iostream>
#include <string>
using namespace std;
class Teacher
{
public:
Teacher(char *temp)
{
director = new char[10];
strcpy(director,temp);
}
~Teacher()
{
cout<<"释放堆区director内存空间1次";
delete[] director;
cin.get();
}
char *show();
protected:
char *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student()
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher("王大力大举");//错误,一个类的成员假如是别的一个类的工具的话,不能在类中利用带参数的结构函数举办初始化
};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a;
a.show();
Student b[5];
for(int i=0; i<sizeof(b)/sizeof(Student); i++)
{
b[i].show();
}
cin.get();
}
但是很遗憾,措施不可以或许被编译乐成,为什么呢?
因为:类是一个抽象的观念,并不是一个实体,并不能包括属性值(这里来说也就是结构函数的参数了),只有工具才占有必然的内存空间,含有明晰的属性值!
这一个问题是类成员初始化较量难过的一个问题,是不是就没有步伐办理了呢?呵呵。。。。。。
c++为了办理此问题,有一个很奇特的要领,下一小节我们将先容。
对付上面的谁人"难过"问题,我们可以在结构函数头的后头加上:号并指定挪用哪谁人类成员的结构函数来办理!
教程写到这里的时候比拟了许多书籍,发明险些所有的书都把这一章节叫做结构类成员,笔者在此以为有所不当,因为从读音上容易夹杂观念,所以把这一小节的名称改为结构类的成员较量符合!
代码如下:
#include <iostream>
using namespace std;
class Teacher
{
public:
Teacher(char *temp)
{
director = new char[10];
strcpy(director,temp);
}
~Teacher()
{
cout<<"释放堆区director内存空间1次";
delete[] director;
cin.get();
}
char *show();
protected:
char *director;
};
char *Teacher::show()
{
return director;
}
class Student
{
public:
Student(char *temp):teacher(temp)
{
number = 1;
score = 100;
}
void show();
protected:
int number;
int score;
Teacher teacher;};
void Student::show()
{
cout<<teacher.show()<<endl<<number<<endl<<score<<endl;
}
void main()
{
Student a("王大力大举");
a.show();
//Student b[5]("王大力大举"); //这里这么用是差池的,数组不可以或许利用带参数的结构函数,今后我们将具体先容vector范例
// for(int i=0; i<sizeof(b)/sizeof(Student); i++)
//{
// b[i].show();
/