A class constructor is a function that places data into a class object and performs any other set up for a class object that needs to be performed when a class object is first instantiated. In this article, I’ll demonstrate how to create and use several different types of class constructors.
类构造函数是将数据放入类对象并为该类对象执行任何其他设置的函数,该类对象在首次实例化该类对象时需要执行。 在本文中,我将演示如何创建和使用几种不同类型的类构造函数。
I’m going to demonstrate how to create and use constructors using a class definition I developed in my previous article, which was an introduction to C++ classes. Here is the class definition I’ll be starting from:
我将演示如何使用我在上一篇文章中开发的类定义(它是C ++类的简介)来创建和使用构造函数。 这是我将从这里开始的类定义:
class Date {
private:
int month, day, year;
string adjustDate(int d) {
string date;
if (d < 10) {
date = "0" + to_string(d);
}
else {
date = to_string(d);
}
return date;
}public:
void display() {
string date = adjustDate(month) + "/" + adjustDate(day)
+ "/" + adjustDate(year);
cout << date;
} void setMonth(int m) {
month = m;
} void setDay(int d) {
day = d;
} void setYear(int y) {
year = y;
}
};
构造函数概述 (An Overview of Constructors)
A constructor function is used to initialize the member variables of a class and to perform any other set-up operations that need to be performed when a class object is instantiated. A class can have multiple constructors based on the needs of the class. Constructors must have the same name as the class.
构造函数用于初始化类的成员变量,并执行在实例化类对象时需要执行的任何其他设置操作。 根据类的需要,一个类可以具有多个构造函数。 构造函数必须与该类具有相同的名称。
There are two types of constructors most classes need to have. The first type is a default constructor. The default constructor initializes all class member variables to their default values, so that integer variables get 0s, string variables get the empty string, and so on.
大多数类需要具有两种类型的构造函数。 第一种类型是默认构造函数。 默认构造函数将所有类成员变量初始化为其默认值,以便整数变量获取0,字符串变量获取空字符串,依此类推。
The second constructor type most classes will have is the fully-parameterized constructor. This constructor has this name because there is a function parameter for every member variable of the class.
大多数类将具有的第二个构造函数类型是完全参数化的构造函数。 该构造函数之所以具有此名称,是因为该类的每个成员变量都有一个函数参数。
In between these two constructors, can be other constructors depending on the needs of the class. For example, the Date
class might provide a constructor that just sets the month and the year and sets the day to its default value.
在这两个构造函数之间,可以根据类的需要使用其他构造函数。 例如, Date
类可以提供一个构造函数,该构造函数仅设置月份和年份并将日期设置为其默认值。
默认构造函数 (Default Constructors)
The first type of constructor I’ll discuss is the default constructor. A default constructor assigns default values for the member variables of a class. For the Date
class, the values for each member variable will be 0. Here is one definition of a default constructor for the Date
class:
我将讨论的第一种构造函数是默认构造函数。 默认构造函数为类的成员变量分配默认值。 对于Date
类,每个成员变量的值为0。这是Date
类的默认构造函数的一个定义:
Date() {
month = 0;
day = 0;
year = 0;
}
We can shorten this definition using an advanced C++ feature often found when defining function and class templates. Here is the shorter definition:
我们可以使用定义函数和类模板时经常使用的高级C ++功能来缩短此定义。 这是简短的定义:
Date() {
month = day = year = {};
}
The compiler will examine the type of the variable on the left-hand side of the assignment statement and assign the type’s default value to the variable.
编译器将在赋值语句的左侧检查变量的类型,并将类型的默认值分配给该变量。
Here is how the default constructor is called when instantiating a new Date
object:
实例化新的Date
对象时,以下是默认构造函数的调用方式:
Date today;
In C++, if you don’t provide a default constructor, the compiler will provide one for you but you don’t want to rely on it for accurate data. Here is the output I get when I instantiate a new Date object without defining a default constructor:
在C ++中,如果不提供默认的构造函数,则编译器会为您提供一个默认的构造函数,但您不想依靠它来获取准确的数据。 这是当我实例化一个新的Date对象而不定义默认构造函数时得到的输出:
75/08/67
Clearly those are not default values for integer variables and indicates that C++ accessed the memory locations for the member variables and returned whatever was there. This is why you should always provide a default constructor for your C++ classes.
显然,这些不是整数变量的默认值,表明C ++访问了成员变量的内存位置并返回了那里的所有内容。 这就是为什么您应该始终为C ++类提供默认构造函数的原因。
全参数构造函数 (The Fully-Parameterized Constructor)
The second type of constructor is the fully-parameterized constructor, which means there is a function parameter for every member variable. Here is one version of such a constructor for the Date
class:
构造函数的第二种类型是完全参数化的构造函数,这意味着每个成员变量都有一个函数参数。 这是Date
类的此类构造函数的一个版本:
Date(int m, int d, int y) {
month = m;
day = d;
year = y;
}
I would say this is a barebones constructor because it doesn’t provide the benefits of data encapsulation since the member variables can be set to any valid integer value. What we need are private member functions that perform data validation.
我会说这是一个准系统的构造函数,因为它不能提供数据封装的好处,因为成员变量可以设置为任何有效的整数值。 我们需要的是执行数据验证的私有成员函数。
We already have those functions with setMonth
, setDay
, and setYear
. I’ll change the definition of setDay
, however, to demonstrate how to do data validation in a constructor. First, here is a new definition of setDay
, using a table lookup to determine how many days are in the month:
我们已经有了setMonth
, setDay
和setYear
那些函数。 我将更改setDay
的定义,以演示如何在构造函数中进行数据验证。 首先,这是setDay
的新定义, setDay
使用表查找来确定一个月中有多少天:
private:
…
int monthDays[12] =
{31, 28, 31, 30, 31, 30, 31, 31, 31, 31, 30, 31};
…public:
…
void setDay(int m, int d) {
int daysInMonth = monthDays[m-1];
if (d > 0 && d <= daysInMonth) {
day = d;
}
else {
day = 1;
}
}
Here is the constructor with setDay
added to it:
这是添加了setDay
的构造函数:
Date(int m, int d, int y) {
month = m;
setDay(m, d);
year = y;
}
Here is a program fragment that tests the constructor:
这是测试构造函数的程序片段:
Date today(8,24,2020);
today.display();
Date tomorrow(8,32,2020);
tomorrow.display();
The output from this program fragment is:
该程序片段的输出为:
08/24/2020
08/01/2020
The second date reverts the day to 1 as per the data validation rule in the function definition. This is an arbitrary decision, of course, and the day could have been set to whatever the class designer wanted.
根据功能定义中的数据验证规则,第二个日期将日期还原为1。 当然,这是一个任意决定,并且可以按照班级设计师的要求设置日期。
参数化构造函数 (Parameterized Constructors)
You can overload a class’s constructor functions if the parameter list differs from the others. This means the constructor will have some parameters (at least one) but not one for every member variable as found in the fully-parameterized constructor. These types of constructors are called parameterized constructor.
如果参数列表与其他列表不同,则可以重载类的构造函数。 这意味着构造函数将具有一些参数(至少一个),但对于在完全参数化的构造函数中发现的每个成员变量,则没有一个参数。 这些类型的构造函数称为参数化构造函数。
I can now define Date
class constructors with two parameters and with one parameter. Here are their definitions:
现在,我可以使用两个参数和一个参数定义Date
类的构造函数。 这是它们的定义:
Date(int m, int y) {
month = m;
setDay(m, 0);
year = y;
}Date(int y) {
month = 0;
setDay(0, 0);
year = y;
}
Of course, I would add data validation to those definitions if this were a class I was putting into production.
当然,如果这是我投入生产的一类,我会在这些定义中添加数据验证。
Another thing to keep in mind is that you only need to provide the number of constructors you need to make the class useful. If you want to limit the number of constructors to a default constructor and a fully-parameterized constructor, that is perfectly fine. The decision depends on the needs of the class and your users.
要记住的另一件事是,您只需要提供使类有用的构造函数的数量即可。 如果要将构造函数的数量限制为默认构造函数和完全参数化的构造函数,那完全可以。 该决定取决于班级和您的用户的需求。
复制构造函数 (The Copy Constructor)
There are times when you want to create a new class object by copying an existing class object. You can do this using a copy constructor. This constructor takes an existing class object as an argument and assigns its member variables to the new object being constructed.
有时您想通过复制现有的类对象来创建新的类对象。 您可以使用复制构造函数执行此操作。 该构造函数将现有的类对象作为参数,并将其成员变量分配给正在构造的新对象。
Here is the definition for a copy constructor for the Date
class:
这是Date
类的副本构造函数的定义:
Date(const Date &d1) {
month = d1.month;
setDay(month, d1.day);
year = d1.year;
}
There are a couple things to notice about this definition. First, the parameter is defined as a constant so that the function cannot accidentally make changes to it. Also, the parameter is passed by reference to make the function more effective. It is a good idea to always pass class objects to functions by reference. This saves on the overhead of the compiler having to make a copy of the complete object before using it in the function.
关于此定义,需要注意几件事。 首先,将参数定义为常量,以使函数不会意外对其进行更改。 同样,参数通过引用传递,以使功能更有效。 始终通过引用将类对象传递给函数是一个好主意。 这节省了编译器必须在函数中使用完整对象之前对其进行复制的开销。
Here is a short program fragment that uses the copy constructor:
这是一个使用复制构造函数的简短程序片段:
int main ()
{
Date today(8,24,2020);
today.display();
Date tomorrow(today);
tomorrow.display();
return 0;
}
The output from this program is:
该程序的输出为:
08/24/2020
08/24/2020
构造函数和类定义 (Constructors and Class Definitions)
Constructors are an important part of a class definition and should be designed and built with care as these functions define how new class objects are to be instantiated. The number and type of class constructors you implement for a class will always depend on the needs of the class and the needs of the user, since classes are designed for users to use.
构造函数是类定义的重要组成部分,应谨慎设计和构建,因为这些函数定义了如何实例化新的类对象。 为类实现的类构造函数的数量和类型将始终取决于类的需求和用户的需求,因为类是为用户设计的。
I must mention that I did omit one type of class constructor, the move constructor. I will come back and define what a move constructor does in a later article once we have more experience designing and implementing classes.
我必须提到,我确实省略了一种类型的类构造函数,即move构造函数。 一旦我们有更多的设计和实现类的经验,我将在后面的文章中返回并定义move构造函数的作用。
Thanks for reading this article and please email me at mmmcmillan1@att.net with comments and suggestions. If you are interested in my online programming courses, please visit https://learningcpp.teachable.com.
感谢您阅读本文,请给我发电子邮件mmmmmillan1@att.net并提供评论和建议。 如果您对我的在线编程课程感兴趣,请访问https://learningcpp.teachable.com 。
翻译自: https://levelup.gitconnected.com/learning-c-class-constructors-2aacfd6b7ff7