逆向-reverse

c++

1,封装

封装:将函数写入结构体内部(但函数不占用结构体的内存空间)
类:带有函数的结构体叫类
底层c和c++没有区别,唯一的区别是编译器帮我们做了很多事情

一般不用结构体作参数,因为设计大量的内存复制,所以一般传结构体指针

2,this指针

通常情况下,编译器会使用ecx寄存器来传递当前的this指针(在反汇编中区分c和c++的重要特点)

3,构造函数与析构函数

4,继承

本质:数据的复制

5,类成员的访问控制

6,在堆中创建对象

new的本质
跟进一系列函数,最终调用HeapAlloc
所以new的本质就是,malloc + 构造函数

仔细观察c和c++的不同

delete[] p 和 delete p
前者删除所有对象,后者只销毁一个

7,引用类型

基本类型的引用类型

类的引用类型

指针的引用类型

数组的引用类型

引用的本质:指针

引用与指针的区别:
1,必须初始化,而且只能指向一个变量,从一而终
2,对引用运算是对其指向的变量做运算,而不是对引用本身做运算
3,引用类型是一个“弱化了的指针”

void Plus(int& i)
{
	i++;
}

int main()
{
	int a = 1;
	Plus(a);

	system("pause");
}

常引用 void print(const Base& b1)

8,面向对象程序设计之继承与封装

合法但不合理的情况
手机设计将电路板藏起来,但是提供按钮给人们使用
子类的构造函数默认里面会call父类的无参构造函数(反汇编层面)
当父类没有构造函数,子类里面无call
结论:基类如果有构造函数,一定给子类提供一个无参的构造函数

若在子类的构造函数里面想要调用父类的有参构造函数,可以这样写
Teacher(int child,int father1,int father2):Person(father1,father2)

main()

9,多态

安全的做法:用父类对象的指针来指向子类对象
不安全的做法:用子类的对象指针来指向父类的对象(编译器不通过,但是可以强制类型转换)
多态:可以让父类指针有多种形态
实现方法:通过虚函数实现多态性 virtual

纯虚函数
作用:规定子类都来提供这样一个接口
如果基类中的函数没有任何实现的意义,那么可以定义为纯虚函数
含有纯虚函数的类称为抽象类,不能创建对象,纯虚函数必须在子类中实现才可以使用

10,虚表

#include "stdafx.h"
#include <stdlib.h>

class Father
{
public:
	virtual void Print()
	{
		printf("father\n");
	}
};

class Child:public Father
{
public:
	void Print()
	{
		printf("child\n");
	}
};

void print(Father* f)
{
	f -> Print();
}

int _tmain(int argc, _TCHAR* argv[])
{
	Father f1;
	Child c1;
	print(&f1);
	system("pause");
	return 0;
}

可以看到,当我们使用多态时,调用的函数与我们传入的对象有关,我们称之为间接调用

如果在父类中不加virtual关键字,那么默认就call父类中的函数

结论:只要使用虚函数,都是间接调用
多态是通过间接调用实现的,没有间接调用,就没有多态
多态 = 间接调用 + 虚表

当没有虚函数时,类的大小就是基本类型的大小*个数,当有虚函数存在时,切无论有几个虚函数,其占用的内存空间都会加上4(虚表大小)

观察虚表:

在对象最开始的地方占用4个字节,里面存着虚表的地址

11,运算符重载

bool类型的本质等同于char类型
本质:给运算符关联一个函数

12,模板

模板的本质:编译器替我们生成多份函数,比如我们需要int和char,那么编译器就会给我们生成2份代码,不同类型的各一份

事例:函数模版和类模板

template <class T>
void Sort(T* arr,int len)
{}
int main()
{
char arr[] = "123",b = 2;
Sort(arr,b);
}
template <class T,class M>
class A
{
T a1;   M a2;
};
int main() { A<int,char>  obj;}

13,纯虚函数

语法:
virtual int max() = 0;

含有纯虚函数的类,称为抽象类,抽象类也可以包含普通的函数
抽象类不能实例化

作用:抽象类看成是一个任何该类的子类都必须遵守的标准
(比如淘宝店都有相同的功能模块,但是内容各不相同,所以可以用一个抽象类来作一个标准,真正实现的是在子类中)

14,对象拷贝—拷贝构造函数

如果不需要深拷贝,不要自己添加拷贝构造函数
父类也会拷贝
本质:内存的复制

15,对象拷贝—重载赋值运算符

16,友元

垃圾语法,破坏了c++的封装特性,不建议使用
(为什么有呢?是向面向过程的妥协,先有c语言再有c++,之前程序员写了很多代码,但是有了c++之后,不加友元有些类的private的成员就不能访问了,是一种妥协)
在之后的面向对象中(java,c#)就没有友元这个东西了

17,内部类

在别的类里面定义的类叫做内部类
在内存上毫无关系,在权限上也毫无关系
总结:内部类和它外面的类毫无关系

作用:要想创建内部类必须写完整的名字而且内部类得在public权限里面

outer::inner obj;

内部类存在的唯一价值:外类的某个函数会用到内部类,就把内部类定义到private权限里面就可以了,别的类不需要用,完美体现了封装隐藏的特性
如果只有一个函数需要这个类,甚至可以将一个类定义到一个函数里面,当使用这个函数时这个类才有价值

18,命名空间

作用:解决命名冲突的问题
命名冲突问题
终极解决方案:命名空间

namespace name1{
1,全局变量
2,函数
3,类
}

不同命名空间里面的内容可以完全一样
访问的时候这样写

ns1::x
ns1::func()
ns1::Cobj obj;

本质:给名字起个前缀

19,static关键字

static修饰局部变量,作用:私有的全局变量(只能当前函数使用)

posted @ 2020-11-01 21:31  lemon想学二进制  阅读(331)  评论(0编辑  收藏  举报