1. 拷贝构造函数
1.1 拷贝构造函数的定义
如果一个类的构造函数的第一个参数为所属类类型的引用。如果还有其他额外参数,且这些额外的参数都有默认值,则该构造函数就叫拷贝构造函数。
函数的默认参数必须放在函数声明中,除非该函数没有声明。
1.2 拷贝构造函数的作用
拷贝构造函数会在一定的时机被系统自动调用。
#ifndef DAY02_TIME_H
#define DAY02_TIME_H
//类的声明
class Time
{
public:
Time(); //默认构造函数声明
Time(const Time& tmpTime, int a = 5); //拷贝构造函数的声明,(tmpTime为所属类类型的引用,其他额外参数有默认值)
};
#endif //DAY02_TIME_H
#include <iostream>
using namespace std;
#include "Time.h"
Time::Time()
{
cout << "调用了默认构造函数Time::Time()"<< endl;
}
//建议拷贝构造函数的第一个参数总是带上const
Time::Time(const Time &tmpTime, int a)
{
cout << "调用了拷贝构造函数Time::Time(Time &tmpTime, int a)"<< endl;
}
int main() {
Time time1; //调用了默认构造函数Time::Time()
Time time2 = time1; //调用了拷贝构造函数Time::Time(Time &tmpTime, int a)
Time time3(time1); //调用了拷贝构造函数Time::Time(Time &tmpTime, int a)
Time time4{time1}; //调用了拷贝构造函数Time::Time(Time &tmpTime, int a)
Time time5 = {time1}; //调用了拷贝构造函数Time::Time(Time &tmpTime, int a)
}
1.3 拷贝构造函数的建议
- 拷贝构造函数的第一个参数总是用const修饰。
- 拷贝构造函数前不要用explicit修饰。
由于进行拷贝构造时,一般系统会进行隐式类型转换,而explicit会关掉隐式类型转换
1.4 类对象的拷贝
(1)默认情况下,类对象的拷贝是每个成员变量逐个进行拷贝。
(2)成员变量的逐个拷贝功能会因为我们自己定义的拷贝构造函数失去作用。
#ifndef DAY02_TIME_H
#define DAY02_TIME_H
//类的声明
class Time
{
public:
int m_Hour;
int m_Minute;
public:
Time(); //默认构造函数声明
Time(int hour, int minute);
Time(const Time& tmpTime, int a = 5); //拷贝构造函数的声明,(tmpTime为所属类类型的引用,其他额外参数有默认值)
};
#endif //DAY02_TIME_H
#include <iostream>
using namespace std;
#include "Time.h"
Time::Time()
{
cout << "调用了默认构造函数Time::Time()"<< endl;
}
Time::Time(int hour, int minute):m_Hour(hour), m_Minute(minute)
{
}
//建议拷贝构造函数的第一个参数总是带上const
Time::Time(const Time &tmpTime, int a)
{
cout << "调用了拷贝构造函数Time::Time(Time &tmpTime, int a)"<< endl;
}
int main() {
Time time1; //调用了默认构造函数Time::Time()
time1 = Time(12, 18);
Time time2 = time1;
cout << time2.m_Hour << ":" << time2.m_Minute; //0:0
Time time3(time1);
cout << time3.m_Hour << ":" << time3.m_Minute; //-865150064:21891,没有进行成员变量的逐个拷贝
Time time4{time1};
Time time5 = {time1};
}
(3)如果我们没有自己定义拷贝构造函数,系统会为我们自动定义一个“合成拷贝构造函数”,该合成拷贝构造函数会将每个成员变量逐个进行拷贝,此时,如果成员变量为类类型,则系统合成的拷贝构造函数会调用该类的拷贝构造函数来拷贝。
#ifndef DAY02_TIME_H
#define DAY02_TIME_H
//类的声明
class A
{
public:
A();
A(const A& tmpA);
};
class Time
{
public:
int m_Hour;
int m_Minute;
A a; //类类型的成员变量
public:
Time(); //默认构造函数声明
};
#endif //DAY02_TIME_H
#include <iostream>
using namespace std;
#include "Time.h"
A::A()
{
cout << "调用了默认构造函数A::A()"<< endl;
}
A::A(const A& tmpA)
{
cout << "调用了拷贝构造函数A::A(const A& tmpA)" << endl;
}
Time::Time()
{
cout << "调用了默认构造函数Time::Time()"<< endl;
}
int main() {
Time time1; //调用了默认构造函数A::A(),调用了默认构造函数Time::Time()
Time time2 = time1; //调用了拷贝构造函数A::A(const A& tmpA)
}
(4)由于自己定义的拷贝构造函数会取代系统合成的拷贝构造函数,此时需要在自己的拷贝构造函数中给类成员进行赋值。以免出现类成员还没赋值就使用的情况。
#ifndef DAY02_TIME_H
#define DAY02_TIME_H
class Time
{
public:
int m_Hour;
int m_Minute;
public:
Time(); //默认构造函数声明
Time(Time& tmpTime); //拷贝构造函数声明
};
#endif //DAY02_TIME_H
#include <iostream>
using namespace std;
#include "Time.h"
Time::Time()
{
cout << "调用了默认构造函数Time::Time()"<< endl;
}
//在拷贝构造函数中给成员变量初始化
Time::Time(Time &tmpTime): m_Hour(12), m_Minute(18)
{
cout << "调用了拷贝构造函数Time::Time(Time &tmpTime)"<< endl;
}
int main() {
Time time1; //调用了默认构造函数Time::Time()
Time time2 = time1; //调用了拷贝构造函数Time::Time(Time &tmpTime)
cout << time2.m_Hour << ":" << time2.m_Minute << endl; //12:18
}
1.5系统调用拷贝构造函数的其它形式
(1)将类对象作为实参传递给一个非引用类型的形参。
#ifndef DAY02_TIME_H
#define DAY02_TIME_H
class Time
{
public:
int m_Hour;
int m_Minute;
public:
Time(); //默认构造函数声明
Time(Time& tmpTime); //拷贝构造函数声明
};
#endif //DAY02_TIME_H
#include <iostream>
using namespace std;
#include "Time.h"
Time::Time()
{
cout << "调用了默认构造函数Time::Time()"<< endl;
}
//在拷贝构造函数中给成员变量初始化
Time::Time(Time &tmpTime)
{
cout << "调用了拷贝构造函数Time::Time(Time &tmpTime)"<< endl;
}
void func1(Time tmp)
{
return;
}
void func2(Time& tmp)
{
return;
}
int main() {
Time time1; //调用了默认构造函数Time::Time()
func1(time1); //调用了拷贝构造函数Time::Time(Time &tmpTime)
func2(time1); //将类对象作为实参传递给引用类型的形参,此时不调用拷贝构造函数
}
(2)从一个函数中返回一个对象的时候也会调用拷贝构造函数。