构造函数和析构函数是C ++中类概念的基础。构造函数和析构函数都或多或少类似于提供用于增强类功能的常规函数(但有一些区别)。
顾名思义,构造函数用于分配内存(如果需要)并构造类的对象,而析构函数用于在销毁类对象时进行所需的清理。在本文中,我们将通过工作示例研究构造函数和析构函数的概念。
如果您不熟悉C ++,则应首先了解C ++的概念。 C ++类 .
构造函数和析构函数
让’通过以下示例了解构造函数和析构函数的概念:
#include<iostream> class 国家 { public: 国家 () { std::cout<<"\n Constructor called \n"; } void setNumOfCities(int num); int getNumOfCities(void); ~country() { std::cout<<"\n Destructor called \n"; } private: int num_of_cities; }; void 国家 ::setNumOfCities(int num) { num_of_cities = num; } int 国家 ::getNumOfCities(void) { return num_of_cities; } int main(void) { 国家 obj; int num = 5; obj.setNumOfCities(num); num = obj.getNumOfCities(); std::cout<<"\n Number of cities is equal to "<<num; return 0; }
在上面的示例中:
- 班级的名字是 国家 .
- 请注意,有两个函数与类具有相同的名称,即国家/地区。
- 具有一个功能‘~’名称之前是析构函数,而另一个是构造函数。
正如我们已经讨论过的,构造函数用于创建对象。确切地说,构造函数是一个特殊的函数,当创建类的对象时会自动调用该函数。同样,析构函数是一个特殊的函数,当删除类对象或超出范围时会自动调用它。
让’通过执行上面显示的代码,验证以上给出的解释。
这是在3d捕鱼达人上编译C ++代码的方式:
$ g++ -Wall cnstrDestr.cpp -o cnstrDestr $
因此,我们看到我们使用g ++编译器来编译c ++代码,在本例中,该代码已编译而没有任何警告或错误。现在让’s execute the code :
$ ./cnstrDestr Constructor called Number of cities is equal to 5 Destructor called
观察到在创建类的对象时,将执行该类的构造函数,并且在该对象即将销毁时,将调用析构函数。因此,这确认了这些特殊功能是在内部或自动(从开发人员’s point of view).
现在有人问’这些功能的实际作用是什么?在哪些情况下确实需要它们?
好了,要回答这个问题,我们假设在同一程序(如上所示)中,对setNumOfCities()和getNumOfCities()的调用是互换的。这意味着,现在代码尝试在设置之前获取值。
这是更新的代码:
#include<iostream> class 国家 { public: 国家 () { std::cout<<"\n Constructor called \n"; } void setNumOfCities(int num); int getNumOfCities(void); ~country() { std::cout<<"\n Destructor called \n"; } private: int num_of_cities; }; void 国家 ::setNumOfCities(int num) { num_of_cities = num; } int 国家 ::getNumOfCities(void) { return num_of_cities; } int main(void) { 国家 obj; int num = 5; num = obj.getNumOfCities(); obj.setNumOfCities(num); std::cout<<"\n Number of cities is equal to "<<num; return 0; }
执行此代码后,输出如下:
$ ./cnstrDestr Constructor called Number of cities is equal to 134514633 Destructor called
观察到在输出中产生了一些垃圾值。这是因为变量的值‘num_of_cities’甚至在没有赋值之前就被获取了。现在,可能有什么解决方案?可以考虑使用类本身中的某些默认值初始化变量。
就像是 :
#include<iostream> class 国家 { public: 国家 () { std::cout<<"\n Constructor called \n"; } void setNumOfCities(int num); int getNumOfCities(void); ~country() { std::cout<<"\n Destructor called \n"; } private: int num_of_cities = 0; }; void 国家 ::setNumOfCities(int num) { num_of_cities = num; } int 国家 ::getNumOfCities(void) { return num_of_cities; } int main(void) { 国家 obj; int num = 5; num = obj.getNumOfCities(); obj.setNumOfCities(num); std::cout<<"\n Number of cities is equal to "<<num; return 0; }
Well, can we do this? 让’编译此代码并验证:
$ g++ -Wall cnstrDestr.cpp -o cnstrDestr cnstrDestr.cpp:23:25: error: ISO C++ forbids initialization of member ‘num_of_cities’ [-fpermissive] cnstrDestr.cpp:23:25: error: making ‘num_of_cities’ static [-fpermissive] cnstrDestr.cpp:23:25: error: ISO C++ forbids in-class initialization of non-const static member ‘num_of_cities’
好吧,编译器抛出错误,抱怨说这不能完成,因为该变量是非静态的。因此,这不是正确的处理方式。那么如何用默认值初始化变量呢?是的,您通过构造函数猜测它是正确的。由于构造函数也是类的成员函数,因此它们可以访问类私有数据成员。
这是可以做到的:
#include<iostream> class 国家 { public: 国家 () { num_of_cities = 0; std::cout<<"\n Constructor called \n"; } void setNumOfCities(int num); int getNumOfCities(void); ~country() { std::cout<<"\n Destructor called \n"; } private: int num_of_cities; }; void 国家 ::setNumOfCities(int num) { num_of_cities = num; } int 国家 ::getNumOfCities(void) { return num_of_cities; } int main(void) { 国家 obj; int num = 5; num = obj.getNumOfCities(); obj.setNumOfCities(num); std::cout<<"\n Number of cities is equal to "<<num; return 0; }
现在让’s编译并执行以上代码:
$ g++ -Wall cnstrDestr.cpp -o cnstrDestr $ ./cnstrDestr Constructor called Number of cities is equal to 0 Destructor called
观察到编译成功并且产生了预期的输出。因此,这应该使您对构造函数和析构函数的功能有了一个很好的了解。
在现实世界中,构造函数用于初始化类的数据成员,最重要的是将内存分配给 指针 和析构函数用于清除此内存。
这是一个例子:
#include<iostream> class 国家 { public: 国家 () { num_of_cities = new(int); std::cout<<"\n Constructor called \n"; } void setNumOfCities(int num); int getNumOfCities(void); ~country() { if(num_of_cities) delete num_of_cities; std::cout<<"\n Destructor called \n"; } private: int *num_of_cities; }; void 国家 ::setNumOfCities(int num) { *num_of_cities = num; } int 国家 ::getNumOfCities(void) { return (*num_of_cities); } int main(void) { 国家 obj; int num = 5; obj.setNumOfCities(num); num = obj.getNumOfCities(); std::cout<<"\n Number of cities is equal to "<<num; return 0; }
以下是有关构造函数和析构函数的一些要点:
- 每当创建和销毁(或超出范围)类对象时,就会调用它们。
- 构造函数和析构函数通常在范围上保持公开。
- 构造函数和析构函数的名称与类的名称相同,并且没有返回类型。这意味着它们不能像其他任何普通函数一样返回值。
- 如果未显式提供构造函数或析构函数,则编译器会在内部生成一个。
- 如果在类中显式声明了默认构造函数,则该默认构造函数是不接受任何自变量或具有默认值的自变量的构造函数。
- 构造函数和析构函数不能被继承。
- 构造函数可以重载。
- 析构函数不能接受参数。
注意,我们还没有介绍C ++中的继承概念。在讨论继承时,我们将详细讨论构造函数和析构函数的一些特征。
如果您喜欢这篇文章,您可能还会喜欢..
![]() |
![]() |
![]() |
![]() |
很棒的文章。谢谢!!!