【无标题】

拷贝赋值函数、拷贝构造函数

111111111111111111111111111111111111111111

拷贝构造函数

也是构造函数的一种,常用来以另一对象为模板创建新对象。如果对象中没有指针,可以直接使用数据库自带的该函数,但有指针就需要自己构建,这是为了避免造成浅拷贝,使两个指针指向同一内存空间。

例如

string s1;

string s2(s1);

222222222222222222222222222222222222222222

拷贝赋值函数

作用和拷贝构造函数基本一致,区别在于拷贝构造的对象是新创建的,而赋值函数则是原来就有的。

3333333333333333333333333333333333333333333333

在代码表示上也有所不同

拷贝构造如下:

inline string::string( const string& str)

{
m_data=new char[strlen(str.m_data+1)];

strcpy(m_data;str.m_data);

}

而拷贝赋值则多了监测是否为自我赋值、删除已有堆空间等操作。

代码如下:

inline string&string ::operator =(const string &str)

{
if(this==&str)

     return this;

delete[] m_data;

m_data=new char[strlen(str.m_data+1)];

strcpy(m_data;str.m_data);

return this;

}

深浅拷贝差别是什么?

浅拷贝:如果复制的对象中引用了一个外部内容(例如分配在堆上的数据),那么在复制这个对象的时候,让新旧两个对象指向同一个外部内容,就是浅拷贝。(指针虽然复制了,但所指向的空间内容并没有复制,而是由两个对象共用,两个对象不独立,删除空间存在)

深拷贝:如果在复制这个对象的时候为新对象制作了外部对象的独立复制,就是深拷贝。

两种拷贝区别是什么?

1)拷贝构造函数是一个对象初始化一块内存区域,这块内存就是新对象的内存区,而赋值函数是对于一个已经被初始化的对象来进行赋值操作。
2)一般来说在数据成员包含指针对象的时候,需要考虑两种不同的处理需求:一种是复制指针对象,另一种是引用指针对象。拷贝构造函数大多数情况下是复制,而赋值函数是引用对象

3)实现不一样。拷贝构造函数首先是一个构造函数,它调用时候是通过参数的对象初始化产生一个对象。赋值函数则是把一个新的对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检察一下两个对象是不是同一个对象,如果是,不做任何操作,直接返回。
999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999

何时执行拷贝构造函数

有下面三种情况:

1 用已有对象构造新对象的时候

Student stu;//先定义一个对象
Student stu2(stu);//(1)会调用拷贝构造函数
Student stu3=stu ;//(2)会调用拷贝构造函数,这里和(1)是一样的,仅仅是写法不同而已

如果对象已经被创建,会调用赋值操作符而不是复制构造函数:

Student stu;

Student stu2;//在这里被创建

stu2 = stu;//这里调用赋值操作符重载(见后文)

完整示例代码1:

#include <iostream>//cin cout
using namespace std;

class Student
{
public:
    //规则1:如果类的用户自己定义了构造函数
    // ,编译器就不会自动合成类的默认构造函数Student(void)
    //这样类就不存在默认构造函数了

    //类的用户自己定义了拷贝构造函数(拷贝构造函数也算是一个构造函数)
    //按照规则1,此时类不再拥有Student(void)这个函数
    Student(const Student& from)
    {
        cout << "copy constructor called." << endl;
    }

    //由于上面已经定义了一个构造函数,按照规则1,
    //Student stu;这条语句就会因为类不存在默认构造函数而编译报错
    //为了能够让我们可以写Student stu;这条语句来创建对象
    // ,我们在这里显示定义类的默认构造函数
    Student(void)
    {
        cout << "default constructor called." << endl;
    }
};

int main(int argv, char* argc[])
{
    cout << "flag1" << endl;//打印标记信息,用来查看函数执行的顺序
    Student stu;//先定义一个对象
    cout << "flag2" << endl;//打印标记信息,用来查看函数执行的顺序
    Student stu2(stu);//(1)会调用拷贝构造函数
    cout << "flag3" << endl;//打印标记信息,用来查看函数执行的顺序
    Student stu3 = stu;//(2)会调用拷贝构造函数,这里和(1)是一样的,仅仅是写法不同而已
    cout << "flag4" << endl;//打印标记信息,用来查看函数执行的顺序

    return 0;
}

2 给函数传递值类型参数的时候

void test_function(Student s)
{//s在该函数被调用的时候创建,该函数执行完之后释放
    s.m_name = "李四";//修改s的名字
}
int main()
{
    Student stu("张三");
    test_function(stu);//(1)创建stu的副本,函数内使用副本
    cout<<stu.m_name;//还是输出“张三”,因为修改的是,函数内的副本
}

参考:向函数传递参数

完整示例代码2:

#include <iostream>//cin cout
#include <string>
using namespace std;

class Student
{
public:
    Student(const Student& from)//拷贝构造函数
    {
        cout << "copy constructor called." << endl;
    }
    //如果只提供上面的拷贝构造函数,编译器就不再生成默认构造函数
    //,会而导致类对象就不可以直接创建,所以还需要提供一个默认构造函数
    Student(void)
    {
        cout << "default constructor called." << endl;
    }
    Student(const string& name) :m_name(name)
    {
        cout << "string constructor called." << endl;
    }
    string m_name;//存放学生姓名
};
void test_function(Student s)
{//s在该函数被调用的时候创建,该函数执行完之后释放
    cout << "flag2" << endl;
    s.m_name = "李四";//修改s的名字
    cout << "flag3" << endl;
}//s释放的时刻
int main()
{
    cout << "flag0" << endl;
    Student stu("张三");
    cout << "flag1" << endl;
    test_function(stu);//(1)创建stu的副本,函数内使用副本
    cout << "flag4" << endl;
    cout << stu.m_name;//还是输出“张三”,因为修改的是,函数内的副本
}

3 函数返回值类型对象的时候

Student get_copy(void)
{
    Student s;
    return s;//这里以s为参数构造构造一个副本,并返回副本,这里发生了拷贝
}

完整示例代码3:

#include <iostream>//cin cout
#include <string>
using namespace std;

class Student
{
public:
    Student(const Student& from)//拷贝构造函数
    {
        cout << "copy constructor called." << endl;
    }
    //如果只提供上面的拷贝构造函数,编译器就不再生成默认构造函数
    //,会而导致类对象就不可以直接创建,所以还需要提供一个默认构造函数
    Student(void)
    {
        cout << "default constructor called." << endl;
    }
};
Student test_function(void)
{//s在该函数被调用的时候创建,该函数执行完之后释放
    cout << "flag2" << endl;
    Student stu;
    cout << "flag3" << endl;
    return stu;
}//s释放的时刻
int main()
{
    cout << "flag1" << endl;
    test_function();//(1)创建stu的副本,函数内使用副本
    cout << "flag4" << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值