首页 > 其他分享 >浅拷贝与深拷贝 以及嵌套和递归使用模板类

浅拷贝与深拷贝 以及嵌套和递归使用模板类

时间:2024-10-25 18:16:08浏览次数:9  
标签:tmp int items ii 嵌套 vv 拷贝 模板

 1. 浅拷贝和深拷贝——对象和类

浅拷贝

浅拷贝只复制对象的基本属性,而不复制引用类型的属性指向的对象,即只复制引用而不复制引用指向的对象

  • 在浅拷贝中,新对象与原始对象共享引用类型的属性指向的对象,即它们指向同一个对象。

  • 编译器提供的拷贝构造函数是浅拷贝,当一个对象修改了内存的数据,会影响到另一个对象。

  • 如果在析构函数释放内存,A释放了内存,那么B就成了野指针,发生不可预知的错误。

深拷贝

  • 深拷贝会复制对象的所有属性,包括基本类型和引用类型的属性,以及引用类型的属性指向的对象,以确保新对象与原始对象完全独立。
  • 在深拷贝中,复制引用类型的属性指向的对象,而不是简单地复制引用。
  • 深拷贝创建的对象与原始对象之间没有任何关联,修改一个对象不会影响另一个对象。

深拷贝的拷贝构造函数需要这么写:

class CGirl
{
    string m_name;
    int m_age;
    int* m_ptr;

    CGirl(){m_name.clear();m_age=0;m_ptr=nullptr;}

    // 深拷贝 重载默认的拷贝构造函数
    CGirl(const CGirl& gg)
    {
        m_name = gg.m_name;m_age = gg.m_age;
        m_ptr = new int;	// 分配内存
        memcpy(m_ptr,gg.m_ptr,sizeof(int));	// 拷贝数据
    }
};

深拷贝的赋值函数会在下面进行实现。


2. 嵌套和递归使用模板类

        这个内容是比较重要的!标准模板库都是要用到这个知识,经常嵌套或递归使用。

​        在C++11之前,嵌套使用模板类的时候,> >之间要加空格,为了与cin的>>区分开来。

​        以一种情况为例:如果把stack存入到vector中,是可以的,但是当stack不够要resize的时候就会出错,原因是:出现了浅拷贝!resize()扩展数组内存空间的函数中,把原数组的元素复制到新数组,如果复制的是类,并且类中使用了堆区内存,就存在浅拷贝的问题。Stack类成员变量items是指针,使用了堆区内存,要用深拷贝,也就是说,对于Stack这种类,一定要重写拷贝构造函数和赋值函数。代码中用的赋值函数,那么就要为Stack类重写赋值函数,实现深拷贝。

​        需要对Stack类和Vector类的赋值函数进行重写,实现深拷贝:

// 用模板类实现一个栈
#include<iostream>
#include<string.h>
using namespace std;

// 类模板
template <class DataType>
class Stack
{
private:
    DataType *items;
    int stacksize;
    int top;
public:

    Stack(int stacksize = 3):stacksize(stacksize),top(0)
    {
        items = new DataType[stacksize];
    }
    ~Stack()
    {
        delete []items; items = nullptr;
    }

    // 重写赋值函数,实现深拷贝,解决不能嵌套调用的问题
    Stack& operator=(const Stack& ss)
    {
        stacksize = ss.stacksize;   top = ss.top;

        DataType* tmp = new DataType[stacksize];
        for(int ii=0;ii<stacksize;ii++) tmp[ii] = ss.items[ii];
        delete []items;
        items = tmp;
        tmp = nullptr;

        return *this;
    }

    bool isempty()
    {
        return top == 0;
    }

    bool IsFull()
    {
        return top == stacksize;
    }

    bool push(const DataType& val)
    {
        if(IsFull())    {cout<<"栈已满"<<endl;    return false;}
        items[top] = val;
        top++;
        return true;
    }

    bool pop(DataType& elem)
    {
        if(isempty())   {cout<<"栈已空"<<endl;    return false;}
        top--;
        elem = items[top];
        return true;
    }
};

