哈哈,從M$ Visual C++ Team的
Andy Rich那里又偷學(xué)到一招:VC8的隱含編譯項(xiàng)
/d1reportSingleClassLayout和
/d1reportAllClassLayout 。看個(gè)復(fù)雜的例子吧(如下),現(xiàn)在假設(shè)我們想知道Derived類的對(duì)象布局,怎么辦? 在Project Properties->C++->Command Line->Additional Options里面加上
/d1reportSingleClassLayoutDerived吧!
class CommonBase
{
int co;
};
class Base1: virtual public CommonBase
{
public:
virtual void print1() {}
virtual void print2() {}
private:
int b1;
};
class Base2: virtual public CommonBase
{
public:
virtual void dump1() {}
virtual void dump2() {}
private:
int b2;
};
class Derived: public Base1, public Base2
{
public:
void print2() {}
void dump2() {}
private:
int d;
};
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
F5編譯之,你會(huì)驚奇地發(fā)現(xiàn),Output里面有如下字樣:
1 class Derived size(32):
2 +---
3 | +--- (base class Base1)
4 0 | | {vfptr}
5 4 | | {vbptr}
6 8 | | b1
7 | +---
8 | +--- (base class Base2)
9 12 | | {vfptr}
10 16 | | {vbptr}
11 20 | | b2
12 | +---
13 24 | d
14 +---
15 +--- (virtual base CommonBase)
16 28 | co
17 +---
18
19 Derived::$vftable@Base1@:
20 0 | &Base1::print1
21 1 | &Derived::print2
22
23 Derived::$vftable@Base2@:
24 0 | &Base2::dump1
25 1 | &Derived::dump2
26
27 Derived::$vbtable@Base1@:
28 0 | -4
29 1 | 24 (Derivedd(Base1+4)CommonBase)
30
31 Derived::$vbtable@Base2@:
32 0 | -4
33 1 | 12 (Derivedd(Base2+4)CommonBase)
34
35 Derived::print2 this adjustor: 0
36 Derived::dump2 this adjustor: 12
看到了嗎? VC8居然輸出了Derived對(duì)象的完整布局! 我們終于可以不必兩眼一抹黑般的去peek/poke了....第1行表明,Derived對(duì)象總占用了32字節(jié);其由三部分組成,分別是行3-行7、行 8-行12、行13、行28;其中前二者分別是基類Base1、Base2的布局,最后的行28為虛擬基類Common的布局。
以基類 Base1部分為例,可發(fā)現(xiàn)其由一個(gè)虛函數(shù)表指針vftable和虛基表指針vbtable構(gòu)成,先看Base1部分的vftable所指向的虛表$ vftable@Base1(行19),不難發(fā)現(xiàn),其中的表項(xiàng)2已經(jīng)被Derived::print2給override了;再來(lái)看Base2部分的 vftable所指向的虛表$vftable@Base2(行23),可發(fā)現(xiàn),同樣的,Base2::dump2被Derived::dump2給 override了。這不明擺著就是虛函數(shù)機(jī)制嘛,heh~
值得注意的是,這個(gè)例子同時(shí)說(shuō)明,多繼承場(chǎng)合下,其實(shí)在單一對(duì)象中是存在多個(gè) this指針的....行35-36給出了如何將Derived的this指針校正為其基類子對(duì)象this指針的偏移量,也就是說(shuō),根據(jù)行36,假設(shè)有個(gè) Derived d,那么d.dump1()實(shí)際上應(yīng)該理解成通過(guò)虛表$vftable@Base2對(duì)((Base2*)(((char*)&d)+12))- >dump1()的調(diào)用....即傳遞給所有Base2成員函數(shù)的this指針應(yīng)該是(Base2*)((char*)(&d)+12),這里可能我寫(xiě)得恐怖了點(diǎn),意思到了就成....這不,普通繼承、多繼承、對(duì)象Slicing的語(yǔ)義都在這個(gè)布局里面了,看仔細(xì)了哈~
OK,多繼承看完了,繼續(xù)看虛擬基類是如何布局的。虛基Common在Derived的布局中,位于Derived本身數(shù)據(jù)成員之后的位置。Base1、 Base2中均保存了一個(gè)vbtable指針,其分別指向各自所使用的虛基表$vbtable@Base1和$vbtable@Base2,為什么要指向一個(gè)虛基表? 很簡(jiǎn)單,因?yàn)锽ase1、Base2有可能會(huì)同時(shí)繼承多個(gè)不同的虛擬基類.....這充分體現(xiàn)了C++對(duì)象布局的復(fù)雜性....在每個(gè)虛基表中,保存了所繼承的虛擬基類部分相對(duì)于子類部分vbtable指針的偏移值,以Base2為例,我們知道Base2的vbtable在Derived中的偏移值為16 (行10),則根據(jù)$vbtable@Base2,虛基Common部分距離Base2 vbtable指針的偏移值為12,則有虛基Common在Derived中的總偏移值為16+12。與普通多繼承同理,我們?cè)谡{(diào)用非虛擬的虛基成員函數(shù)時(shí),必須將Derived的this指針調(diào)整為指向虛基部分的this指針,只有這樣才能成功地訪問(wèn)虛基自身的數(shù)據(jù)成員和虛基的虛擬函數(shù)(通過(guò)虛基自己的 vftable,為簡(jiǎn)單起見(jiàn),上例中我就沒(méi)弄那么復(fù)雜了,大家可以自己玩玩,明白如何舉一反三即可)
Transferring the Password
There are various ways to get the passwords stored in KeePass into other windows. The first, and most simple method is copying them to the clipboard. For this, just double-click onto the specific field in the main password list. Example: if you want to copy the password of entry X, point onto the password field of the entry in the main view and double-click. The password is copied to the clipboard. If you enable the auto-clearing option, KeePass will clear the clipboard automatically after some seconds. This prevents you from forgetting to clear the clipboard yourself, leaving sensitive data in the clipboard.
The second method is drag-n-drop. As in method 1, point onto the field you want to use, click the left mouse button and hold it. Drag the data into other windows.
The third, and the most powerful method is auto-type. KeePass features a very mighty auto-type feature, which types user names, passwords, etc. into other windows for you. The default auto-typing sequence is: {USERNAME}{TAB}{PASSWORD}{TAB}{ENTER}. But this sequence is customizable, per entry (read the CHM documentation file that comes with KeePass for more about this). This makes the auto-type feature applicable to all windows and webforms you'll ever see. There are two submethods to perform an auto-type:
- Selecting an entry: Just select the entry that you want to get auto-typed, right-click onto it and click "Perform Auto-Type". KeePass will minimize itself, the window that had the focus before will come to the front. KeePass starts typing the data into this window.
- Global hot key: This is the most powerful of all methods. You leave KeePass running in the background. As soon as you're on a site that requires a login (the password of which you stored in KeePass before), just press a hot key (by default, Ctrl-Alt-A). KeePass immediately auto-types the data into the target window.
#include <boost/config.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
template<class T>
inline T & ToRef( T *pT)
{
return *pT;
}
#define TODEF(x) bind( ToRef<x>, _1)
template<class T>
inline void DeletePointer( T *pT)
{
delete pT;
}
#define ALL(v) (v).begin(), (v).end()
struct X
{
public:
int m_t;
X():m_t(11)
{
}
bool f(int a)
{
std::cout << m_t << std::endl;
return true;
}
};
int main()
{
using namespace boost;
using namespace std;
vector<X *> v;
for( int i=0; i<10; ++i)
v.push_back( new X);
for_each( ALL(v), bind(&X::f, TODEF(X), 4 ) );
for_each( ALL(v), bind( DeletePointer<X>, _1) );
return 0;
}
一天,一只兔子在山洞前寫(xiě)論文。
一只狼過(guò)來(lái),問(wèn)兔子:‘你在寫(xiě)什么?”
答:“論文”
狼問(wèn):“你的論文的主題是什么?”
答:“《論兔子如何吃掉狼》”。
狼聽(tīng)了哈哈大笑。
兔子說(shuō),我寫(xiě)的論文大部分稿子在洞里,我把道理寫(xiě)的很清楚。
狼想看看兔子的論文是怎么寫(xiě)的。于是兔子把狼領(lǐng)進(jìn)山洞。
過(guò)了一會(huì),兔子獨(dú)自走出山洞。
兔子繼續(xù)在山洞前寫(xiě)它的論文。
一只狐貍過(guò)來(lái),問(wèn):“你在寫(xiě)什么?”
答:“我在寫(xiě)論文”。
“論文的主題是什么?”
答:“論兔子如何吃掉狐貍”。
向來(lái)狡猾的狐貍也笑了。說(shuō):“這怎么可能呢”
兔子說(shuō):“我寫(xiě)的大部分稿子還在洞里,我把道理寫(xiě)的很清楚。”
狐貍想去看看兔子的論文是怎么寫(xiě)的,于是兔子把狐貍領(lǐng)進(jìn)山洞。
過(guò)了一會(huì)兒,兔子獨(dú)自一個(gè)走出山洞。
最后,在山洞里一只獅子在幾堆白骨之間,滿意地一邊剔著牙,一邊閱讀兔子交給它的論文的提要:“一個(gè)動(dòng)物,能力大小并不重要,關(guān)鍵看你的導(dǎo)師是誰(shuí)。
據(jù)說(shuō)這是道中國(guó)人老是選錯(cuò)的題,當(dāng)然這樣說(shuō)是有所隱喻的,不過(guò)我們大可以跳出政治的范疇,實(shí)際點(diǎn)說(shuō),對(duì)于政治,我們大多數(shù)人是心有余而力不足的,于是會(huì)有各種表現(xiàn),焦慮的就成了憤青一族,忍受的就成了洗腦一族,總之都沒(méi)什么好詞兒,還沒(méi)怎么呢就先自己掐起來(lái)了......
上帝把兩群羊放在草原上,一群在南,一群在北。
上帝還給羊群找了兩種天敵,一種是獅子,一種是狼。
上帝對(duì)羊群說(shuō):“如果你們要狼,就給一只,任它隨意咬你們。
如果你們要獅子,就給兩頭,你們可以在兩頭獅子中任選一頭,還可以隨時(shí)更換。”
這道題的問(wèn)題就是:如果你也在羊群中,你是選狼還是選獅子?
很容易做出選擇吧?
好吧,記住你的選擇,接著往下看。
南邊那群羊想,獅子比狼兇猛得多,還是要狼吧。于是,它們就要了一只狼。
北邊那群羊想,獅子雖然比狼兇猛得多,但我們有選擇權(quán),還是要獅子吧。于是,它們就要了兩頭獅子。
那只狼進(jìn)了南邊的羊群后,就開(kāi)始吃羊。
狼身體小,食量也小,一只羊夠它吃幾天了。
這樣羊群幾天才被追殺一次。
北邊那群羊挑選了一頭獅子,另一頭則留在上帝那里。
這頭獅子進(jìn)入羊群后,也開(kāi)始吃羊。獅子不但比狼兇猛,而且食量驚人,每天都要吃一只羊。
這樣羊群就天天都要被追殺,驚恐萬(wàn)狀。
羊群趕緊請(qǐng)上帝換一頭獅子。不料,上帝保管的那頭獅子一直沒(méi)有吃東西,正饑餓難耐,它撲進(jìn)羊群,比前面那頭獅子咬得更瘋狂。
羊群一天到晚只是逃命,連草都快吃不成了。
南邊的羊群慶幸自己選對(duì)了天敵,又嘲笑北邊的羊群沒(méi)有眼光。
北邊的羊群非常后悔,向上帝大倒苦水,要求更換天敵,改要一只狼。
上帝說(shuō):“天敵一旦確定,就不能更改,必須世代相隨,你們唯一的權(quán)利是在兩頭獅子中選擇。”
北邊的羊群只好把兩頭獅子不斷更換。
可兩頭獅子同樣兇殘,換哪一頭都比南邊的羊群悲慘得多,它們索性不換了,讓一頭獅子吃得膘肥體壯,另一頭獅子則餓得精瘦。
眼看那頭瘦獅子快要餓死了,羊群才請(qǐng)上帝換一頭。
這頭瘦獅子經(jīng)過(guò)長(zhǎng)時(shí)間的饑餓后,慢慢悟出了一個(gè)道理:
自己雖然兇猛異常,一百只羊都不是對(duì)手,可是自己的命運(yùn)是操縱在羊群手里的。
羊群隨時(shí)可以把自己送回上帝那里,讓自己飽受饑餓的煎熬,甚至有可能餓死。
想通這個(gè)道理后,瘦獅子就對(duì)羊群特別客氣,只吃死羊和病羊,凡是健康的羊它都不吃了。
羊群喜出望外,有幾只小羊提議干脆固定要瘦獅子,不要那頭肥獅子了。
一只老公羊提醒說(shuō):“瘦獅子是怕我們送它回上帝那里挨餓,才對(duì)我們這么好。
萬(wàn)一肥獅子餓死了,我們沒(méi)有了選擇的余地,瘦獅子很快就會(huì)恢復(fù)兇殘的本性。”
羊群覺(jué)得老羊說(shuō)得有理,為了不讓另一頭獅子餓死,它們趕緊把它換回來(lái)。
原先膘肥體壯的那頭獅子,已經(jīng)餓得只剩下皮包骨頭了,并且也懂得了自己的命運(yùn)是操縱在羊群手里的道理。
為了能在草原上待久一點(diǎn),它竟百般討好起羊群來(lái)。而那頭被送交給上帝的獅子,則難過(guò)得流下了眼淚。
北邊的羊群在經(jīng)歷了重重磨難后,終于過(guò)上了自由自在的生活。
南邊的那群羊的處境卻越來(lái)越悲慘了,那只狼因?yàn)闆](méi)有競(jìng)爭(zhēng)對(duì)手,羊群又無(wú)法更換它,
它就胡作非為,每天都要咬死幾十只羊,這只狼早已不吃羊肉了,它只喝羊心里的血。
它還不準(zhǔn)羊叫,哪只叫就立刻咬死哪只。
南邊的羊群只能在心中哀嘆:“早知道這樣,還不如要兩頭獅子。”