c++第十三章 -(副本构造器)

  • 逐位复制(bitwise copy):编译器将生成必要的代码把“源”对象各属性的值分别赋值给“目标”对象的对应成员的行为。对对象的地址赋值操作,于是乎,当删除一个对象时,它包含的指针也将被删除,但万一此时另一个副本(对象)还在引用这个指针,就会出问题!
  • 要是程序员在当初进行对象“复制”时能够精确地表明应该复制些什么和如何赋值,那就理想了。为解决该问题,我们可以对=操作符进行重载,其中对指针进行处理:MyClass &operator= (const MyClass &rhs);该语句的意思是表明这个方法所预期的输入参数应该是一个MyClass类型的、const常量不可改变的引用,并返回一个引用,该引用指向一个MyClass类的对象。

对赋值操作符重载的Demo:

class MyClass
{
public:
    MyClass(int *p);
    ~MyClass();

    MyClass &operator=(const MyClass &rhs);
    void print();
private:
    int *ptr;
};

MyClass::MyClass(int *p)
{
    ptr = p;
}

MyClass::~MyClass()
{
    delete ptr;
}

//MyClass a(1);MyClass(2);a = b;在这里已经对=操作符进行了重载
MyClass &MyClass::operator=(const MyClass &rhs)//传入一个const常量地址
{
    if (this != &rhs)
    {
        delete ptr;//删除掉a对象原有的ptr成员

        ptr = new int;//重新申请一块内存,表明了,现在有两个指针指向的地址是不一样滴,解决了2个指向指向同一块地址的问题
        *ptr = *rhs.ptr;//将传进来对象的值赋值给ptr
    }
    else
    {
        std::cout << "赋值号两边为同个对象,不做处理!\n";//
    }
    return *this;
}

void MyClass::print()
{
    std::cout << *ptr << std::endl;
}

int main(int argc, const char * argv[])
{
    MyClass obj1(new int(1));
    MyClass obj2(new int(2));

    obj1.print();
    obj2.print();

    obj2 = obj1;//这里=号已经重载了

    obj1.print();
    obj2.print();

    return 0;
}

控制台输出结果:

1
2
1
1

副本构造器何时被调用?当创建一个实例对象obj1,然后再创建实例obj2的同时用obj1的值对它进行初始化,此时,编译器将在MyClass类里寻找一个副本构造器(copy constructor),如果找不到,它会自行创建一个。即使我对之前的=操作符进行了重载,但由编译器(系统)创建的副本构造器仍以“逐位复制”的方法把obj1赋值给obj2。换句话说就是我们对=操作符进行了重载,“逐位复制”的行为仍然会发生。然而这个时候,我们就须要自定义一个副本构造器:MyClass(const MyClass &rhs);

副本构造器Demo:

class MyClass
{
public:
    MyClass(int *p);
    MyClass(const MyClass &rhs);//副本构造器
    ~MyClass();

    MyClass &operator= (const MyClass &rhs);
    void print();
private:
    int *ptr;
};

MyClass::MyClass(int *p)
{
    std::cout << "进入构造器\n";
    ptr = p;
}
MyClass::MyClass(const MyClass &rhs)
{
    std::cout << "进入副本构造器\n";
    *this = rhs;//这里的=操作符已经被重载了
}
MyClass::~MyClass()
{
    std::cout << "进入析造器\n";
    delete ptr;
}
MyClass &MyClass::operator=(const MyClass &rhs)
{
    std::cout << "进入赋值语句重载\n";
    if (this != &rhs)
    {
        delete ptr;

        ptr = new int;
        *ptr = *rhs.ptr;
    }
    else
    {
        std::cout << "赋值号两边为同个对象,不做处理!\n";//
    }
    return *this;
}
void MyClass::print()
{
    std::cout << *ptr << std::endl;
}
int main(int argc, const char * argv[])
{
    MyClass obj3(new int(3));
    MyClass obj4 = obj3;//

    obj3.print();
    obj4.print();

    return 0;
}

控制台输出:

进入构造器
进入副本构造器
进入赋值语句重载
3
3
进入析造器
进入析造器

c++第十三章 -(副本构造器),布布扣,bubuko.com

时间: 2024-10-07 15:04:24