template <class T>
class Vector
{
private:
    T *items;       // 数组元素
    int len;        // 数组元素的个数。
public:
    Vector(int size = 2):len(size)
    {
        items = new T[len];
    }
    ~Vector()
    {
        delete []items;items = nullptr;
    }

    // 重写赋值函数,实现深拷贝,解决不能嵌套调用的问题
    Vector& operator=(const Vector& vv)
    {
        this->len = vv.len;
        delete[] items;
        items = new T[vv.len];
        for(int ii=0;ii<this->len;ii++) items[ii] = vv.items[ii];

        return *this;
    }

    bool resize(int size)
    {
        if(this->len>=size)    return false;

        T *tmp = new T[size];
        for(int ii=0;ii<this->len;ii++) tmp[ii]=items[ii];
        delete []items;
        items = tmp;
        this->len = size;

        return true;
    }

    int size() const { return len; }     // 获取数组长度。

    T& operator[](int index)  // 重载操作符[],可以修改数组中的元素。
    {
        if(index>=this->len)    resize(index+1);

        return items[index];
    }

    const T& operator[](int index) const  // 重载操作符[],不能修改数组中的元
    {
        return items[index];
    }
};

int main()
{
    
    // Vector容器的大小缺省值是2,Stack容器的大小缺省值是3。
	// 创建Vector容器,容器中的元素用Stack<string>。
	Vector< Stack<string> > vs;         // C++11之前,>>之间要加空格。
               
	// 手工的往容器中插入数据。
	vs[0].push("西施1"); vs[0].push("西施2"); vs[0].push("西施3");        // vs容器中的第0个栈。
	vs[1].push("西瓜1"); vs[1].push("西瓜2"); vs[1].push("西瓜3");        // vs容器中的第1个栈。
	vs[2].push("冰冰");   vs[2].push("幂幂");                                            // vs容器中的第2个栈。 
	
	// 用嵌套的循环,把vs容器中的数据显示出来。
	for (int ii = 0; ii < vs.size(); ii++)         // 遍历Vector容器。
	{
		while (vs[ii].isempty() == false)      // 遍历Stack容器。
		{
			string item; vs[ii].pop(item); cout << "item = " << item << endl;
		}
	}
    

    
    // 创建Stack容器,容器中的元素用Vector<string>。
	Stack<Vector<string>> sv;
              
	Vector<string> tmp;       // 栈的元素,临时Vector<string>容器。
	// 第一个入栈的元素。
	tmp[0] = "西施1"; tmp[1] = "西施2";  sv.push(tmp);
	// 第二个入栈的元素。
	tmp[0] = "西瓜1"; tmp[1] = "西瓜2";  sv.push(tmp);
	// 第三个入栈的元素。
	tmp[0] = "冰冰1"; tmp[1] = "冰冰2";   tmp[2] = "冰冰3";  tmp[3] = "冰冰4";  sv.push(tmp);
              
	// 用嵌套的循环,把sv容器中的数据显示出来。
	while (sv.isempty() == false)
	{
		sv.pop(tmp);   // 出栈一个元素,放在临时容器中。
		for (int ii = 0; ii < tmp.size(); ii++)   // 遍历临时Vector<string>容器,显示容器中每个元素的值。
			cout << " vs[" << ii << "] = " << tmp[ii] << endl;
	}

	// 创建Vector容器,容器中的元素用Vector<string>。
	Vector<Vector<string>> vv;       // 递归使用模板类。
               
	vv[0][0] = "西施1"; vv[0][1] = "西施2";  vv[0][2] = "西施3";
	vv[1][0] = "西瓜1"; vv[1][1] = "西瓜2";
	vv[2][0] = "冰冰1"; vv[2][1] = "冰冰2";   vv[2][2] = "冰冰3";  vv[2][3] = "冰冰4";
            
	// 用嵌套的循环,把vv容器中的数据显示出来。
	for (int ii = 0; ii < vv.size(); ii++)
	{
		for (int jj = 0; jj < vv[ii].size(); jj++)
			// cout << " vv[" << ii << "][" << jj << "] = " << vv[ii][jj] << endl;
			cout << vv[ii][jj] << " ";
		cout << endl;
	}

    return 0;
}

