类的构造函数(C++)

对于Stock类,还有其他的一些工作要做。应为类提供被称为构造函数和析构函数的标准函数。
类不能像结构一样初始化,原因在于,数据部分的访问状态是私有的,这意味着程序不能直接访问数据成员。程序只能通过成员函数来访问数据成员,因此需要设计合适的成员函数,才能成功地将对象初始化(如果使数据成员成为公有,而不是私有,就可以按照结构一样初始化类对象,但使数据称为公有的违背了类的一个主要初衷:数据隐藏)。

一般来说,最好是在创建对象时对它进行初始化。就Stock类当前的实现而言,gift对象的company成员是没有值的。类设计假设用户在调用任何其他成员函数之前调用acquire(),但无法强加这种假设。避开这种问题的方法之一是在创建对象时,自动对它进行初始化。为此,C++提供了一个特殊的成员函数——类构造函数,专门用于构造新对象、将值赋给它们的数据成员。更准确地说,C++为这些成员函数提供了名称和使用语法,而程序员需要提供方法定义。名称于类名相同。例如,Stock类一个可能的构造函数是名为Stock()的成员函数。构造函数的原型和函数头有一个有趣的特征——虽然没有返回值,但没有被声明为void类型。实际上,构造函数没有声明类型。

声明和定义构造函数:

现在需要创建Stock的构造函数。由于需要为Stock对象提供3个值,因此应为构造函数提供3个参数。程序可能只想设置company成员,而将其他值设置为0;这可以使用默认参数来完成。因此,原型如下:

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

第一个参数是指向字符串的指针,该字符串用于初始化成员company。n和pr参数为shares和share_val成员提供值。注意,没有返回类型。原型位于类声明的公有部分。

Stock::Stock(const string &co, long n, double pr) {
	company = co;
	if (n < 0) {
		std::cerr << "Number of shares can't be negative; " << company << " shares set to 0.\n";
		shares = 0;
	}
	else shares = n;
	share_val = pr;
	set_tot();
}

上述代码和前面的函数acquire()相同。区别在于,程序声明对象时,将自动调用构造函数。

注意:不能将类成员名称用作构造函数的参数名,构造函数的参数表示的不是类成员,而是赋给类成员的值。否则最终的代码将是这样的:

shares = shares;

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

使用构造函数:

C++提供了两种使用构造函数来初始化对象的方式。第一种方式是显式地调用构造函数:

Stock food = Stock("World Cabbage", 250 ,1.25);

另一种方法是隐式地调用构造函数:

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

每次创建类对象(甚至使用new动态分配内存)时,C++都是哦那个类构造函数。下面是将构造函数与new一起使用的方法:

Stock *pstock = new Stock("Electroshock Games", 18, 19.0);

这条语句创建一个Stock对象,将其初始化为参数提供的值,并将该对象的地址赋给pstock指针。在这种情况下,对象没有名称,但可以使用指针来管理该对象。
构造函数的使用方式不同于其他类方法。一般来说,使用对象来调用方法,但无法使用对象来调用构造函数,因为在构造函数构造出对象之前,对象是不存在的。因此构造函数被用来创建对象,而不能通过对象来调用。

默认构造函数:

默认构造函数是在未提供显式初始值时,用来创建对象的构造函数。也就是说,它是用与下面这种声明的构造函数:

Stock fluffy_the_cat;

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

Stock::Stock() { }

因此将创建fluffy_the_cat对象,但不初始化其成员。默认构造函数没有参数,因为声明中不包含值。
奇怪的是,当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。为类定义了构造函数后,程序员就必须为它提供默认构造函数。如果提供了非默认构造函数,但没有提供默认构造函数,则下面的声明将出错:

Stock stock1;

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

Stock(const string &co = "error", long n = 0, double pr = 0.0);

另一种方式是通过函数重载来定义另一个构造函数——一个没有参数地构造函数。
由于只能有一个默认构造函数,因此不要同时使用这两种方式。实际上,通常应初始化所有的对象,以确保所有成员一开始就有已知的合理值。因此,用户定义的默认构造函数通常给所有成员提供隐式初始值。例如:

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

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

使用上述任何一种方式(没有参数或所有参数都有默认值)创建了默认构造函数后,便可以声明对象变量,而不对它们进行显式初始化:

Stock first;	//call default constructor implicitly
Stock first = Stock();	//call it explicitly
Stock *prelief = new Stock;	//call it implicitly

然而,不要被非默认构造函数的隐式形式所误导:

Stock first("Concrete Conglomerate");	//call constructor
Stock second();	//declares a function
Stock third;	//call default constructor

第一个声明调用非默认构造函数,即接受参数的构造函数;第二个声明指出,second()是一个返回Stock对象的函数。隐式地调用默认构造函数时,不要使用圆括号。

声明:以上整理自个人理解和Stephen Prata 著的《C++ Primer Plus》

猜你喜欢

转载自blog.csdn.net/MoooLi/article/details/82749897