类的构造函数与析构函数
为什么需要构造函数与析构函数
C++的目标之一是让使用类对象就像使用标准类型一样,因此我们希望可以像初始化int或结构体那样来初始化Stock对象,而常规的初始化语法并不适用于类型Stock。
int year = 2001;
struct thing
{
char * pn;
int m;
};
thing amabob = {"wodget", -23};
Stock hot = {"xxxxx", 200,50.25}; // No! compile error
不能像初始化int或结构体那样来初始化对象的原因在于,数据的访问状态是私有的,这意味着程序不能直接访问数据成员(如果使用数据成员是公有的,就可以按照上述的方法初始化类对象),因此需要设计合适的成员函数,才能成功地将对象初始化。
一般来说,最好在创建对象时对它进行初始化。为此C++提供了一个特殊的成员函数–类构造函数,专门用于构造新对象、将值赋给它们的数据成员。更准确地说,C++为这些成员函数提供了名称和使用语法,而程序员需要提供方法定义,名称与类名相同。
1. 构造函数
1.1 声明和定义
需要注意构造函数中的参数名应避免与类成员相同
void Stock::Stock(const std::string & co, long n, double pr)
{
company = co;
if (n < 0)
{
std::cout << "Number of shares can't be negative; "
<< company << " shares set to 0.\n";
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
1.2 使用构造函数
构造函数用来初始化类里面的数据成员,C++提供了两种使用构造函数来初始化对象的方式。第一种方式是显式地调用构造函数:
Stock food = Stock("World Cabbage", 250, 1.25);
另一种方式是隐式地调用构造函数:
Stock garment("Furry Mason", 50, 2.5);
我们也可以将构造函数与new一起使用:
Stock *pstock = new Stock("Furry Mason", 50, 2.5);
这条语句创建一个Stock对象,将其初始化为参数提供的值,并将该对象的地址赋给pstock指针。在这种情况下,对象没有名字,但可以使用指针来管理该对象。
1.3 默认构造函数
默认构造函数是在未提供显式初始值时,用来创建对象的构造函数。也就是说,它是用于下面这种声明的构造函数:
Stock fluffy_the_cat; // uses the default constructor
如果类没有提供任何构造函数,则C++将自动提供默认构造函数。它是默认构造函数的隐式版本,不做任何工作。对于Stock类来说,默认构造函数可能如下:
Stock::Stock(){}
如何定义默认的构造函数
定义默认构造函数的方式有两种。一种是给已有构造函数的所有参数提供默认值:
Stock(const std::string & co = "Error", long n = 0, double pr = 0.0);
另一种方式是通过函数重载来定义另一个构造函数–一个没有参数的构造函数:
Stock();
Stock first; // 默认构造函数
Stock first = Stock(); // 显式的调用构造函数
Stock *prelief = new Stock; // 隐式的调用构造函数
Stock first("vvvvvvvvv"); // 默认构造函数
Stock second(); // x
Stock third;
需要注意区别,第一个声明调用非默认构造函数;第二个声明指出second()是一个返回Stock对象的函数。隐式地调用构造函数时,不要用圆括号。
2. 析构函数
用构造函数创建对象后,程序负责跟踪该对象,直到过期为止。对象过期时程序将自动调用一个特殊的成员函数,即析构函数。
析构函数的原型必须是下述这样:
~Stock();
如果既可以通过初始化,也可以通过赋值来设置对象的值,则应采用初始化方式。通常这种方式效率更高。
Stock stock1 = Stock("sss", 2, 2.0); // 初始化
stock2 = Stock("sww", 10, 2.0); // 赋值