目录
1、构造函数的作用与特性
C++的目标之一是使用类对象就像使用标准变量一样。标准变量可以在声明时进行初始化,那对于类对象,在声明时如何初始化呢,这就需要用到构造函数了。
为保证数据的隐藏,类中的数据成员往往都是私有的,因此程序无法直接访问类的数据成员,程序只能通过成员函数来访问私有数据成员,所以需要设计合适的成员函数才能将对象初始化。
C++的类提供了一个特殊的成员函数——类的构造函数,专门用于构造新对象,将值赋给它们的数据成员。在创建对象时,类的构造函数会被自动调用,用来对对象的数据成员初始化。
构造函数的两个重要特性:
- 构造函数的函数名称与类名相同,且构造函数没有返回值和声明类型;
- 构造函数被用来创建对象,它不能通过对象来调用;
2、构造函数的声明
在上篇文章《【和春笋一起学C++】(三十五)类的使用实例》中,Student类声明中提供了类的构造函数,即函数名为Student的成员函数,位于类声明的公有部分,并且没有返回类型,很多同学应该也注意到了该函数,很有特点。为方便阅读,本文还是把Student类的完整声明贴出来吧。
#pragma once
#include <iostream>
class Student
{
public:
Student();
~Student();
void scoreSet(int yuwen_score_, int shuxue_score_, int yingyu_score_);
int get_average_score();
private:
std::string name;
int num[8];
unsigned short yuwen_score;
unsigned short shuxue_score;
unsigned short yingyu_score;
void show_score();
};
inline void Student::show_score()
{
using namespace std;
cout << "语文分数:" << yuwen_score << endl;
cout << "数学分数:" << shuxue_score << endl;
cout << "英语分数:" << yingyu_score << endl;
}
3、构造函数重载
同普通的成员函数一样,构造函数也可以重载,上面代码中Student类的构造函数还可以声明如下:
Student(int yuwen_score_, int shuxue_score_, int yingyu_score_);
定义如下:
Student::Student(int yuwen_score_, int shuxue_score_, int yingyu_score_)
{
yuwen_score = yuwen_score_;
shuxue_score = shuxue_score_;
yingyu_score = yingyu_score_;
}
在使用构造函数创建对象时根据参数类型、数目匹配对应的构造函数。
为区分类的成员数据与类的成员函数参数,在命名类数据成员时通常加上“m_”前缀(m是member的简称),如成员数据yuwen_score命名为m_yuwen_score更好。
修改数据成员命名后的Student类声明如下:
class Student
{
public:
Student();
Student(int yuwen_score_, int shuxue_score_, int yingyu_score_);
~Student();
void scoreSet(int yuwen_score_, int shuxue_score_, int yingyu_score_);
int get_average_score();
private:
std::string m_str_name;
int m_num[8];
unsigned short m_yuwen_score;
unsigned short m_shuxue_score;
unsigned short m_yingyu_score;
void show_score();
};
其中,带参数的构造函数定义如下:
Student::Student(int yuwen_score_, int shuxue_score_, int yingyu_score_)
{
m_yuwen_score = yuwen_score_;
m_shuxue_score = shuxue_score_;
m_yingyu_score = yingyu_score_;
}
这样就能很清楚的区分函数参数与类成员数据了。
4、构造函数使用
C++提供了两种使用构造函数来初始化对象的方式。
第一种方式:显式的调用构造函数
Student student2 = Student(78, 99, 81);
这种方式初始化对象时会创建一个临时对象,该临时对象中的数据成员值被设置为上述的三个数据,然后将该临时对象中的数据成员值分别赋值给student2对象中相对应的数据成员,当该语句执行完后编译器会自动删除临时对象。
第二种方式:隐式的调用构造函数
Student student2(78, 99, 81);
这种方式格式更紧凑,它与第一种显式调用的区别是:这种方式不会创建临时对象。
使用new创建对象并初始化:
Student *pt_student = new Student(78, 99, 81);
这种情况下,对象没有名称,但可以使用指针来管理该对象。
在C++中,创建类对象的过程都需要用到类的构造函数。
原文为CSDN作者:三月微暖寻春笋
5、默认构造函数
默认构造函数是在未提供显式的初始化值时,被用来创建对象的构造函数。
下面的语句就使用了隐式的构造函数创建对象。
Student student2;
如果类没有提供构造函数,C++将自动提供默认构造函数,默认构造函数不做任何工作,对于Student类,如果没有提供默认构造函数,则C++提供的默认构造函数方法定义如下:
Student::Student()
{
}
使用C++提供的默认构造函数创建对象时,将不会对数据成员进行初始化。
需要特别注意的是,仅当类没有提供任何构造函数时,编译器才会提供默认构造函数。如果类定义了非默认构造函数,那么程序员最好再提供默认构造函数,否则,创建对象时可能会出错。如Student类声明中提供了非默认的构造函数,但没有提供默认构造函数,如下:
class Student
{
public:
Student(int yuwen_score_, int shuxue_score_, int yingyu_score_);
~Student();
private:
};
此时,使用语句Student student2;创建对象将出错。所以,如果想要在创建对象时不显式初始化对象,就必须定义一个不接受任何参数的默认构造函数。
在创建对象时,通常需要对所有数据成员初始化,以确保所有数据成员在一开始就有已知的、合理的值。因此,默认构造函数通常给所有数据成员提供隐式初始化值。如Student类的默认构造函数可以定义如下:
Student::Student()
{
name = "xxx";
for (int i = 0; i < 8; i++)
{
num[i] = 0;
}
yuwen_score = 80;
shuxue_score = 90;
yingyu_score = 85;
}
在设计类时,通常应提供对所有数据成员做隐式初始化的默认构造函数。
文中的几条术语:
- 隐式初始化是指对象的初始化值程序不可见,显式初始化指对象的初始化值程序可见;
- 默认构造函数隐式初始化对象,也可以不初始化对象;
- 非默认构造函数显式初始化对象;