前言
上期讲到构造函数,本期接着讲
本文章为初学者为巩固知识所创作,知识有限,大佬轻喷
一、编译器默认提供的构造函数
首先来看一段代码
class MyClass
{
public:
int i;
char c;
string str;
};
void main()
{
MyClass class1;
cout << class1.i << " ";
cout << class1.c << " ";
cout << class1.str << " ";
cout << endl;
}
解释一下写这段代码的原因: 首先定义一个MyClass类, 内部并没有定义任何构造函数,那么内部的变量的值是多少呢? 我们调用一下test函数 结果可以发现,内部变量是随机值
那我们实现一个有参构造函数呢
class MyClass
{
public:
int i;
char c;
string str;
MyClass(int i, char c, string str)
{
;
}
};
void test()
{
MyClass class1;
cout << class1.i << " ";
cout << class1.c << " ";
cout << class1.str << " ";
cout << endl;
}
定义了一个有参构造函数,但内部没有任何函数实现
再次调用test函数 报错了 错误为MyClass没有默认构造函数 那为什么定义一个有参构造函数后就报错了呢? 因为在自己没有实现任何构造函数时,编译器会自己实现三个空构造函数,而当自己实现了构造函数后,就会发生变化
如何再加上这段代码
MyClass class1;
MyClass class2(1, '2', "abc");
MyClass class3(class2);
创建对象class1时报错,class3时没有报错。
所以可见编译器提供了拷贝构造函数,没有提供无参构造函数 这种构造函数叫‘隐式构造’ 当自己没有实现任何构造函数时,类会提供3种隐式构造函数 自己实现了有参构造后,类则不会提供隐式默认无参构造 当自己实现拷贝构造函数后,类不会提供任何隐式构造函数
二、浅拷贝与深拷贝
老规矩,上代码
class MyClass
{
public:
int i;
char c;
string str;
MyClass(int i, char c, string str)
{
this->i = i;
this->c = c;
this->str = str;
}
};
void test()
{
MyClass class1(1, 'c', "abc");
MyClass class2(class1);
cout << "class2内部变量为:";
cout << "i = " << class2.i << " ";
cout << "c = " << class2.c << " ";
cout << "str = " << class2.str << " ";
cout << endl;
}
调用test函数 运行结果: 上述代码我们使用编译器提供的拷贝构造函数初始化class2,并没有任何问题
那么我们如果把成员变量存放到堆区呢
class MyClass2
{
public:
int* arr;
MyClass2()
{
arr = new int[4];
for (int i = 0; i < 4; i++)
arr[i] = i;
}
void show()
{
for (int i = 0; i < 4; i++)
cout << arr[i] << " ";
cout << endl;
}
};
void test2()
{
MyClass2 class1;
MyClass2 class2(class1);
cout << "class1 修改前 class2 内部arr数据为:";
class2.show();
for (int i = 0; i < 4; i++)
class1.arr[i] = i + 1;
cout << "class1 修改后 class2 内部arr数据为:";
class2.show();
}
int main()
{
test2();
return 0;
}
MyClass2中arr是堆区数组,我们通过默认构造对class1进行初始化,此时class1.arr中数据为 0,1, 2, 3
再通过默认的拷贝构造对class2进行初始化,那么class2.arr中数据肯定也为 0,1, 2, 3
用下面的代码修改class1中的数据
for (int i = 0; i < 4; i++)
class1.arr[i] = i + 1;
修改后为 1, 2, 3, 4 我们执行代码看看class2中数据为多少
class2 为什么也改变了呢
用图片来解释吧
编译器默认的拷贝构造执行了 class2.arr = class1.arr; 这样的操作二者指向同一块内存区域,修改class1,class2 也会改变
编译器默认的拷贝构造函数为浅拷贝 那么如何解决这种浅拷贝的问题呢
当然是自己实现拷贝构造函数啦
只要自己实现拷贝构造函数让堆区的数据也拷贝过来就行了 思路简单,直接上代码
MyClass2(MyClass2& cla)
{
this->arr = new int[sizeof(cla.arr)];
for (int i = 0; i < sizeof(cla.arr); i++)
this->arr[i] = cla.arr[i];
}
执行效果:
OK,完了,下期写点什么好呢,简单写写运算符重载吧(反正没人看)
都看到这了点个赞呗 下期再见
|