C++之拷贝构造

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修饰的取地址操作符重载

相关推荐

  1. C++ 拷贝构造函数

    2024-06-15 06:40:05       41 阅读
  2. C++ 拷贝构造函数

    2024-06-15 06:40:05       34 阅读
  3. C++ delete删除拷贝构造函数和拷贝赋值运算符

    2024-06-15 06:40:05       9 阅读
  4. [C++] 拷贝构造函数 && 深拷贝、浅拷贝

    2024-06-15 06:40:05       15 阅读
  5. C++拷贝构造函数介绍

    2024-06-15 06:40:05       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-15 06:40:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-15 06:40:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-15 06:40:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-15 06:40:05       18 阅读

热门阅读

  1. 【代码】3d->video

    2024-06-15 06:40:05       8 阅读
  2. 前端常用排序算法

    2024-06-15 06:40:05       5 阅读
  3. 鸿蒙Arkts上传图片并获取接口返回信息

    2024-06-15 06:40:05       9 阅读
  4. .NETCORE 微软企业登录

    2024-06-15 06:40:05       6 阅读
  5. bash和sh区别

    2024-06-15 06:40:05       6 阅读
  6. 从零手写实现 nginx-23-directive IF 条件判断指令

    2024-06-15 06:40:05       7 阅读
  7. svm 超参数

    2024-06-15 06:40:05       6 阅读
  8. shell判断语句练习

    2024-06-15 06:40:05       6 阅读
  9. MySQL周内训参照2、DDL与DML语句

    2024-06-15 06:40:05       9 阅读
  10. Scala学习笔记12: 高阶函数

    2024-06-15 06:40:05       6 阅读