赞
踩
1、转换构造函数
一个类中构造函数可以重载,允许多个存在。如果构造函数只有一个参数(或参数带有默认值)且非当前类对象时,可以将其他类型自动转换为当前类类型,这个过程称为隐式类型转换。
如下示例中的三个构造函数都可以发生隐式类型转换,在使用等号初始化或赋值时自动转换。
这样的可以发生隐式类型转换的构造函数称为:转换构造函数。
示例代码:
- #include<iostream>
- using namespace std;
-
- class CTest
- {
- public:
- CTest(int a){} //转换构造函数
- /*
- CTest(int a, int b = 0){} //转换构造函数
- CTest(int a = 0,int b = 0){} //转换构造函数
- explicit CTest(int a = 0, int b = 0){} //禁止发生隐式类型转换
- CTest(int a,int b){} //不是转换构造函数
- */
- };
- int main()
- {
- CTest tst(1); //调用带参的构造
- CTest tst1 = 1; //合法操作,发生隐式类型转换,将int类型转换为CTest类型
- tst1 = 2; //合法操作,发生隐式类型转换,将int类型转换为CTest类型
- }
注意:如果是多个参数且无默认值时,则不能自动隐式类型转换。如果想要避免隐式类型转换,需在构造函数前加上关键字:explicit。
2.拷贝构造函数
拷贝构造函数,C++编译器默认提供的特殊的构造函数,在空类中它与无参构造并存,拷贝构造函数是众多构造函数中的一种。
“默认拷贝构造函数”用于创建一个新对象作为现有对象的副本,其作用是将现有对象的成员变量复制到新对象中。
参数为当前类对象的引用。与默认的无参构造不同,其函数体代码一般不为空,操作为:参数中对象成员依次给this对象成员进行初始化。
注意:当我们手动重构拷贝构造函数时,编译器就不会提供默认的拷贝构造函数了,当然也不会存在默认的无参构造了。
- #include<iostream>
- using namespace std;
-
- class CTest
- {
- public:
- CTest() {}
- CTest(const CTest& tst) {}
- };
- int main()
- {
- CTest tst1; //调用无参构造
- CTest tst2(tst1); //调用拷贝构造 或者写成 CTest tst2=tst1;
- }
存在的问题:
默认拷贝构造函数是一个浅拷贝,当类中存在指针成员且指向了一个new出来的具体空间,拷贝构造函数只是将两个指针存储的地址进行拷贝,并不会处理指针指向的空间。这样就导致了多个对象 里的指针指向了同一个空间,那么会导致以下问题:
1.当其中一个对象通过指针修改其指向空间的值,那么其他对象再使用就是修改之后的值了,这样的情况多数不是我们预期的。
2.如果是new出来的空间,那么会导致多个对象回收同一块内存空间,引起非法操作错误。
示例代码:
- #include<iostream>
- using namespace std;
- class Test
- {
- private:
- int* p;
- public:
- Test(int x)
- {
- this->p = new int(x);
- cout << "对象被创建" << endl;
- }
- ~Test()
- {
- if (p != NULL)
- {
- delete p;
- p = NULL;
- }
- cout << "对象被释放" << endl;
- }
- int getX() { return *p; }
- };
-
- int main()
- {
- Test a(10);
- Test b = a;//会调用默认的拷贝构造函数
- return 0;
- }
执行结果:
解决办法:
深拷贝,它并不是一个固定的写法,而是一个解决的办法:即在拷贝构造时,如果参数对象中的指针成员指向了一个内存空间,那么在重构拷贝构造时,需要为当前this对象中指针成员额外开辟新的内存空间,并初始化对应的值。
- class CTest
- {
- public:
- int* m_p;
- CTest(const CTest& tst)
- {
- //深拷贝
- if (tst.m_p)
- m_p = new int(*tst.m_p);
- else
- m_p = nullptr;
- }
- };
在某些情况下,可以使用指针或引用避免对象的值传递,也避免了浅拷贝问题。
3.默认operator=
空类中编译器会默认提供一个operator=函数,参数和返回值为当前类对象的引用,一旦手动重构,编译期就不再提供默认的了。
当用一个类对象给类的另一个对象赋值时,会调用默认的operator=函数。
默认的operator=函数的函数体代码不为空,参数中对象成员依次给this对象成员赋值。
默认operator=函数也是浅拷贝,解决办法深拷贝:
- class CTest
- {
- private:
- int m_a;
- int* m_p;
- public:
- CTest& operator=(const CTest& tst)
- {
- if (this != &tst)
- {
- this->m_a = tst.m_a;
- if (tst.m_p)
- {
- if (this->m_p)
- {
- *this->m_p = *tst.m_p;
- }
- else
- {
- this->m_p = new int(*tst.m_p);
- }
- }
- else
- {
- if (this->m_p)
- {
- delete this->m_p;
- }
- this->m_p = nullptr;
- }
- }
- }
-
- };
4.总结
C++构造函数调用规则:http://t.csdnimg.cn/H5jOr
类的默认成员函数(共六个)
1.默认无参数构造
2.默认的拷贝构造
3.默认的operator=(赋值操作符重载)
4.默认析构函数
5.默认的取地址操作符重载
6.const修饰的取地址操作符重载
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。