c++第十三章 -(副本构造器)的相关文章

Java编程思想第四版读书笔记——第十三章 字符串

Java编程思想第四版读书笔记--第十三章 字符串 字符串的操作是计算机程序设计中最常见的行为. 关键词: StringBuilder ,StringBuffer,toString(),format转换,正则表达式, 1.不可变String String对象时不可变的.每当把String对象作为方法的参数时,都会复制一份引用.(其实就是对函数中参数列表中参数的操作不会影响外面的原参数) 如下: import static net.mindview.util.Print.*; public cla

《C++ Primer》读书笔记—第十三章 控制拷贝

声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 第III部分,类设计者的工具 1.类是C++的核心概念.每个类都定义了一个新类型和在此类型对象上可执行的操作. 2.当定义一个类时,我们显式或隐式地指定在此类型的对象的拷贝.移动.赋值和销毁时做什么.一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数(copy construcor),拷贝赋值运算符(copy-assignment operato

第二十三章

曲则全,枉则正,洼则盈,敝则新,少则得,多则惑.是以圣人执一,为天下牧.不自视故彰:不自见故明:不自伐故有功:弗矜故能长.夫唯不争,故莫能与之争.古之所谓「曲则全」者,几语哉!诚全归之. 罗大伦道德经文字版-第二十三章1 暂时的隐忍会换来更多 各位朋友大家好,今天我们接着来聊<道德经>.我们今天聊到了第二十三章了,慢慢改变,这也说明改变已经很巨大了,我们一点点学.一点点提升,我与您一起往前走.其实我在讲<道德经>的过程中,我也在提升,我也在学习,我们一起来学习,三年之约,我们不见不

第十三章、大规模数据库架构

第十三章.大规模数据库架构 内容提要: 1.了解分布式数据库技术 2.了解并行数据库技术 3.了解云数据库技术 4.了解XML数据库技术 第一节 分布式数据库 1.1.分布式数据库系统概述 分布式数据库系统与分布式数据库的区别: 分布式数据库系统--数据分布存储于若干场地,并且每个场地由独立于其它场地的DBMS进行数据管理.物理上分散.逻辑上集中的数据库系统. 分布式数据库--分布式数据库系统中各场地上数据库的逻辑集合. 1.2.分布式数据库目标与数据分布策略 分布式数据库目标: 12个目标:

javascript高级程序设计 第十三章--事件

javascript高级程序设计 第十三章--事件js与HTML的交互就是通过事件实现的,事件就是文档或浏览器窗口中发生的一些特定的交互瞬间. 事件流:事件流描述的是从页面中接收事件的顺序,IE的是事件冒泡流,Netscape的是事件捕获流,这个两个是完全相反的事件流概念. 事件冒泡:由最具体的元素接收,然后逐级向上传播到更高级的节点,即事件沿DOM树向上传播,直到document对象. 事件捕获:不大具体的节点应该更早接收到事件,相当于沿DOM节点树向下级传播直到事件的实际目标,在浏览器中,是

java-第十三章-类的无参方法(一)-查找客户姓名

package 上机练习; public class A02class { String names[] = new String[30]; public void showA(String name) { for (int i = 0; i < names.length; i++) { if (names[i] == null) { names[i] = name; break; } } } public void showB() { System.out.println("\t客户列表

java-第十三章-类的无参方法(一)-实现图形生成器

package 上机练习; public class A03class { public String showA(int rows, String ch) { for (int i = 0; i < rows; i++) { for (int j = 0; j <= i; j++) { System.out.print(ch); } System.out.println(); } return ch; } } package 上机练习; import java.util.Scanner; p

java-第十三章-类的无参方法(一)-模拟账户查询,实现存取款

package 上机练习; import java.util.Scanner; public class A04class { double Money = 0; public double showA() { return Money; } public void showB(double money) { Money += money; System.out.println("当前余额:" + Money); } public void showC(double money2) {

java-第十三章-类的无参方法(一)-代参方法的编程计算器

package 本章总结; public class A01class { public int ope(int Operator, int num1, int num2) { switch (Operator) { case 1: num1 += num2; break; case 2: num1 -= num2; break; case 3: num1 *= num2; break; case 4: num1 /= num2; break; default: System.out.print