基于VS编译器探测成员函数指针的调用规则,并分析MFC消息映射实现机制的局限性问题

这篇具有很好参考价值的文章主要介绍了基于VS编译器探测成员函数指针的调用规则,并分析MFC消息映射实现机制的局限性问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

#include<iostream>
using namespace std;
class B1
{
	int b1;
public:
	void 	mfn1()
	{
		cout << "B1" << endl;
		cout << this << endl;
	}
	virtual void foo(){}
	virtual void fb1() {}
};

class B2
{
	int b2;
public:
	void 	mfn2()
	{
		cout << "B2" << endl;
		cout << this << endl;
	}
	virtual void fb2() {}
	virtual void foo() {}

};

class D :public B1, public B2
{
public:
	void 	mfd()
	{
		cout << "D" << endl;
		cout << this << endl;
		++d;
	}
	int d=0;
	
	virtual void foo() {}
	virtual void fb2() {}
};

int main()
{
	using mB1f = void(B1::*)();
	using mB2f = void(B2::*)();
	using mDf= void(D::*)();

	//D选择类的成员指针
	mDf df1 = &D::mfn1;
	mDf df2 = &D::mfn2;
	mDf dfd = &D::mfd;

	//D选择类的成员指针强转成基类选择类的成员指针
	mB1f mb1f = static_cast<mB1f>(df1);
	mB2f mb2f = static_cast<mB2f>(df2);

	D* ptr = new D;
	cout << ptr << endl;

	//用指针调用指向成员函数的指针时的偏移规则
	/*
	* 偏移发生在二个阶段
	* 1.调用指针,转换到选择类类型指针阶段;这个阶段只能隐式发生上向转换,或者指针类型一致;否则,即向下转换发生编译期错误
	* 2.调用函数阶段;将第一阶段转换后的指针传给成员函数;
		这时候只检测触发一种转换偏移,即若函数代码定义处的this指针参数的静态类型;如果是第一阶段转换后实际指针类型的基类;才发生向上转换偏移
		否则不检测任何错误【即便是基类到子类的向下转换也不检测】,直接硬传地址调用;这样代码段与this指针不匹配,一种代码混淆;基本确定造成运行期错误
	*/

	//按上述规则:
	//子类指针调用子类选择类中的成员指针,
	(ptr->*df1)();//第一阶段不发生偏移转换,第二阶段偏移转换为0
	(ptr->*df2)();//第一阶段不发生偏移转换,第二阶段发生偏移转换


	//子类指针调用基类选择类中的成员指针,
	(ptr->*mb1f)(); // 第一阶段偏移转换为0,第二阶段没有发生偏移转换
	(ptr->*mb2f)();// 第一阶段发生偏移转换,第二阶段没有发生偏移转换

	B1* pb1 = ptr;
	B2* pb2 = ptr;

	//基类指针调用基类选择类的成员指针
	(pb1->*mb1f)();//二阶段都没发生偏移转换
	(pb2->*mb2f)();//二阶段都没发生偏移转换
//!	(pb1->*df1)();  //基类指针调用子类选择类的成员指针,error:选择类不兼容

	cout << "------------------------" << endl;

	(ptr->*dfd)();//二阶段都没发生偏移转换
	mB1f mbd1 = static_cast<mB1f>(dfd);
	mB2f mbd2 = static_cast<mB2f>(dfd);

	(ptr->*mbd1)();//第一阶段偏移转换为0,第二阶段没有发生偏移转换【安全,因为安全转换的行为的转换量也是0】
	(ptr->*mbd2)();//第一阶段偏移转换,第二阶段没有发生偏移转换【危险: this指针的值已经与代码不匹配,代码混淆偏移】

	(pb1->*mbd1)();//第一阶段不发生偏移转换,第二阶段没有发生偏移转换【安全,因为安全转换的行为的转换量也是0】
	(pb2->*mbd2)();//第一阶段不发生偏移转换,第二阶段没有发生偏移转换【危险,因为往往这时的pb2已经是一个偏移值了,this指针的值已经与代码不匹配,代码混淆偏移】

	//指向变量的成员指针,相当于偏移到这个成员变量的偏移量、
	//指向静态成员变量或者静态成员函数的指针;就是这个变量或者静态成员函数的真实地址
	//指向普通成员函数的指针,其实也是这个成员函数的真实地址,但是有首个隐藏的this指针参数,这个this指针类型是编译期根据成员函数定义所在的类静态决定的,这个this指针参数所能接受的是同种类型指针间,或者子类型指针到基类型指针转换的调用【调用中根据偏移规则可能进行偏移】;
	//指向virtual成员函数的指针,实际上是一个结构体其中包含了virtual函数的索引,this指针偏移量等信息,参考<<深入探索C++对象模型>>;
	return 0;
}



/*
当想继承MFC的窗口类时,如果有多重继承,则继承的窗口类顺序要特别注意(要在继承列表的首个);
否则根据MFC消息映射机制的实现方式;调用指向成员函数指针时;根据前面的规则会触发代码混淆,导致运行期错误;如下:

这个也是MFC 窗体类继承顺序的问题的根本原因:https://www.debugease.com/vc/2194514.html
class CMyDlg : public TMyWndBase, public CMyClass
{
}; 如果把 TMyWndBase 写在后面,如下class CMyDlg : public CMyClass, public TMyWndBase
{
}; 然后 CMyDlg 定义 OnPaint 消息处理函数,这时便会出现断言错误
*/文章来源地址https://www.toymoban.com/news/detail-737692.html

到了这里,关于基于VS编译器探测成员函数指针的调用规则,并分析MFC消息映射实现机制的局限性问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包