首页 > 编程语言 >C++逆向分析——对象拷贝

C++逆向分析——对象拷贝

时间:2023-08-02 18:35:38浏览次数:37  
标签:逆向 对象 C++ 运算符 复制 Student 拷贝 构造函数

对象拷贝

我们通常存储对象,都用数组、列表之类的来存储,那如下所示我们使用数组来存储对象,但是在工作中发现这个数组不够用了,就需要一个更大的数据,但我们重新创建一个数组还需要把原来的数据复制过来;在C语言中可以使用函数来进行拷贝,直接拷贝内存,在C++中实际上跟C语言要做的事情是一样的,在C++中就称之为对象拷贝

C++逆向分析——对象拷贝_赋值运算符

拷贝构造函数

如何在C++中拷贝构造函数,来看一下如下代码:

C++逆向分析——对象拷贝_拷贝构造函数_02

可以看见我们定义了一个类,然后创建了两个对象obj、objNew,但是第二个对象的语法很奇怪,传入的参数是第一对象,其实这就是默认拷贝析构函数。

其本质就是很简单的内存复制:

C++逆向分析——对象拷贝_逆向分析_03

 

在vs2022里实验下:

#include <stdio.h>
struct Student {
	int a;
	int b;

	Student() {
		printf("Look.");
	}

	Student(int a, int b) {
		this->a = a;
		this->b = b;
	}

	~Student() {	
		printf("Look A.");
	}

};

void main() {
	Student s(1, 2);
	Student s2(s);
	return;
}

 反汇编码可以看到,的确就是无脑式的内存copy!

Student s(1, 2);
00FE458F 6A 02                push        2  
00FE4591 6A 01                push        1  
00FE4593 8D 4D F0             lea         ecx,[s]  
00FE4596 E8 2A CE FF FF       call        Student::Student (0FE13C5h)  
	Student s2(s);
00FE459B 8B 45 F0             mov         eax,dword ptr [s]  
00FE459E 8B 4D F4             mov         ecx,dword ptr [ebp-0Ch]  
00FE45A1 89 45 E0             mov         dword ptr [s2],eax  
00FE45A4 89 4D E4             mov         dword ptr [ebp-1Ch],ecx  
	return;

在odb里看到的内存copy示例(我觉得奇怪的就是为啥不是连续4个地址变量呢?):

C++逆向分析——对象拷贝_逆向分析_04

 

 

 

上面的内存复制是在栈中,而我们想在堆中去拷贝可以这样写:

CObject* p = new CObject(obj);

如上所示,我们是通过拷贝析构函数在内存中创建了一个新的对象,而如果该类本身有一个父类,父类会被拷贝吗?我们写一段代码来论证一下:

C++逆向分析——对象拷贝_逆向分析_05

那么这段代码,拷贝构造函数不仅可以将当前对象的内容复制,还可以将父类的内容复制过来。

拷贝构造函数是编译器已经提供的,其已经非常成熟了,通常情况下是不建议自己写拷贝构造函数的,除非出现类中包含指针类型的成员,这种情况是需要自己重些拷贝构造函数的,因为拷贝构造函数只是会拷贝当前指针成员的值,并不会拷贝指针成员指向的内容。

所以这种拷贝方式,我们可以称之为浅拷贝;而如果可以做到能够复制成员的情况下,还可以将指针指向的内存地址复制过来,并自动申请一块新的内存提供,这种方式我们称之为深拷贝

如果要实现深拷贝,我们就需要自己重写拷贝构造函数。

MyObject(const MyObject& obj) {

m_nLength = obj.m_nLength;

m_strBuffer = newchar[m_nLength];

memset(m_strBuffer, 0, m_nLength);

strcpy(m_strBuffer, obj.m_strBuffer);

}

C++逆向分析——对象拷贝_拷贝构造函数_06

需要注意的是这个格式是固定的,不要自己「自由发挥」。

总结:

  1. 如果不需要深拷贝,就不要自己添加拷贝构造函数;
  2. 如果你天假了拷贝构造函数,那么编译器将不再提供,所有的事情都需要由新添加的函数自己来处理。

重载赋值运算符

上一章学习了如何通过拷贝对象函数的方式来实现对象拷贝,这里就来学习使用重载赋值运算符实现对象拷贝。

在C++中是允许我们在两个对象之间直接使用赋值运算符的:

CObject a(1, 2), b(3, 4);

