携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天
前言
只有品尝过奋斗的滋味,才能体会人生的珍贵;只有勤耕不辍,才能不负韶华、不负自己。
上一篇关于C++学习的文章 C++学习——坚持(二)主要学习了面向对象的一些基本概念,这篇文章主要对类和对象进行进一步的探讨。
一:构造函数
1:简单了解
对于编写程序来说,构造函数可谓是很关键的一部分了,在 c++中,为给对象进行初始化,就提供了一种叫做构造函数的机制,实际上就是为成员变量赋初值的。 构造函数是类中特殊的成员函数,属于类的一部分。当给出类的定义时,由程序员来编写构造函数,如果没有编写类的构造函数,就由系统添加一个参数表为空、函数体也为空的构造函数,也就是说任何类都至少有一个构造函数。 声明对象后,可以用运算符 new 为对象进行初始化,这时调用的是所属对象的构造函数。构造函数的作用是完成对象的初始化工作,用来保证对象的初始状态是确定的。
2:如何定义构造函数
当我们在定义一个类时,需要为类定义一个相应的构造函数,构造函数的函数名与类名相同,并且没有返回值。同时构造函数允许重载(指在程序的同一范围内声明几个功能相似的同名函数)。
构造函数的声明格式:
构造函数名(即类名)(形参1,形参2,......形参n);
我们假设一个类的成员变量是 X1,X2…Xn,那么在类体外定义构造函数时有以下几种方式:
形式一:
类名::类名(形参1,形参2,…形参n);
{
X1=形参1;
X2=形参2;
…
Xn=形参n;
}
形式二:、
类名::类名()
{
X1 = 初始化表达式1;
X2 = 初始化表达式2;
…
Xn = 初始化表达式n;
}
形式三:
类名::类名(形参1,形参2,…形参n):X1(形参1),X2(形参2)…Xn(形参n){}
例如 :使用固定值在初始化列表中为各个变量赋初值
myDate::myDate():year(2022),month(2),day(2){} //三个函数的初始化均在初始化列表中完成
或使用带入的参数值通过初始化列表为各成员变量赋初值
myDate::myDate(int y,int m,intd):year(y),month(m),day(d){}
在编写构造函数时,能够赋初值的地方有两处:一处是在初始化列表中;一处是在构造函数体内部;构造函数中为成员变量初始化时,既不要有重复,也不要有遗漏
3:怎么使用构造函数
当我们创建好一个对象时,系统就会根据创建对象的语句所提供的参数来选择调用哪一个构造函数去初始化该对象,系统在调用构造函数时是不需要程序员控制的。 假如没有提供参数,就调用无参的构造函数,并且类中定义了哪种构造函数,就决定了创建对象时可以使用那种形式。
例如:定义一个myDate类,构造函数如下:
myDate::myDate(int y = 2022,int m = 8,int d = 1)
{
year = y;
month = m;
day = d;
}
//myDate类的三个参数都有默认值
那么我们创建对象时,就可以采用以下形式:
myDate d0; //输出2022/8/1
myDate d1(2021); //输出 2021/8/1
myDate d2(2021,9); //输出 2021/9/1
myDate d3(2021,9,2); //输出 2021/9/2
调用构造函数时,给定的实参从左至右与形参进行匹配,如果实参的个数少于形参的个数,则不足的形参使用默认值进行初始化。
也可以通过构造函数创建对象指针
假设在类体定义一个构造函数:
myDate::myDate(int y,int m,int d)
{
year = y;
month = m;
day = d;
}
则创建对象时,可以采用:
myData *pa = new myDate (2022,8,1);pa ->printDate();
比如我们声明了一个 Clock类,然后定义一个无参构造函数并调用它:
#include <iostream>
#include <iomanip>
using namespace std;
class Clock
{
public:
Clock();//声明无参构造函数
void showTime();//声明显示时间的成员函数
private:
int hour;//声明表示小时的成员变量
int min; //声明表示分钟的成员变量
int sec;//声明表示秒的成员变量
};
Clock::Clock()//类外实现无参构造函数
{
hour=0;//初始化过程中直接给成员变量赋值
min=0;
sec=0;
}
void Clock::showTime()//类外实现成员函数
{
cout<<setw(2)<<setfill('1')<<hour<<":"<<setw(2)<<setfill('2')<<min<<":"<<setw(2)<<setfill('3')<<sec<<endl; //setw(n)函数用于设置字段宽度为 n位;setfill()函数用于填充字符
}
int main(int argc, char** argv)
{
Clock clock;//创建Clock对象clock
cout<<"clock";
clock.showTime();//对象调用成员函数
return 0;
}
同样的,我们定义一个有参构造函数并调用它;
# include <iostream>
# include <iomanip>
using namespace std;
class Clock
{
public:
Clock(int h,int m,int s);//声明有参构造函数
void showTime();//声明显示时间的成员函数
private:
int hour;
int min;
int sec;
} ;
Clock::Clock(int h,int m,int s) //类外实现有参构造函数
{
hour=h;//将初始值赋给成员变量
min=m;
sec=s;
}
void Clock::showTime()//类外声明成员函数
{
cout<<hour<<":"<<min<<":"<<sec<<endl;
}
int main()
{
Clock clock1(11,11,11);//创建Clock对象 clock1,并传入初值
cout<<"clock1"<<" ";
clock1.showTime();//clock1调用成员函数showTime(),用于显示时间
Clock clock2(22,22,22);//创建Clock对象 clock2,并传入初值
cout<<"clock2"<<" ";
clock2.showTime();//clock2调用成员函数showTime()
return 0;
}
那如果是定义一个含有成员对象的类的构造函数并调用呢?
我们举一个常用的学生和日期的例子,先定义一个日期类myDate,然后再定义一个学生类 Student,Student类中存放学生的姓名和出生日期,其中出生日期类的对象作为Student类的成员变量:
# include <iostream>
using namespace std;
class myDate //创建myDate类
{
public:
myDate(int y,int m,int d);
void show();
private:
int year;
int month;
int day;
};
myDate::myDate(int y,int m,int d):year(y),month(m),day(d)
{
cout<<"myDate类构造函数"<<endl;
}
void myDate::show()
{
cout<<"出生日期:"<<year<<"/"<<month<<"/"<<day<<endl;
}
class Student //创建Student类
{
public:
Student(string n, int y, int m, int d);
void show();
private:
string name;
myDate date;
};
//类外实现构造函数
Student::Student(string n, int y, int m, int d)
:date(y,m,d)
{
cout<<"Student类构造函数"<<endl;
name=n;
}
//类外实现show()函数
void Student::show()
{
cout<<"姓名:"<<name<<endl;
date.show();
}
int main()
{
Student stu("lili",2003,1,1); //创建学生对象stu
stu.show(); //显示学生信息
return 0;
}