[本节内容]
拷贝构造函数 :
区别于构造函数https://blog.youkuaiyun.com/ly_6699/article/details/87870429
类的六个默认成员函数在下面博客中讲到:
类与对象:https://blog.youkuaiyun.com/ly_6699/article/details/87870429
大家先看一段代码思考一下:
class C {
public:
C(int b) //构造函数
{
a = b;
}
void Show() //一般函数
{
cout << a << “ ”;
}
private:
int a;
};
int main()
{
C a(100);
a.Show();
C a2(a); //注意这里的对象初始化要调用拷贝构造函数
a2.Show();
system("pause");
return 0;
}
运行结果:100 100
从以上代码的运行结果可以看出,系统为对象a2自动分配了内存并完成了与对象 a 的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
4.1概念
只有单个形参,该形参是对本类类型对象的引用(一般用const修饰),在用已存在的类类型创建新对象时由编译器自动调用。
4.2特征
拷贝构造函数也是特殊的成员函数,其特征如下:
1.拷贝构造函数是构造函数的一个重载形式
2.拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d) //类类型对象的引用
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(d1); //d2是d1拷贝构造的结果
system("pause");
return 0;
}
3.若未显式定义,系统生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节节序完成拷贝,这种拷贝我们叫做浅拷贝或值拷贝。
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(d1);
system("pause");
return 0;
}
注意:默认拷贝构造函数无论是什么类型,都直接按直接进行值拷贝。
但是对string,栈…数据结构中需要开辟空间的类型无法完成拷贝,因为它们要用同一块空间完成拷贝,但无法完成同时释放。只能用深拷贝解决。
class String
{
public:
String(const char* str = "jack")
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
~String()
{
cout << "~String()" << endl;
free(_str);
}
private:
char* _str;
};
int main()
{
String s1("hello");
String s2(s1); // 程序奔溃且输出两个~String
}
解决方法: 先开辟一个空间,再进行值拷贝
class String
{
public:
String(const char* str = "jack")
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
~String()
{
cout << "~String()" << endl;
free(_str);
}
String(const String& s) //拷贝构造函数
:_str(new char[strlen(s._str)+1]) //初始化时即先开辟空间
{
strcpy(_str, s._str); //在进行值拷贝
}
private:
char* _str;
};
4.4 拷贝构造函数的几个细节
1) 拷贝构造函数里能调用private成员变量吗?
解答: 因为拷贝构造函数仍然是特殊的一个成员函数,所以操作的还是自己类的成员变量,故不受private的限制。
2) 以下函数哪个是拷贝构造函数,为什么?
1)X::X(const X&);
2) X::X(X);
3)X::X(X&, int a=1);
4) X::X(X&, int a=1, int b=2);`
解答:
X::X(const X&); //是拷贝构造函数
X::X(X); //不是,单纯的值拷贝会引发无限递归
X::X(X&, int=1); //是
X::X(X&, int a=1, int b=2); //是
原因: 对于一个类X, 如果一个构造函数的第一个参数是下列之一,且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数。
a) X&
b) const X&
c) volatile X&
d) const volatile X&
3. 一个类中可以存在多个拷贝构造函数吗?
解答:一个类中可以存在超过一个拷贝构造函数:
class X {
public:
X(const X&); // const 的拷贝构造
X(X&); // 非const的拷贝构造
};
注意,如果一个类中若果只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的对象指向拷贝初始化了。
class X {
public:
X();
X(X&);
};
const X cx;
X x = cx; // error
如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。这个默认的参数可能为 X::X(const X&)或 X::X(X&),由编译器根据上下文决定选择使用哪一个。