标签:tmp,int,items,ii,嵌套,vv,拷贝,模板
From: https://blog.csdn.net/weixin_56520780/article/details/143232901

相关文章

  • 一图胜千言,PPT中的数据分析模板样式
    PPT中数据可视化是一种将数据以图形或图表的形式展示出来的方法,它可以帮助观众更直观地理解数据所传达的信息。数据可视化是一个不断发展的领域,随着技术的进步,新的工具和方法不断出现,使得数据的呈现更加直观和互动。在笔格PPT,选择合适的样式模板便可直接制作图表,小编带来了各......
  • 网站修改意见文档模板?
    创建一个网站修改意见文档时,可以遵循以下模板结构,以确保信息清晰、全面且易于理解:网站修改意见文档1.文档基本信息文档标题:版本号:作者:日期:审核人:2.项目概述项目名称:项目背景:目标用户:主要功能:3.修改意见概览序号当前问题建议改进责任人预计完......
  • 如何修改网站模板的图片?后台如何修改网站内容?
    修改网站模板的图片登录后台管理系统:通常需要通过网站提供的管理员入口登录到后台管理系统。导航至模板管理:在后台找到“模板管理”或“外观设置”等相关选项。选择要编辑的模板:如果有多个模板可选,选择当前正在使用的或准备使用的模板。进入图片管理:在模板......
  • 网站模板做好了怎么修改?
    网站模板的修改通常涉及以下几个步骤:备份原始文件:在开始任何修改之前,确保备份原始的网站模板文件。这可以在出现问题时帮助你快速恢复。确定修改需求:明确你需要对网站模板进行哪些具体的修改,比如颜色调整、布局改动、功能增加等。使用合适的工具:根据模板的技术栈......
  • pbootcms修改默认首页index.html模板名称
    步骤定位到控制器文件打开 /apps/home/controller/IndexController.php 文件。查找 getIndexPage 方法在该文件中找到 privatefunctiongetIndexPage() 方法。修改模板名称在 getIndexPage 方法中,找到返回模板名称的代码块,通常如下所示:php retur......
  • 网站模板修改上传图片?模板如何修改网站logo?
    确定图片上传的位置确定在网站的哪个部分需要添加图片上传功能,例如用户资料页面、产品详情页等。HTML表单设置在需要上传图片的地方添加一个表单,使用 <form> 标签,并确保 enctype 属性设置为 multipart/form-data,这允许文件数据被正确编码。<formaction="/up......
  • C++模板
    模板初阶如何实现一个通用的加法函数?我们可以类似这样使用函数重载的方法进行编写intsum(int&a,int&b){ returna+b;}doublesum(double&a,double&b){ returna+b;}使用函数重载虽然可以实现,但是有一下几个不好的地方:1.重载的函数仅仅是......
  • Day 11 函数对象 + 函数的嵌套 + 名称空间与作用域
    目录0昨日复习0.1函数0.2定义0.3三种形式的函数0.3.1无参函数0.3.2有参函数0.3.3空函数0.4函数的返回值0.5函数的调用0.6函数参数的应用0.6.1形参0.6.2实参0.6.3位置形参0.6.4位置实参0.6.5默认形参0.6.6关键字实参0.7可变长参数0.7.1*形参0.7.2*实参0.7.3**......
  • node根据模板生成pdf,并在pdf中插入文本信息,水印,签章。
    要求通过node生成司机小程序需要的pdf,并在pdf插入信息,用户签章,公司签章,水印等。第三方插件#pdf-lib版本1.17.1。读取pdf模板,插入信息,签章,水印。#@pdf-lib/fontkit版本1.1.1。加载pdf插入信息时所需的字体文件ttf。#canvas版本2.11.2。根据用户名形成用户签章(文字......
  • 使用yield压平嵌套字典有多简单?
    我们经常遇到各种字典套字典的数据,例如:nest_dict = {    'a': 1,    'b': {        'c': 2,        'd': 3,        'e': {'f': 4}    },    'g': {'h': 5},    'i': 6,    'j�......