b = a;

C++逆向分析——对象拷贝_赋值运算符_07

那么赋值运算符实现的对象复制是否会当前复制对象继承的父类进行复制呢?

C++逆向分析——对象拷贝_赋值运算符_08

如上图所示,赋值运算符是可以复制父类的。

但是在这里赋值运算符是否就非常完美了呢?不是的,赋值运算符和拷贝构造函数是有相同缺点的,那就是其默认都是浅拷贝

我们想要解决这个问题就需要重写一个赋值运算符,自己来实现深拷贝

C++逆向分析——对象拷贝_拷贝构造函数_09

标签:逆向,对象,C++,运算符,复制,Student,拷贝,构造函数
From: https://blog.51cto.com/u_11908275/6941545

相关文章

  • C++逆向分析——模版
    模版假设有一个冒泡排序的函数:voidSort(int*arr,intnLength){inti,k;for(i=0;i<nLength;i++){for(k=0;k<nLength-1-i;k++){if(arr[k]>arr[k+1]){inttemp=arr[k];arr[k]=arr[k+1];arr[k+1]=temp;}}}}但是这个冒......
  • C++逆向分析——运算符重载
    运算符重载现在有一个类,其中有一个函数用于比较2个类的成员大小:#include<stdio.h>classNumber{private:intx;inty;public:Number(intx,inty){this->x=x;this->y=y;}intMax(Number&n){returnthis->x>n.x&&this->y......
  • C++逆向分析——多态和虚表
    虚表上一章了解了多态,那么我们来了解一下多态在C++中是如何实现的。了解本质,那就通过反汇编代码去看就行了,首先我们看下非多态的情况下的反汇编代码:然后再来看下多态情况下的反汇编代码:很明显这里多态的情况下会根据edx间接调用,而非多态则会直接调用。那么我们来看下间接调用的流程......
  • C++逆向分析——继承与封装
    面向对象程序设计之继承与封装之前已经学习过继承和封装了,但是要在实际开发中使用,光学语法和原理是不够的,在设计层面我们需要做一些优化。如下代码是继承的例子:#include<stdio.h>classPerson{public:intAge;intSex;voidWork(){printf("Person:Work()"......
  • C++逆向分析——引用
    voidmain(){intx=1;int&ref=x;ref=2;printf("%d\n",ref);return;}反汇编代码:intx=1;00724A5FC745F401000000movdwordptr[x],1int&ref=x;00724A668D45F4lea......
  • C++逆向分析——类成员的访问控制
    类成员的访问控制课外→好的编程习惯:定义与实现分开写,提升代码可读性。如下代码,Student这个类的所有成员我们都可以调用,但是我们不想让被人调用Print1这个方法该怎么?structStudent{intage;intsex;voidPrint1(){printf("FuncPrint1");}voidPrint(){......
  • C++逆向分析——new和delete new[]和delete[]
    在堆中创建对象我们可以在什么地方创建对象?全局变量区,在函数外面在栈中创建对象,也就是函数内在堆中创建对象注意:之前一直提到的堆栈实际上是两个概念->堆、栈,我们之前所讲的就是栈,从本章开始要严格区分。在C语言中,我们可以通过一个函数去申请一块内存,就是malloc(N);申请的这一块内存......
  • C++逆向分析——继承
    继承structPerson{intage;intsex;};structTeacher{intage;intsex;intlevel;intclassId;};如上代码中可以看见,Teacher类与Person类都存在着相同的2个成员age和sex,那么这就相当于重复编写了,我们可以通过继承的方式避免这样重复的编写(当前类名称:要......
  • C++逆向分析——this指针
    this指针概述C++是对C的拓展,C原有的语法C++都支持,并在此基础上拓展了一些语法:封装、继承、多态、模板等等。C++拓展新的语法是为了让使用更加方便、高效,这样就需要编译器多做了很多事情,接下来我们就需要一一学习这些概念。封装之前我们学习过结构体这个概念,那么结构体可以做参数传......
  • C语言逆向——预处理之宏定义、条件编译与文件包含
    预处理之宏定义、条件编译与文件包含预处理一般是指在程序源代码被转换为二进制代码之前,由预处理器对程序源代码文本进行处理,处理后的结果再由编译器进一步编译。预处理功能主要包括宏定义、文件包含、条件编译三部分。宏定义简单的宏:#define标识符字符序列#defineFALSE0#d......