基本概念
构造函数 类中的特殊函数 用于描述初始化算法
作用
在对象被创建时使用特定值构造对象
将对象初始化为一个特定状态
如 在构造一个clock类的时候
把初始时间设为0 0 0就可以通过构造函数来设置
形式
函数名与类名相同
不能定义返回值类型,不能有return
可以有形式参数,也可以没有形式参数
可以是内联函数
可以重载
可以带默认值
调用时机
对象被创建时自动被调用
如
创建对象的时候给初始值 构造函数自动被调用 Clock myClock (0,0,0);
如果没有这样形式的构造函数 那么编译器报错 说不存在这样形式的构造函数
默认构造函数
调用时不需要实参的构造函数
参数表为空
全部参数为默认值
两个默认构造函数不能同时出现在一个类中
建立新对象 一定会调用构造函数
如果定义类时不声明一个构造函数 那么编译器在编译时会自动生成一个构造函数(隐含默认构造函数)
隐含生成默认构造函数
参数列表为空
类内定义成员初始值,使用该值
没有定义,则默认方式初始化,默认方式初始化的值不确定
=default
程序已经定义构造函数 那么编译器不再隐含生成默认函数,如果此时希望编译器隐含生成默认函数,则使用=default
如
class Clock { public: Clock() = default;//指示编译器提供默认构造函数private: int hour, minute, second; };
以下是之前例子的带构造函数扩展
#include<iostream> using namespace std; class Clock { public: Clock(int newH, int newM, int newS);//构造函数 不能定义返回值类型 void也不行 Clock();//构造函数重载 默认构造函数 void setTime(int newH, int newM, int newS); void showTime(); private: int hour, minute, second; }; Clock::Clock(int newH, int newM, int newS) ://类名写前面 无返回值类型 构造函数也是成员函数 成员函数实现的时候都要写类名 hour(newH), minute(newM), second(newS)//初始化列表 还记得c++中给变量赋初值的另一种方法吗 如 int a(3) 这里采用同样的方法,意思是 将函数收到的newH赋值给类中的hour {}//当然上面的初始化列表可以写到函数体中,但是并不方便 Clock::Clock() :hour(0), minute(0), second(0){}//默认构造函数 给hour赋值0,以此类推 void Clock::setTime(int newH, int newM, int newS) { hour = newH; minute = newM; second = newS; } void Clock::showTime() { cout << hour << ":" << minute << ":" << second<<endl; } int main() { Clock c;//调用构造函数 此处不给初始值,因此调用默认构造函数 Clock c2(1,2,3);//不管有没有参数,调用创建对象的时候都会调用构造函数,如果类中没有定义构造函数,那么编译器会隐含生成一个构造函数,但如果你定义了,且没有再定义默认构造函数-> c.showTime();//那么当你创建一个新对象但不给初值的时候会报错 cout << ".....................\n"; c2.showTime(); cout << "....................."; cout <<endl<< "已初始化" << endl; int h, m, s; cout << "请设定时分秒" << endl; cin >> h >> m >> s; c.setTime(h, m, s); c.showTime(); cout <<endl<< "时间已设定" << endl; return 0; }
委托构造函数
上面的两个构造函数功能几乎一样可以采用委托构造函数来简化,最重要的是,委托构造函数可以保证两个构造函数的一致性,以后修改一次,那么委托他的那些构造函数也会被修改
Date(int year,int month,int day):_year(year), _month(month), _day(day){}//其声明在class内,但 : 以后的内容可以在class外定义,不影响后面构造函数的委托 //其余构造函数全都委托给第一个构造函数 Date() :Date(1990,1,1){} Date(int year) :Date(){}
复制构造函数
用已经存在的对象去初始化新对象 类似于
int a=0; int b=a;
以上操作是c++定义好的,所以可以直接用,但类中并没有定义这种操作,因此需要去定义
隐含的复制构造函数
,如果没有自定义复制构造函数,编译器会为我们生成一个默认的复制构造函数 该函数会实现两个对象数据成员的一一对应复制
很多时候,该默认函数就能令人满意了,因此这样的话就不需要自己写复制构造函数,但是另一些时候,我们需要自己规定复制构造函数 比如说 对象里面有指针,编译器给的默认复制构造函数就不够用了,或者有特殊的复制需求
复制构造函数的定义
该函数的形参是本类对象的引用,作用是用已存在的对象去初始化同类型的新对象
格式是
class内声明 类名 (const 类名 &对象名); //&引用符号 如果该函数对形参做了任何修改,那么对实参也会做相同的修改 为保证安全性 需要限定符const
class外实现 类名::类名 (const 类名 &对象名)//前面的类名表示该函数所在类的名字,后面的类名是因为它是构造函数,因此函数名就是类名
{函数体}
调用复制构造函数的3种情况
1.定义对象时用本类的另一个对象去初始化
2.函数的形参是类的对象(而不是类的对象的引用),在此过程中会发生对象的值的传递 此时要调用复制构造函数
3.函数的返回值是类的对象 函数执行结束 返回主调函数 的时候 使用return语句中的对象初始化一个无名对象再传递给主调函数 发生复制构造
这种情况可以通过移动构造避免不必要的复制
=delete
不希望对象被复制构造时,用=delete指示编译器不生成默认复制构造函数
如
在point类中声明
point(const point& p) = delete;