??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
: 比如我有一个CMyButton的类Q我现在有他的一个handle
: ~译器怎么Ҏq个句柄扑ֈCMyButton的代码的Q?/em>
??某某 的大作中提到: ?br>: q个和OS/Compiler没关p,是库L作用
: 以从某个文章里看的,说MFC用了一个大mapQ没验证q?br>: 有本讲GDI的书里,用了WNDCLASS里的extra bytes来实现的q个映射
MFC的应用里Q每个MFCU程Q必要使用MFC方式启动的线E)都维护有一个MFC object和HWND之间?/p>
mappingQ整个MFC框架是使用q个机制来实现应用C++对象和系l原生H口内核对象之间的关联;
因ؓq个mapping是以U程为单位来l护的,每个U程间互不关联,所以,一个应用里对于涉及UIH口?/p>
d最好是都放在同一个线E里面,一般就是当前进E的ȝE,否则可能出现MFC object和HWND之间
兌不上的问题,而且q样的问题还很隐蔽?br>
至于WNDCLASSl构自带的extra bytes域,是以前缺乏应用框架的时代Q用Win32 API直接开发时Q让每个
H口c(q里的类Q不是C++ class的概念,而是WindowspȝH口定义时的一U数据结构)都能有个?/p>
带一些额外的自定义数据的I间Q这个空间往往被用来存放与当前H口cȝ关的用户数据Q通常是指?/p>
某个内存区域的指针,当程序操作这个属于这个窗口类的窗口时可以根据这个附带的自定义数据(?/p>
者指针)来操作对应的兌自定义数据;很多后来出现的框Ӟ也都使用了这个extra bytes域,来存?/p>
框架本n的一些和H口cȝ兌的数据结构。从目前势看,直接使用WNDCLASS以及extra bytes的可?/p>
性是微乎其微了,但是如果要做好原生应用的开发,很多底层的实现细节最要还是要知道一下,以便?/p>
优化l构和性能Q以及出错时的调试处理;因ؓ无论是Winform/WPFQ还是跨q_的WTL/QT/WxWindows{?/p>
{新型的机制或者框架、类库,只要是在Windowsq_上搭建的Q那都是Z前面说过的这套最基本也是
最核心的Win32 API基础之上?/p>
初看之下Q给人的感觉是图论相关的问题Q比如旅行者问题、欧拉环怹cR?/p>
在思考这个问题的时候,忽然间联惛_了图Z的最生成树Q虽然ƈ不是真正要去得出最生成树Q?/p>
但是按照最生成树所提供的思\--q点很重?-那就是图和树之间有着相当密切的关p:即最生
成树q不能直接解册个问题,但是它们之间存在的这层关pȝ提供了解决问题的一个有益的试?/p>
向;
于是Q思考进了一步,问题?#8220;?#8221;化成?#8220;?#8221;--如何把当前这个问题采用树的结构和Ҏ表达?/p>
来:树的根节点,很自然地惛_了由问题中旅行的起始节点来表达;然后Q随着节点的不断加入,树就
自然地生成,此处的关键在于如何生成,或者说节点加入的规则,以及每个节点Z适应q个规则Q所
必须持有的相兛_性信息:最直接的,父子节点之间的关p需要维护,从父节点到子节点的距(或代
P必须要保留,其次Q考虑到如果每个节炚wl护相关的距(代hQ信息,那么从当前节点到根节
点的代h也就可以由此递推得出Q进一步,我们所要求出的最短\径(或最代P不就可以从上q这
些节点中l护的距M息中得出吗?q是非常关键的一步,它把当前我们构徏的数据结构和问题的要?/p>
之间建立起了相当直接的联pR这说明我们目前思考的方向是有价值的而且极有可能着q个方向前行
Q可以得出相当不错的l果?/p>
昄Q既然要求最短\径(最代PQ那么我们目前构建出的这颗Junction树(因ؓ其上的节点在?/p>
中的物理含义是代表JunctionQ那q里我们姑且称其ؓJunction TreeQ,树上的每个节点也应当保留
在其之下的子树的最短\径(最代PQ这q当于把每个节炚w作ؓ根节点,然后求出各条子\?/p>
的代Pq比较得出最短\径(最代PQ以及在q条最短\径上的直接子节点Q?/p>
每加入一个子节点Q就要对上述已构建出的这些数据结构中的信息进行维护,以调整每个节点当前的最
短\径代价和相应q条路径上的直接子节点;当所有原“?#8221;中的“?#8221;信息Q也是
(fromJunction,toJuction,ductLength)所代表的(起始点,l止点,长度代hQ,都按照上q方案加?/p>
Juction Tree之后Q我们可以知道从最初的起始节点Q也是Junction Tree的根节点Q到最l节点的Q?/p>
Junction Tree上的某条路径上的叶子节点Q的最短(最代P路径了?/p>
对于Juction Treeq个ADT抽象数据l构的具体实玎ͼ考虑C先队列中二叉堆的l典实现往往使用数组
Q同时也ZW合TC SRM一贯的h快的E序设计风格Q我们这里同时用几个数l来l护前述构徏
出的数据l构?/p>
//////////////////////////////////////////////////////////////////////////////////////////
#include<cstdlib>
#include<vector>
#include<set>
using namespace std;
const int NIL = -1;
const int MAX = 50;
int Cost[MAX];
int ParentNode[MAX];
int MaxSubNode[MAX];
int MaxSubCost[MAX];
class PowerOutage
{
public:
int estimateTimeOut(vector<int> fromJunction, vector<int> toJunction, vector<int>
ductLength)
{
if (!CheckParameter(fromJunction, toJunction, ductLength)) return NIL;
Ini();
int count = fromJunction.size();
for (int i = 0; i < count; i++)
{
AddNode(fromJunction[i], toJunction[i], ductLength[i]);
}
return CalculateMinCost(fromJunction, toJunction, ductLength);
}
private:
void Ini()
{
memset(Cost, NIL, sizeof(int) * MAX);
memset(ParentNode, NIL, sizeof(int) * MAX);
memset(MaxSubNode, NIL, sizeof(int) * MAX);
memset(MaxSubCost, 0, sizeof(int) * MAX);
}
bool CheckParameter(const vector<int>& fromJunction, const vector<int>& toJunction,
const vector<int>& ductLength)
{
if (fromJunction.size() != toJunction.size() || toJunction.size() !=
ductLength.size())
return false;
return true;
}
void AddNode(int parent, int child, int cost)
{
if (parent < 0 || child < 0 || cost < 0) return;
Cost[child] = cost;
ParentNode[child] = parent;
int curParent = parent, curChild = child;
bool adjustParentCost = true;
while (adjustParentCost && curParent != NIL)
{
int candidateParentMaxSubCost = Cost[curChild] + MaxSubCost
[curChild];
if (MaxSubCost[curParent] < candidateParentMaxSubCost)
{
MaxSubCost[curParent] = candidateParentMaxSubCost;
MaxSubNode[curParent] = curChild;
curChild = curParent;
curParent = ParentNode[curParent];
}
else
{
adjustParentCost = false;
}
}
}
int CalculateMinCost(const vector<int>& fromJunction, const vector<int>&
toJunction, const vector<int>& ductLength)
{
int len = fromJunction.size();
int minCost = 0;
set<int> minCostPath;
minCostPath.insert(0);
int curNode = MaxSubNode[0];
while(curNode != NIL)
{
printf("%d;",curNode); // print the min cost path
minCostPath.insert(curNode);
curNode = MaxSubNode[curNode];
}
for (int i = 0; i < len; i++)
{
if (minCostPath.find(toJunction[i]) == minCostPath.end())
minCost += 2 * ductLength[i];
else
minCost += ductLength[i];
}
return minCost;
}
};
恰恰相反Q有些反的Ҏ是l常会被使用到的?/p>
反射M上分成两大特性,一是自省,二是发射Q?/p>
自省的能力极为重要,而且几乎会天天用刎ͼ很少见到q哪?net应用中不使用attribute的,而attributeҎ就是metadata通过在自省能力支撑下实现的;当然自省不单单是attributeҎ的q用Q只要是在运行时动态检视程序自w的Ҏ都要由反射的自省能力来支持Q比如Visual Studio的IDEQ这个集成开发环境本w就?net应用的好案例Q对?netlg的自动探功能;同时Q自省的能力也是Z虚拟机^台的语言Q比如c#和javaQ区别于传统语言比如c和c++的重要特性之一Q这提供了程序设计开发更Z利和安全的运行时环境Q相对而言Q在c++Q当然是native而不是managedQ的环境下,除了RTTI极ؓ单薄的运行时自省Q也是QTq个库通过meta-object system部分模拟了自省的Ҏ;
反射的另外一个重要特性就是发,它让“E序可以写程?#8221;了,要的说就是在q行时动态生成MSILq加载运行以及持久化动态生成的MSIL的能力;p个特性的支持Q让原先一些程序设计和开发领域相对困隑֒J琐的工作,比如元编Emeta programmingQ比如动态代理dynamic proxyQ比如AOP中的基础设施weaver的实玎ͼ变得可能或相Ҏ于实玎ͼ反射的特性,也是Z虚拟机^台CLR的支持,以metadata为基来实现的Q所以这也是虚拟机^台语a的特有优势,而在传统语言q_上,q是难以实现的;比如关于meta programmingQc++是通过模板Ҏ实现的~译期meta programmingQ这与虚拟机q_上实现的q行时meta programmingq是有比较大的差距(比如前者如何保证生成的代码的type-safeQ;
以上q两个特性,自省和发,都有个共同点Q他们都是围l着metadata机制Qƈ在虚拟机q_q行时环境CLR支持下实现的Q前者是q行时检视相关的metadataQ后者是q行时动态生成相关的metadata和MSILQ从q点也就可以看出Q要x入理解这些特性,需要研Imetadata和MSIL的实玎ͼ以及虚拟行时环境的实玎ͼ在javaq_上,是bytecode和JVMQ;
所以,反射Q可能是虚拟机^台所提供的相Ҏ为强Ԍ最为复杂,和^台运行时本n关系最密切Q也是区别于传统语言和运行时最鲜明的特性?/p>
CRT incorrectly set a lock at _global_unlock which resulted in such issue.
In CLR-mixed mode, during the inialization of static local object, CRT would call _atexit_m(_CPVFV func) in msilexit.cpp to register a special __clrcall callback function which would be called back to destroy such static object when the current AppDomain quited.
In the multithread environment, _atexit_helper which was invoked by _atexit_m, could register such callbace function successfully because it had been guarded by __global_lock() and __global_unlock(). But in the same environment, the _atexit_m would fail to assign the correct value to __onexitbegin_m and __onexitend_m.
__onexitbegin_m and __onexitend_m were shared by the different threads; It's the key point of such issue. For example, the following statements,
__onexitbegin_m = (_CPVFV *)_encode_pointer(onexitbegin_m);
__onexitend_m = (_CPVFV *)_encode_pointer(onexitend_m);
should also guarded by __global_lock() and __global_unlock() or other syn primitives.
__global_lock();
__onexitbegin_m = (_CPVFV *)_encode_pointer(onexitbegin_m);
__onexitend_m = (_CPVFV *)_encode_pointer(onexitend_m);
__global_unlock();
extern "C" int __clrcall _atexit_m(_CPVFV func)
{
MANAGED_ASSERT(AppDomain::CurrentDomain->IsDefaultAppDomain(), "This fuction must be called in the default domain");
__global_lock();
_CPVFV* onexitbegin_m = (_CPVFV*)_decode_pointer(__onexitbegin_m);
_CPVFV* onexitend_m = (_CPVFV*)_decode_pointer(__onexitend_m);
__global_unlock();
int retval = _atexit_helper((_CPVFV)_encode_pointer(func), &__exit_list_size, &onexitend_m, &onexitbegin_m);
__global_lock();
__onexitbegin_m = (_CPVFV*)_encode_pointer(onexitbegin_m);
__onexitend_m = (_CPVFV*)_encode_pointer(onexitend_m);
__global_unlock();
return retval;
}
The error comes directly from the CLR when a type has multiple definitions that are not consistent based upon the ODR, one-definition-rule for types. And, the linker itself isn't involved.
For example, with one module compile with /D_SECURE_SCL=0, while another is compiled with _SECURE_SCL=1;
At first, it's found that with _SECURE_SCL, the only thing that could be different as following,
#if _SECURE_SCL
typedef _Range_checked_iterator_tag _Checked_iterator_category;
#endif
But, actually, it's not the typedef that changed the layout the these iterators (istreambuf_iterator/ostreambuf_iterator), and further they don't really use the extra pointer that _SECURE_SCL adds.
Finally, it's found the root cause is that, these iterators, istreambuf_iterator/ostreambuf_iterator had been moved from <xutility> to <streambuf>, and their ultimate base class had been changed from _Iterator_base_secure to _Iterator_base. And, the layout of _Iterator_base would be different between HID and no-HID, and between SCL and no-SCL. It is the cause where the issue comes from.
What we can learn from such issue,
These iterators really shouldn't derive from either _Iterator_base_secure or _Iterator_base, because these classes contain data members (pointers) which are entirely unused. It would result in unnecessary bloat and extra work being performed in ctor/dtor etc.
Introduce a new class, _Iterator_base_universal, which is defined identically regardless of HID/no-HID and SCL/no-SCL. It would contains the three internal typedefs that all standard iterators need to have, and nothing else. And _Iterator_base (in all of its variants) and _Iterator_base_secure now should derive from _Iterator_base_universal to get these typedefs.
Now, when an iterator wants these typedefs, but not the data members of _Iterator_base and _Iterator_base_secure, it could derive from _Iterator_base_universal. And istreambuf_iterator and ostreambuf_iterator are now as small as possible, and keep identical representations or layout across HID/no-HID, SCL/no-SCL.
虽然对于全新的工E项目,推荐通过.net实现Q但是,只要你工作在Windowsq_上,必然会遇到和COM相关的技术和机制Q无论是大量的legacy的工E和代码Q还是作为OS重要功能以及nativelg的首选交互Ş式和接口暴露方式Q比如DirectX APIQ比如一些WMI的APIQ最有趣的是Q即使是.net的核心CLR本n也是一个COMlgQ可以通过Host相关接口让native应用来加载,以在当前q程中启动整个CLR的虚拟执行环境或者叫托管执行环境(managed executive environment)?/p>
把握COM有两点很关键Q?br>1QInterface-based designQ从设计和编码思\上就是要完全Z接口Q?br>2QVirtualTable-based binary compatibility, 实现上无ZU语a或者机Ӟ只要W合Z虚表的二q制兼容规范Q就都可以实施;
COM仅仅是个规范Q基于COM的具体技术非怹多,OLEQAutomationQStructural storageQActiveX...汗牛充栋Q还有COM+Q这个是提供企业U开发必备的一些基功能和设施,比如Q事务管理机Ӟ对象池,安全理Q消息队?..需要指出,目前即便?net Framework也没有实现COM+所提供q些机制Q只是简单的装了后者?/p>
COM技术中可能有一些比较困隄地方Q接口的一致性,对象的聚合和生命周期Q套_跨套间的接口讉KQ名字对象,{等Q这些ƈ不是COM规范Zؓ刉的困难Q而是Z设计和提供,可以跨进E和机器边界Q跨异构q_Q当然必dCCOM所规定的基服务Q,透明化具体对象类型及对象生命周期Q便于统一部v和版本管理的lg技术,所必须付出的代Pq个代h从开发h员角度看具体表现为,概念理解的困难以及具体二q制实现的困难;
不过从另一个角度看QCOM已经很容易了Q?br>a) COM规范已把要达致这些目标的pȝQ所必须提供的接口和Ҏ抽象了出来Q只不过Z表达q些抽象的概念而新造的术语名词有些陌生和突兀Q如果让遇到怼问题的每一个设计和开发h员都自己来做抽象Q未必会生成更好的方案;
b) Z帮助设计和开发h员,Z提供了很多的开发库Q以提高COM开发的正确性和效率Q最显著的就是MFC中关于COM/OLE的辅助类和函敎ͼ以及ZCOM而生的ATLQ从本质上看Q这些类库都是把COM规范中必d现的QWindowsq_本n没有提供Q具体设计和开发h员实际实施时会重复实现的Q同时又非常Ҏ出错的那部分功能Q集中到了这些类库里l一实现Q让具体设计和开发h员以代码重用的Ş式来实现COM规范Q?/p>
当然Z也意识到了COMq样的一些问题,特别是具体实现时设计和开发h员必要x几乎所有的二进制细节,于是.netp生了Q把q些规范的许多复杂性都装在了虚拟机里面,把这些目标功能(跨边界、透明性等{)通过一致而又qx的^台接口和自描q的meta dataQ以一U让设计和开发h员更易接受的风格开放了出来Q?/p>
COM的媄响是非常q大的,比如XPCOM QFirefox上的一U插件技术标准,是ҎCOM的思想和原则制定的Q许多评QFirefox的成功是因ؓ它插件是如此的成功,q也是COM本n所意料不到的A献之一?/p>
?net的^CQ即使是.net CLR/SSCLI的具体实C大量q用了COM的思想和机Ӟ可以?net是搭徏在COM二进制组件^C上的虚拟机托^台?/p>
最后,.net开始时的内部编hCOM 2.0
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*) 关于“名词太多”
q是要实现可以跨q程和机器边界,跨异构^収ͼ当然必须实现了COM所规定的基服务Q,透明化具体对象类型及对象生命周期Q便于统一部v和版本管理的lg技术,所必须付出的代仗?/p>
COM规范已把要达致这些目标的pȝQ所必须提供的接口和Ҏ抽象了出来Q只不过Z表达q些抽象的概念而新造的术语名词有些陌生和突兀Q如果让遇到怼问题的每一个设计和开发h员都自己来做抽象Q未必会生成更好的方案;
举个例子QapartmentQ套_是Z抽象传统OS中进E和U程的实现而新造的术语名词和概念;M抽象q样的一些概念,不新造术语,是非常困隄Q对?netQ后者用了CLR虚拟机来装了大多数的实现细节,q用让h更容易接受的风格来开放接口,可事实上仍然新造了一些名词和概念Q如cM范畴的AppDomainQ?/p>
*) 关于“ZATL的实现比较难?#8221;
ATL主要使用了template技术,COM接口指针Q用静态{换来模拟动态绑定,{等Q实际ƈ不是很复杂,只能c++实现机制的中{难度,主要涉及Modern C++ design一书中一些相兌计理늚q用。对比Boost中某些库的实玎ͼATL很h道了?/p>
*) 关于“qƈ不是COM本n复杂Q而是C++已经落后于时代了”
首先COM的规范的是复杂的,为啥Q第一点已l说了,是Z要抽象出跨边界和对象透明的组件技术;.net表象上看比较“单容?#8221;Q风gq设计和开发h员,实际上复杂事务和实现l节都被划分到CLR那个层面上去实现了;ȝ一下CLR的开源实现SSCLIQ你会发玎ͼ整个虚拟机^台的实现Q大量运用了COM的思想和机Ӟ是一个巨型系l^台的COM serverQ?/p>
其次QCOM规范本n是独立于实现语言的,只要构徏出的lgW合规范制定的二q制兼容Q系l就可以q作Q这和C++是否落后时代没有关系。如果开发h员认为,.net才够先进Q也完全可以?net中的托管语言Q如C#来实现COMlgQ?/p>
最后,每种语言都有光用的范_现在可以q么?#8220;如果有一个全新的目需求,要达致跨边界和对象透明lgQƈ且没有太q严苛的性能需求,那么.netq_及其上的托管语言来实玎ͼ比用C++及相兌助类库来以COMlg形式来实玎ͼ要更合适,也更快速便捷和节省预算?#8221;但是Q在q个判断上我们加了很多严格的U束Q一旦需求变_特别是项目的非功能性需求,要求高性能q算或者更畅的与legacy的nativepȝ怺Q那?#8220;使用native语言来实现性能关键以及legacy交互功能Q通过COM装Q再由COMInterop?net托管应用调用”可能是更现实的方案。C++是一门活的语aQ不断发展的语言Q即使在最新的托管时代里,C#成ؓ标准LQ但C++/CLI仍然是托语a里功能最完整的语a?/p>
许多优秀开源项目,比如BoostQ其中很多作者本w都是学者兼开发或者是带有研究性质的开发h员,在高校、非盈利l织或者商业企业的非直接盈利项目的资金支持下,在很进度压力和商业压力的情况下Q精雕细琢,多次q代后,构徏出的_֓代码。用q样的标准来要求所有的软g产品Q特别是商业产品Q当焉d数关p重大和长远的基核心部分外)的构建,是不U学的,也是不合的Q因为及时占领市场和_的盈利,以及获得用户的赞许才是商业Y件最重要的目标?/p>
回头来看金山目前开源的q些产品Q比如这里讨论的金山卫士Q其从推出就是免费的Q是Z市场上的先期推出的同cd兯Y件及时比拼占领些许相兛_Z额,其ƈ不是金山的基和核心品;从这些先天的条g看,q个产品的商业投入不会很大同时又有快速推出的要求Q能有目前这L产品质量Q是合理的,从企业角度和用户角度看也都是可以接受的?/p>
说到q里Q就感觉有必要涉及一?#8220;重构”Q这个现在大安很重视同时也l常谈及的话题。ؓ何大安很重视?而且常常谈及Q这其中当然有Y件构建本w的特点Q比如对需求理解的不断深入和调整、设计的不断改善和演q、代码风格的l一以及l节的完善等{;但是Q有个大家在潜意识里都感觉到Q^时却很少谈及的缘?-q度和成本,因ؓ有了q些压力Q品的W一版往往不是很完的Q然后如果还做后l版本的话,那么p引入重构Q因为有了这些压力,在经q多q之后,如果q个产品q存在的话,那么pq行大规模的重构。简单的_重构之所以重要,不仅仅是软g构徏本n特点所引发Q也是商业压力之下的构徏q程的有效应对之道?br>
In the fusion, or any other components or modules, how to retrieve the execution engine instance and how to generate such engine?
UtilExecutionEngine, implemented as COM object, support Queryinterface/AddRef/Release, and exposed via interface IExecutionEngine.
With SELF_NO_HOST defined,
BYTE g_ExecutionEngineInstance[sizeof(UtilExecutionEngine)];
g_ExecutionEngineInstance would be the singleton instance of current execution engine,
otherwise, without SELF_NO_HOST, the 'sscoree' dll would be loaded and try to get the exported function, which is named 'IEE' from such dll. Here, it is the well-known shim, in .net CLR, such module is named 'mscoree'. Further, if 'IEE' could not be found in such dll, system would try to locate another exported function, named 'LoadLibraryShim', and use such function to load the 'mscorwks' module, and try to locate the 'IEE' exportd functionin it.
It's very obvious that Rotor has implemented its own execution engine, but it also gives or make space for implementation of execution engine from 3rd party. Here, .net CLR is a good candidate definitely, Rotor might load the mscorwks.dll module for its usage.
PAL, PALAPI, for example, HeapAlloc, one famous WIN32 API, has been implemented as one PALAPI (defined in Heap.c), to make it possible that the CLI/Rotor be ported smoothly to other OS, such freebsd/mac os.
CRT routines are also reimplemented, such as memcpy, it has been implemented as GCSafeMemCpy
There're many macros in fuctions, such as SCAN_IGNORE_FAULT/STATIC_CONTRACT_NOTHROW/STATIC_CONTRACT_NOTRIGGER, they are for static analysis tool to scan, analyse and figour out the potential issues in code.
From view point of the execution model by CLI, the act of compiling (including JIT) high-level type descriptions would be separated from the act of turning these type descriptions into processor-specific code and memory structures.
And such executino model, in other word, the well-known 'managed execution', would defer the loading, verification and compilation of components until runtime really needs; At the same time, the type-loading is the key trigger that causes CLI's tool chain to be engaged at runtime. Deferred compilation(lead to JIT)/linking/loading would get better portability to different target platform and be ready for version change; The whole deferred process would driven by well-defined metadata and policy, and it would be very robust for building a virtual execution environment;
At the top of such CLI tool chain, fusion is reponsible for not only finding and binding related assemblies, which are via assembly reference defined in assembly, fusion also takes another important role, loader, and its part of functionality is implemented in PEAssembly, ClassLoader classes. For example, ClassLoader::LoadTypeHandleForTypeKey.
For types in virtual execution environment of CLI, rotor defines four kinds of elements for internal conducting,
ELEMENT_TYPE_CLASS for ordinary classes and generic instantiations(including value types);
ELEMENT_TYPE_ARRAY AND ELEMENT_TYPE_SZARRAY for array types
ELEMENT_TYPE_PRT and ELEMENT_TYPE_BYREF for pointer types
ELEMENT_TYPE_FNPTR for function pointer types
every type would be assigned unique ulong-typed token, and such token would be used to look up in m_TypeDefToMethodTableMap (Linear mapping from TypeDef token to MethodTable *)which is maintained by current module; If there it is, the pointer to method table of such type would be retrieved, or it would look up in the loader module, where the method table should exist in while it's JIT loaded, not launched from NGEN image;
And all the unresolved typed would be maintained in a hash table, PendingTypeLoadTable; Types and only those types that are needed, such as dependencies, including parent types, are loaded in runtime, such type is fully loaded and ready for further execution, and other unresolved types would be kept in the previous hash table.
2) 再从大多数应用中常见的类l承体系上看Q?br>除了整个l承体系所l一开攑և来的接口集(也就是由虚函数所l成Q,在承体pȝ每个层面另外会有大量的其他辅助成员函敎ͼ其数量通常比虚函数多的多)Q这些成员函数完全没必要设计成虚函数Q?/p>
3) 从其他语a看,
即较新的虚拟机语言C#(Java是较老的虚拟a),反而定义了比C++更ؓ严格更ؓ昑ּ的成员方法实现或覆盖或重载或新徏的规则;q是非常重要的对C++以及Java设计思想的反思?/p>
4) 从语a的适用场合看,
我们现在的讨论,l大多数情况下带有一个非帔R要的默认前提Q那是在用h模式下使用C++Q如果放宽这个约束,在内核模式下使用C++Q那情况又完全不同了?br>引用下面q个文档的观点,http://www.microsoft.com/china/whdc/driver/kernel/KMcode.mspx
首先Q用h下非常廉h几乎不用考虑的资源,在内怸是非常昂늚Q比如内核堆栈一般就3个pageQ?/p>
在内怸能分?paging)时必M证将被执行的所有代码和数据必须有效的驻留在物理内存中,如果q时需要多ȝ几张虚表以及虚表指针那还是显得非常昂늚Q同时编译器函数Q模板等生成代码的方式,让开发h员很隄定要执行一个函数所需要的所有代码的所在位|,因此也无法直接控制用于安|这些代码的节(个h认ؓ可能通过progma segment/datasegment/codesegment对于代码和数据进行集中控ӞQ因此在需要这些代码时Q可能已l被page out了;
所有涉及类层次l构Q模板,异常{等q样的一些语al构在内核态中都可能是不安全的Q最好是把类的用限定ؓPODc,回到我们的主题虚函数Q也是说内核态下c设计中没有虚函数?/p>