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

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

时间:2024-10-25 18:16:08浏览次数:17  
标签: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

相关文章

  • node根据模板生成pdf,并在pdf中插入文本信息,水印,签章。
    要求通过node生成司机小程序需要的pdf,并在pdf插入信息,用户签章,公司签章,水印等。第三方插件#pdf-lib版本1.17.1。读取pdf模板,插入信息,签章,水印。#@pdf-lib/fontkit版本1.1.1。加载pdf插入信息时所需的字体文件ttf。#canvas版本2.11.2。根据用户名形成用户签章(文字......