首页 > 编程语言 >C++逆向分析——友元、内部类、命名空间和static

C++逆向分析——友元、内部类、命名空间和static

时间:2023-08-02 18:35:53浏览次数:41  
标签:友元 函数 int C++ Test static 命名

友元

友元可以理解为:朋友、元素;老师认为这个友元是C++中的一个垃圾,因为友元的存在破坏了面向对象的封装性,不推荐使用,之所以有这个章节是因为有人不了解这个概念

注意:在一些新版本的C++编译器里面已经不再提供类似于友元这样的特性了。

大家都知道在C++中对象的私有成员,外部是无法访问的,这在面向对象中是很正常的,如果你想访问按照正常的逻辑你应该在类中声明成员函数去增删改查这个私有成员。

C++逆向分析——友元、内部类、命名空间和static_Test

友元的诞生就是破坏了这个封装性,让你可以在外部去使用这个私有成员。

C++逆向分析——友元、内部类、命名空间和static_命名空间_02

友元的语法就是:friend 返回类型 函数名(参数列表)

老师个人认为C++之所以有友元是因为这是C++作者面向过程的一种妥协,这是因为C++是先有的C才有的C++,而很多人已经很熟悉C语言的语法了,你这时候推出一个新的概念,是对开发者的不友好(代码重构、学习代码),所以要妥协。

刚刚举例说明的是友元函数,就是告诉编译器这个函数是我的朋友,可以访问我的任何成员。

除了友元函数,还有加强版的垃圾:友元类,如下是语法格式:

class CObject {


 friend class Test;


private:


int x;


public:

 CObject() {}

 CObject(int x) {


this->x = x;

 }
};
 

class Test {


public:


void Fun(CObject* c) {


 printf("%d \n", c->x);

 }
};

以上代码就是告诉编译器,Test是CObject的朋友,所以Test可以直接访问CObject的私有成员;但是要注意的是,这种访问是单向的,Test可以访问CObject,但反之则不行。

内部类

内部类,简单的说就是在别的类里面定义的类就是内部类。

  • 大小:当前类和其内部类不存在包含关系,不会影响当前类的大小;

C++逆向分析——友元、内部类、命名空间和static_逆向分析_03

  • 关系:两者之间不存在什么特殊关系,也无法访问对方的私有成员;

C++逆向分析——友元、内部类、命名空间和static_内部类_04

  • 声明:声明创建内部类需要使用格式 → 类::内部类 名称;
  • 权限:如果你的内部类不想外部创建对象,那就定义到private内即可;而如果你用到这个内部类的情况非常的少,例如你只有一个成员函数需要使用到,那么完全可以定义到这个函数内;
  • 作用:如果我们需要实现一些功能而用到一个类,但是其他的模块、类用不到,我们可以就把这个类写到当前所需要使用类中。(隐藏

 

在我的vs2022里实验下:

#include <stdio.h>


class Date
{

public:
	int year;
	int month;
	int day;

	class Time
	{
	public:
		int hour;
		int minute;
		int secend;
	};
};

void main() {
	Date d;	
	int s = sizeof(d);
	printf("%d\n", s);
	return;
}

 答案是12. 因为没有使用Time。加一个Time t成员size就是24了。

 

命名空间

命名空间主要是用来解决命名冲突的问题;比如你定义了一个函数叫Fun,而如果你还想定一个函数也叫Fn,这种情况下就可以使用命名空间来解决这个问题。

命名空间的关键词:namespace,其语法格式如下:

namespace 名称x {

// 全局变量


// 函数


// 类

}
 
namespace 名称y {

// 全局变量


// 函数


// 类

}

C++逆向分析——友元、内部类、命名空间和static_命名空间_05

调用也很简单,使用格式:命名空间名称::函数\变量\类

如果我们命名空间内的东西非常多,但是你要调用就必须要加上前缀,这时候你可以在代码的首行写:

using namespace x;

但这也会引起命名冲突,如果命名空间x里面有一个Test函数,但是在正常代码中也存在Test函数,你想调用的是本身的该怎么办呢?实际上在C++中,你定义的所有东西都存在一个全局命名空间,而想调用可以使用如下语法:

::Test();

 

 

在我的vs2022里实验下:

#include <iostream>
using namespace std;

// 第一个命名空间
namespace first_space {
    void func() {
        cout << "Inside first_space" << endl;
    }
}
// 第二个命名空间
namespace second_space {
    void func() {
        cout << "Inside second_space" << endl;
    }
}
int main()
{
    // 调用第一个命名空间中的函数
    first_space::func();

    // 调用第二个命名空间中的函数
    second_space::func();

    return 0;
}

看下反汇编代码:

// 调用第一个命名空间中的函数
    first_space::func();
00CF2671 E8 4B EC FF FF       call        first_space::func (0CF12C1h)  

    // 调用第二个命名空间中的函数
    second_space::func();
00CF2676 E8 4C EB FF FF       call        second_space::func (0CF11C7h)

 可以看到就是编译器给函数加了一个名字而已!

 

static关键字

用static就是一个全局变量,只不过它是一个私有的全局变量。

在面向过程(没有对象的概念,用函数)中的static:

void Func() {

staticchar strBuffer[0x10];

strcpy(strBuffer, "test");

}

用static声明的全局变量,只有当前函数能访问;我们可以看下反汇编代码来论证这是一个全局变量:

C++逆向分析——友元、内部类、命名空间和static_内部类_06

如上图所示的这个内存地址,很明显就是一个全局区的地址(这也就表示相同变量只能申请一次,不再接受第二次申请,也就表示全局变量应用场景,你可以用这个关键词来实现)。

 

 

在我的vs2022里试验下:

#include <stdio.h>
#include <string.h>


void Func() {
	static char strBuffer[30] = "hello world";
	strcpy_s(strBuffer, "test");
}


int main ()
{
	Func();  
	return 0;
}

 看下反汇编代码:

C++逆向分析——友元、内部类、命名空间和static_命名空间_07

 

 在odb里看到的:

C++逆向分析——友元、内部类、命名空间和static_Test_08

 

 注意看到那一堆的push offset啥的 不要慌,就是一个static变量的内存地址。指向hello world

 

面向对象设计中的static之静态数据成员:

C++逆向分析——友元、内部类、命名空间和static_内部类_09

面向对象设计中的static之静态成员函数:

C++逆向分析——友元、内部类、命名空间和static_Test_10

static的经典应用:单子模式;有些时候我们希望定义的类只能有一个对象存在,这时候你该如何限制呢?实现思路有两个:

  1. 禁止对象被随便创建
  2. 保证对象只有一个存在

C++逆向分析——友元、内部类、命名空间和static_Test_11

标签:友元,函数,int,C++,Test,static,命名
From: https://blog.51cto.com/u_11908275/6941541

相关文章

  • C++逆向分析——对象拷贝
    对象拷贝我们通常存储对象,都用数组、列表之类的来存储,那如下所示我们使用数组来存储对象,但是在工作中发现这个数组不够用了,就需要一个更大的数据,但我们重新创建一个数组还需要把原来的数据复制过来;在C语言中可以使用函数来进行拷贝,直接拷贝内存,在C++中实际上跟C语言要做的事情是一......
  • 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++拓展新的语法是为了让使用更加方便、高效,这样就需要编译器多做了很多事情,接下来我们就需要一一学习这些概念。封装之前我们学习过结构体这个概念,那么结构体可以做参数传......