C++中类的构造函数和析构函数

c++的目标之一是让使用类对象就像使用标准类型一样。

为什么使用构造函数?

        数据的初始化是非常重要的,未经初始化的数据很多情况下都不是期望的结果,很多忘记初始化的数据是导致错误的根源。构造函数就是提供了一个初始化的地方,可以把初始化数据的代码写在构造函数里。当然允许你可以不写在构造函数里,可以自定义一个方法再去调用,不过构造函数的方便之处在于只要创建了对象,就会自动地调用构造函数,保证不会忘记调用。这才是使用构造函数的根本目的。

        构造函数的原型和函数头有一个有趣的特征—虽然没有返回值,但没有被声明为void类型。实际上,构造函数没有声明类型。

class Stock
{
private:
	std::string company;
	long shares;
	double share_val;
	double total_val;
	void set_tot() { total_val = shares * share_val; }
public:
	void acquire(const std::string &co, long n, double pr);
	void buy(long num. double price);
	void sell(long num, double price);
	void update(double price);
	void show()
};

        由于需要为Stock对象提供3个值,因此应为构造函数提供3个参数。其中一种原型可以是

Stock::Stock(const string& co,long n=0,double pr=0.0)

注意:

Stock::Stock(const string& company,long shares,double share_val)

这种表示是错误的。构造函数的参数表示的不是类成员,而是赋给类成员的值。因此,参数名不能与类成员相同。

为避免这种混乱,一种常见的做法是在数据成员名中使用m_前缀,另一种常见的做法是在成员名中使用后缀_。如

std::string m_company; long m_shares;
std::string company_; long shares_;

使用构造函数

       C++提供了两种使用构造函数来初始化对象的方式。

第一种是显式地调用构造函数:

Stock garment = Stock("Furry Mason", 50, 2.5);

第二种是隐式地调用构造函数:

Stock garment("Furry Mason", 50, 2.5);

构造函数与new一起使用的方法:

Stock *pstock = new Stock("Furry Mason", 50, 2.5);

这条语句创建一个Stock对象,将其初始化为参数提供的值,并将该对象的地址赋给pstock指针。在这种情况下,对象没有名称,但可以使用指针来管理该对象。

        一般来说,使用对象来调用方法,但无法使用对象来调用构造函数,因为在构造函数构造出对象之前,对象是不存在的。因此构造函数被用来创建对象,而不能通过对象来调用。

默认构造函数

        默认构造函数是在未提供显示初值时,用来创建对象的构造函数。例如

Stock garment;

        如果没有提供任何构造函数,则C++将自动提供默认构造函数。它是默认构造函数的隐式版本,不做任何工作。对于Stock类来说,默认构造函数可能如下:

Stock::Stock() { }

因此将创建garment对象,但不初始化其成员,类似于 int x;

        当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。为类定义了构造函数后,程序员就必须为它提供默认构造函数。如果提供了非默认构造函数,如Stock::Stock(const string& co,long n=0,double pr=0.0),但没有提供默认构造函数,则下面的声明将出错:

Stock stock1; //not possible with current constructor

        这样做的原因可能是想禁止创建未初始化的对象。然而,要创建对象,而不显式地初始化,则必须定义一个不接受任何参数的默认构造函数。定义默认构造函数的方式有两种。一种是给已有构造函数的所有参数提供默认值:

Stock::Stock(const string& co = "Error", int n = 0, double pr = 0.0);

另一种方式是通过函数重载来定义另一个构造函数—一个没有参数的构造函数:

Stock::Stock();

        实际上,通常应初始化所有的对象,以确保所有成员一开始就有已知的合理值。因此用户定义的默认构造函数通常给所有成员提供隐式初始值。如下:

Stock::Stock()
{
	company = "no name";
	shares = 0;
	share_val = 0.0;
	total_val = 0.0
}

在设计类时,通常应提供对所有类成员做隐式初始化的默认构造函数。


析构函数

        用构造函数创建对象后,程序负责跟踪该对象,直到其过期为止。对象过期时,程序将自动调用析构函数。析构函数完成清理工作,因此实际上很有用。例如,如果构造函数使用new来分配内存,则析构函数将使用delete来释放这些内存。Stock的构造函数没有使用new,因此析构函数实际上没有需要完成的任务。在这种情况下,只需让编译器生成一个什么都不做的隐式析构函数即可。

        析构函数和构造函数一样,没有返回值和声明类型。与构造函数不同的是,析构函数没有参数。

Stock::~Stock()
{
}

        由于在类对象过期时析构函数将自动被调用,因此必须有一个析构函数。如果程序员没有提供析构函数,编译器将隐式地声明一个默认析构函数,并在发现导致对象呗删除的代码后,提供默认析构函数的定义。

对于使用下面这种语法创建并初始化一个名为garment的对象,首先编译器会调用构造函数来创建一个临时对象,然后将该临时对象复制到garment中,并丢弃它。此时编译器将为临时对象调用析构函数。

Stock garment = Stock("Furry Mason", 50, 2.5);

猜你喜欢

转载自blog.csdn.net/wxn704414736/article/details/80192544