首页 > 编程笔记

C++构造函数的定义和使用

构造函数是类的特殊成员函数,用于初始化对象。构造函数在创建对象时由编译器自动调用。

C++ 中的每个类至少要有一个构造函数,如果类中没有定义构造函数,系统会提供一个默认的无参构造函数,默认的无参构造函数体也为空,不具有实际的初始化意义。因此,在 C++ 程序中要显示定义构造函数。

本文将针对构造函数的定义与具体用法进行详细讲解。

自定义构造函数

构造函数是类的特殊成员函数,C++ 编译器严格规定了构造函数的接口形式,其定义格式如下所示:

class 类名
{
权限控制符:
    构造函数名(参数列表)
    {
        函数体
    }
...       //其他成员
};

关于构造函数定义格式的说明,具体如下。

注意:如果在类中提供了自定义构造函数,编译器便不再提供默认构造函数。自定义构造函数时,可以定义无参构造函数,也可以定义有参构造函数,下面分别进行讲解。

1) 自定义无参构造函数

自定义无参构造函数时,可以在函数内部直接给成员变量赋值。

【示例1】通过案例演示无参构造函数的定义与调用。C++ 代码如下:
#include<iostream>
#include<iomanip>
using namespace std;
class Clock     //定义时钟类Clock
{
public:
    Clock();      //声明无参构造函数
    void showTime();   //声明显示时间的成员函数
private:
    int _hour;     //声明表示小时的成员变量
    int _min;      //声明表示分钟的成员变量
    int _sec;      //声明表示秒的成员变量
};
Clock::Clock()     //类外实现无参构造函数
{
    _hour=0;      //初始化过程,将成员变量初始化为0
    _min=0;
    _sec=0;
}
void Clock::showTime()   //类外实现成员函数
{
    cout<<setw(2)<<setfill('0')<<_hour<<":"
    <<setw(2)<<setfill('0')<<_min<<":"
    <<setw(2)<<setfill('0')<<_sec<<endl;
}
int main()
{
    Clock clock;     //创建对象clock
    cout<<"clock:";
    clock.showTime();    //通过对象调用成员函数showTime()显示时间
    return 0;
}
运行结果:

clock:00:00:00

示例分析:
本例对象 clock 的初始化时间为 00:00:00,因为创建 clock 对象调用的是无参构造函数,无参构造函数将时、分、秒都初始化为 0。

2) 自定义有参构造函数

如果希望在创建对象时提供有效的初始值,可以通过定义有参构造函数实现。

【示例2】修改【示例1】,将无参构造函数修改为有参构造函数,以演示有参构造函数的定义与使用。C++ 代码如下:
#include<iostream>
#include<iomanip>
using namespace std;
class Clock         //定义时钟类Clock
{
public:
    Clock(int hour, int min, int sec);    //声明有参构造函数
    void showTime();       //用于显示时间的成员函数
private:
    int _hour;         //声明表示小时的成员变量
    int _min;         //声明表示分钟的成员变量
    int _sec;         //声明表示秒的成员变量
};
Clock::Clock(int hour, int min, int sec)   //类外实现有参构造函数
{
    _hour=hour;        //初始化过程,将初始值直接赋值给成员变量
    _min=min;
    _sec=sec;
}
void Clock::showTime()       //类外实现成员函数
{
    cout<<setw(2)<<setfill('0')<<_hour<<":"
    <<setw(2)<<setfill('0')<<_min<<":"
    <<setw(2)<<setfill('0')<<_sec<<endl;
}
int main()
{
    Clock clock1(10,20,30);       //创建对象clock1,传入初始值
    cout<<"clock1:";
    clock1.showTime();        //通过对象调用成员函数showTime()显示时间
    Clock clock2(22,16,12);       //创建对象clock2,传入初始值
    cout<<"clock2:";
    clock2.showTime();        //通过对象调用成员函数showTime()显示时间
    return 0;
}
运行结果:

clock1:10:20:30
clock2:22:16:12

示例分析:
注意:在实现构造函数时,除了在函数体中初始化成员变量,还可以通过:运算符在构造函数后面初始化成员变量,这种方式称为列表初始化,其格式如下所示:

类::构造函数(参数列表): 成员变量1(参数1), 成员变量2(参数2),…, 成员变量n(参数n)
    {
        构造函数体
    }

本例使用列表初始化实现成员变量初始化的方式如下所示:

Clock::Clock(int hour, int min, int sec):_hour(hour),_min(min),_sec(sec)
    {
        //...
    }

重载构造函数

在 C++ 中,构造函数允许重载。

