首页
社区
课程
招聘
[分享]一道“简单”的c++题目(个人觉得还是要对c++对象模型有比较深刻的理解才行)
发表于: 2012-11-11 15:30 7871

[分享]一道“简单”的c++题目(个人觉得还是要对c++对象模型有比较深刻的理解才行)

2012-11-11 15:30
7871
class Base
{
public:
	virtual void fun()
	{
		printf("Base\n");
	}
};
class Mase:virtual public Base
{
public:
	void fun()
	{
		printf("Mase\n");
	}
	void add()
	{
		printf("add\n");
	}
};

int main()
{
	Base *p1=new Mase;
	p1->fun();
	delete p1;
	return 0;
}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 6
支持
分享
最新回复 (15)
雪    币: 14
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
		Mase()
	{

		Base base;

		PULONG_PTR Base_VTable =reinterpret_cast<PULONG_PTR>(dynamic_cast<Base*>(&base));
		PULONG_PTR Mase_Base_VTable = reinterpret_cast<PULONG_PTR>(dynamic_cast<Base*>(this));

		DWORD dwProtect;
		VirtualProtect((PVOID)Mase_Base_VTable, sizeof(ULONG_PTR), PAGE_READWRITE, &dwProtect);
		Mase_Base_VTable[0] = Base_VTable[0];
		VirtualProtect((PVOID)Mase_Base_VTable, sizeof(ULONG_PTR), dwProtect, &dwProtect);

	}

不要用 (int*)this获取虚函数表,虚函数表不是一定在第一个。(RTTI的影响等)
不要用Base::fun获取类成员指针,因为得到的是一个thunk。
--------------------------------------------------------------------------------------
知道C++内存布局是好事,不过尽量不要硬编码引用C++编译器生产的数据,不同的编译器会有差异的。
2012-11-11 17:58
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
看了您的代码跟建议还是很有收获的,非常感谢指点.自己写的代码灵活性实在太差了.
我这边写的:
	Mase()
	{
		//需要修改派生类的vptr用Base::fun替换掉
		int **x=(int**)*( (int*)this+2);
		typedef void  (Base::*Funx)(void);
		Funx temp;
		Base base;
		temp=**(Funx**)(&base);
		//temp=&Base::fun;//得到基类fun函数的地址是个thunk
		DWORD nOld=0;
		VirtualProtect(x,sizeof(x),PAGE_READWRITE,&nOld);
		int error=GetLastError();
		*x=(int*)*(int**)&temp;//覆盖掉派生类对象中基类vptr的第一项用基类fun函数地址替换Mase:fun
		VirtualProtect(x,sizeof(x),nOld,&nOld);
	}
见笑了.
2012-11-12 09:21
0
雪    币: 1358
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不错,学习了,理解c++更深刻了~
2012-11-16 17:00
0
雪    币: 326
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
请问这东西有神马实用价值?搞不明白。
2012-11-16 17:05
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
6
这个不就是高效C++55个做法中讲的构造函数内不能调用基类的虚函数的那一段吗,派生类的函数把基类的虚函数给覆盖了,名词覆盖。
2012-11-16 17:06
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
7
楼主是科锐的吧?????????
2012-11-16 17:09
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
8
百度一份答案来:
class A
{
public:
A(int sss = 0):x(sss)
{
}
virtual void Show()
{
cout << x << endl;
}
private:
int x;
};
class B : public A
{
public:
B(int s):A(s),y(s){}
void Show()
{
//A::Show 想在这里调用基类的Show
cout << y << endl;
}
private:
int y;
};
int main()
{
B s(0);
B s1(1);
s.Show();
s1.Show();
_getch();
return 0;
}
2012-11-16 17:16
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
9
重新温习了下C++,感觉收获了不少。

楼上有人改写虚函数表,然而虚函数表是由编译器分配在不可写的内存区域,要改必须调用系统函数(题目应该没让你#include<windows.h>吧?),这和打内存补丁没什么区别了。。。。。。。。而我们的类对象却是分配在可写的内存区的,改它的内容是可能的。所以我试了试直接改类对象的虚函数表指针。代码如下:

 
class Base
{
public:
virtual void fun()
{
printf("Base\n");
}
};
class Mase:virtual public Base //这个虚继承很关键!,因为本类中无新的虚函数,所以this处是VBT
{
public:
Mase()
{
int *vbtptr = *(int **)this;//注意,不是VFT
Base *p = new Base();//提取一个基类的虚函数表指针
*(int*)(vbtptr[1] +(int)this) = *(int*)p;//替换当前类继续的基类虚函数表指针
 
}
void fun()
{
printf("Mase\n");
}
void add()
{
printf("add\n");
}
};
 
int main()
{
Base *p1=new Mase;
p1->fun();
delete p1;
return 0;
}
2012-11-17 14:08
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
10
其实重点不是这个,小弟我也不是科锐的。。。。不过,小道消息:出此题的人是科锐的,哈哈
2012-11-17 16:19
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
11
楼主的思路清晰,小弟佩服了。其实题目没说不让修改内存属性(包含windows.h),给力!
2012-11-17 16:21
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
12
个人认为 此题的目的是让你搞清楚 什么时候建立虚表的,接着来个理论联系实际而已,证明你的猜想是正确的
2012-11-17 16:43
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
13
输出:
Base
Mase

答案(麻烦打下分数):
#include <stdio.h>
class Base
{
public:
virtual void fun()
{
printf("Base\n");
}
};
class Mase:virtual public Base
{
public:
Mase()
{
Base::fun();
}

void fun()
{
printf("Mase\n");
}
void add()
{
printf("add\n");
}
};

int main()
{
Base *p1=new Mase;
p1->fun();
delete p1;
return 0;
}
2012-11-17 16:58
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
14
要求如下:
通过给Mase添加构造函数实现让程序函数调用都输出Base。


可能是做卷思维定式了。如果空只给留在这个函数里,其它地方不让动,#include是不能在这儿用的.........
2012-11-17 17:38
0
雪    币: 90
活跃值: (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
潜力贴留名.Opera插图补丁.颜色补丁.字数补丁..
2012-11-17 19:44
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
16
[QUOTE=邓韬;1118633]输出:
Base
Mase

答案(麻烦打下分数):[/QUOTE]

怪我没有描述清楚吧。不是你的这个意思,你这个输出了2个结果,一次调用了基类的fun,一次调用了派生类的fun,这个题目的意思通俗点讲就是:如何阻止多态?方法基本上就是上面的2种:可以修改虚表指针vptr,也可以修改虚表中vtbl的内容,用基类的覆盖掉派生类的。
2012-11-18 00:12
0
游客
登录 | 注册 方可回帖
返回
//