【示例3】Clock 类可以定义多个构造函数,示例代码如下所示:
class Clock          //定义时钟类Clock
{
public:
    //构造函数重载
    Clock();
    Clock(int hour);
    Clock(int hour, int min);
    Clock(int hour, int min, int sec);
    void showTime();        //声明显示时间的成员函数
private:
    int _hour;         //声明表示小时的成员变量
    int _min;          //声明表示分钟的成员变量
    int _sec;          //声明表示秒的成员变量
};
当定义具有默认参数的重载构造函数时,要防止调用的二义性。

修改【示例2】,在 Clock 类中定义重载构造函数,并且其中一个构造函数具有默认参数,在创建对象时,构造函数调用会产生二义性。

【示例4】C++ 程序代码如下:
#include<iostream>
#include<iomanip>
using namespace std;
class Clock         //定义时钟类Clock
{
public:
    //声明重载构造函数
    Clock(int hour, int min);
    Clock(int hour, int min, int sec=0); 
    void showTime();       //声明显示时间的成员函数
private:
    int _hour;         //声明表示小时的成员变量
    int _min;         //声明表示分钟的成员变量
    int _sec;         //声明表示秒的成员变量
};
Clock::Clock(int hour, int min):_hour(hour),_min(min)
{
    cout<<"调用两个参数的构造函数"<<endl;
    _sec=10;
}
Clock::Clock(int hour, int min, int sec=0)    //类外实现构造函数
{
    cout<<"调用三个参数的构造函数"<<endl;
    _hour=hour;
    _min=min
    _sec=sec;
}
void Clock::showTime()       //类外实现成员函数showTime()
{
    cout<<setw(2)<<setfill('0')<<_hour<<":"
    <<setw(2)<<setfill('0')<<_min<<":"
    <<setw(2)<<setfill('0')<<_sec<<endl;
}
int main()
{
    Clock clock(8,0);        //创建对象clock,传入初始值
    cout<<"clock:";
    clock.showTime();        //通过对象调用成员函数显示时间
    return 0;
}
本例运行时编译器会报错:

“Clock::Clock”:对重载函数的调用不明确
“Clock::Clock”:重定义默认参数:参数1
有多个构造函数“Clock::Clock”的实例与参数列表匹配

示例分析:

含有成员对象的类的构造函数

C++ 允许将一个对象作为另一个类的成员变量,即类中的成员变量可以是其他类的对象,这样的成员变量称为类的子对象或成员对象。

含有成员对象的类的定义格式如下所示:

class B
{
    A a;   //对象a作为类B的成员变量
    ...   //其他成员
}

创建含有成员对象的对象时,先执行成员对象的构造函数,再执行类的构造函数。

例如,上述格式中,类 B 包含一个类 A 对象作为成员变量,在创建类 B 对象时,先执行类 A 的构造函数,将类 A 对象创建出来,再执行类 B 的构造函数,创建类 B 对象。如果类 A 构造函数有参数,其参数要从类 B 的构造函数中传入,且必须以:运算符初始化类 A 对象。

在类中包含对象成员,能够真实地描述客观事物之间的包含关系,比如描述学生信息的类,类中的成员除了姓名、学号属性,还包含出生日期。

在定义学生类的时候,可以先定义一个描述年、月、日的出生日期类,再定义学生类,将出生日期类的对象作为学生类的成员变量。

【示例5】通过案例演示含有成员对象的类的构造函数的定义与调用。C++ 代码如下:
#include<iostream>
using namespace std;
class Birth       //定义出生日期类Birth
{
public:
    Birth(int year,int month, int day); //构造函数
    void show();       //声明成员函数show()显示日期
private:
    int _year; 
    int _month;
    int _day;
};
//类外实现构造函数
Birth::Birth(int year, int month, int day)
    :_year(year),_month(month),_day(day)
{
    cout<<"Birth类构造函数"<<endl;
}
//类外实现show()函数
void Birth::show()
{
    cout<<"出生日期:"<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
class Student       //定义学生类Student
{
public:
    //构造函数
    Student(string name, int id, int year, int month, int day); 
    void show();
private:
    string _name;
    int _id;
    Birth birth;
};
//类外实现构造函数
Student::Student(string name, int id, int year, int month, int day)
    :birth(year,month,day)
{
    cout<<"Student类构造函数"<<endl;
    _name=name;
    _id=id;
}
//类外实现show()函数
void Student::show()
{
    cout<<"姓名:"<<_name<<endl;
    cout<<"学号:"<<_id<<endl;
    birth.show();
}
int main()
{
    Student stu("lili",10002,2000,1,1); //创建学生对象stu
    stu.show();      //显示学生信息
    return 0;
}
运行结果:

Birth类构造函数
Student类构造函数
姓名:www.weixueyuan.net
学号:10002
出生日期:2012-1-1

示例分析:
由运行结果可知,学生对象成功创建且显示出了学生信息。创建对象 stu 时,先调用 Birth 类构造函数,之后才调用 Student 类构造函数。

优秀文章