注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

HongMain 的博客

关注编程技术: Linux, Windows, C/C++

 
 
 

日志

 
 
 
 

资源释放以及派生类支持特殊操作的问题的解决方案  

2011-08-08 22:49:42|  分类: 编程语言(主要是 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
问题描述:
曾经做过一个项目,是一个类似Google Picasa 的产品,主要功能是利用非常成熟的PDF 处理技术,管理用户系统里的文档。具体点是:扫描、监听用户的整个文件系统,列出所有用户关注的文件,文件类型有PDF、Doc、图片、多媒体、txt、网页等等,对于不同的文件类型,有部分操作是相同的,如画thumbnail 显示在列表里、取path等;也有不同的操作,如:PDF 可以添加水印、加密、合并、打印等,Doc、txt、图片等文件类型可以转换成PDF 等。
解决方案:
以下是这个项目里几个主要的类,由于是封闭式的开发,凭印象整理的,也没有太多测试,但思路是清晰的,写在这里,留作备份,遇到类似问题可以参考。
//------------------------------------------
// XFile.h
#ifndef __XFILE_H__
#define __XFILE_H__

class XOperator;

// 所有文件类型的基类
class XFile
{
public:
    XFile(const char* path);
    virtual ~XFile();    // 一定要虚析构
    virtual const char* Path();
    // 其他成员函数(所有文件类型所共有的操作)
    // ......

    // 文件操作函数入口,具体操作由XOperator 的派生类来完成。
    virtual bool Operate(XOperator&) = 0;

protected:
    char* mPath;
};

// PDF 文件
// 相关操作有加水印,数字签名等
class PDFFile : public XFile
{
public:
    PDFFile(const char*);
    virtual bool Operate(XOperator&);
};

// word 文件
// 相关操作有转换成PDF 等
class DocFile : public XFile
{
public:
    DocFile(const char*);
    virtual bool Operate(XOperator&);
};

// 多媒体文件
// 相关操作有播放等
class MediaFile : public XFile
{
public:
    MediaFile(const char*);
    virtual bool Operate(XOperator&);
};

#endif //__XFILE_H__

//---------------------------------------
// XFile.cpp
#include <assert.h>
#include <string.h>
#include "XFile.h"
#include "XOperator.h"

XFile::XFile(const char* path)
{
    assert(path);
    if (path)
    {
        mPath = new char[strlen(path) + 1];
        strcpy(mPath, path);
    }
}

XFile::~XFile()
{
    delete[] mPath;
}

const char* XFile::Path()
{
    return mPath;
}

// PDFFile
PDFFile::PDFFile(const char* path)
    : XFile(path)
{
}

bool PDFFile::Operate(XOperator& op)
{
    op.Operate(*this);
}

// DocFile
DocFile::DocFile(const char* path)
    : XFile(path)
{
}

bool DocFile::Operate(XOperator& op)
{
    op.Operate(*this);
}

// MediaFile
MediaFile::MediaFile(const char* path)
    : XFile(path)
{
}

bool MediaFile::Operate(XOperator& op)
{
    op.Operate(*this);
}

//-------------------------------------------
// XOperator.h
#ifndef __XOPERATOR_H__
#define __XOPERATOR_H__

#include "XFile.h"

// 所有操作的基类
class XOperator
{
public:
    virtual ~XOperator() = 0;
    // 具体操作的执行函数
    virtual bool Operate(PDFFile& file);
    virtual bool Operate(DocFile& file);
    virtual bool Operate(MediaFile& file);
};

// 打开文件的操作,这个操作支持所有的文件类
class OpOpen : public XOperator
{
public:
    virtual bool Operate(PDFFile& file);
    virtual bool Operate(DocFile& file);
    virtual bool Operate(MediaFile& file);
};

// 对于多媒体文件特有的操作:播放多媒体文件
class OpPlay : public XOperator
{
public:
    virtual bool Operate(MediaFile& file);
};

// 将文件转换成PDF
class OpConvert : public XOperator
{
public:
    virtual bool Operate(DocFile& file);
};

#endif

//-------------------------------------
// XOperator.cpp
#include <iostream>
#include "XOperator.h"

// XOperator
// 需要添加这个定义,否则link 时会出错
XOperator::~XOperator()
{
}
// 所有操作的默认实现是提示这个操作不支持指定的文件类型
bool XOperator::Operate(PDFFile& file)
{
    std::cerr << "This operate does not support PDF files.\n";
    return false;
}
bool XOperator::Operate(DocFile& file)
{
    std::cerr << "This operate does not support Doc files.\n";
    return false;
}

bool XOperator::Operate(MediaFile& file)
{
    std::cerr << "This operate does not support Media files.\n";
    return false;
}

// OpOpen
// 打开文件的操作,这个操作支持所有的文件类
bool OpOpen::Operate(PDFFile& file)
{
    std::cout << "Open PDF file: " << file.Path() << std::endl;
    return true;
}
bool OpOpen::Operate(DocFile& file)
{
    std::cout << "Open Doc file: " << file.Path() << std::endl;
    return true;
}
bool OpOpen::Operate(MediaFile& file)
{
    std::cout << "Open Media file: " << file.Path() << std::endl;
    return true;
}
                           
// OpPlay
// 对于多媒体文件特有的操作:播放多媒体文件
bool OpPlay::Operate(MediaFile& file)
{
    std::cout << "Play Media file: " << file.Path() << std::endl;
}

// OpConvert
// 将文件转换成PDF
bool OpConvert::Operate(DocFile& file)
{
    std::cout << "Convert Doc file: " << file.Path() << std::endl;
}

//-------------------------------------
// FileFactory.h

#ifndef __FILE_FACTORY_H__
#define __FILE_FACTORY_H__

class XFile;

class FileFactory
{
public:
    // 根据path 创建对应的文件对象
    // 这里只是简单的判断扩展名
    static XFile* CreateFile(const char* path);
};
   
#endif

//----------------------------------------
// FileFactory.cpp

#include "FileFactory.h"
#include "XFile.h"
#include <string.h>

// 这个实现只是为了演示
XFile* FileFactory::CreateFile(const char* path)
{
    int len = strlen(path);
    if (len < 4)
    {
        return NULL;
    }

    if (0 == strncasecmp(path + (len-4), ".pdf", 4))
    {
        return new PDFFile(path);
    }

    if (0 == strncasecmp(path + (len-4), ".doc", 4))
    {
        return new DocFile(path);
    }

    if (0 == strncasecmp(path + (len-4), ".mov", 4))
    {
        return new MediaFile(path);
    }

    return NULL;
}

//-----------------------------------------
// HFile.h
#ifndef __HFILE_H__
#define __HFILE_H__

#include "XFile.h"

// 引用计数类
class UseCount
{
public:
    UseCount();
    UseCount(const UseCount&);
    ~UseCount();
    int only();
    int reattach(const UseCount&);
    int makeonly();
   
private:
    UseCount& operator=(const UseCount&);
    int* p;
};

// Handle 类,根据引用计数自动释放
class HFile
{
public:
    // Handle(); 如果需要建立HFile 的数组,需要这个,为了简单,暂不支持
    HFile(const char* filepath);
    HFile(const HFile& h);
    HFile& operator=(const HFile&);
    ~HFile();

    // XFile 的接口
    const char* Path();
    bool Operate(XOperator&);
   
private:
    UseCount uCount;
    XFile* mFile;
   
};

#endif

//---------------------------------------
// HFile.cpp
#include "HFile.h"
#include "FileFactory.h"

// UseCount
UseCount::UseCount()
  : p(new int(1))
{
}
UseCount::UseCount(const UseCount& u)
  : p(u.p)
{
    ++*p;
}
UseCount::~UseCount()
{
    if (--*p == 0)
        delete p;
}
int UseCount::only()
{
    return *p == 1;
}

int UseCount::reattach(const UseCount& u)
{
    ++*u.p;
    if (--p == 0) {
        delete p;
        p = u.p;
        return true;
    }
    p = u.p;
    return false;
}

int UseCount::makeonly()
{
    if (*p == 1)
        return false;
    --*p;
    p = new int(1);
    return true;
}

// HFile
HFile::HFile(const char* path)
    : mFile(FileFactory::CreateFile(path))
{
}

HFile::HFile(const HFile& h)
    : uCount(h.uCount)
    , mFile(h.mFile)
{
}

HFile& HFile::operator=(const HFile& h)
{
    if (uCount.reattach(h.uCount))
        delete mFile;
    mFile = h.mFile;
    return *this;
}

HFile::~HFile()
{
    if (uCount.only()) {
        delete mFile;
    }
}

// XFile 的接口
const char* HFile::Path()
{
    if (mFile)
    {
        mFile->Path();
    }
}

bool HFile::Operate(XOperator& op)
{
    if (mFile)
    {
        mFile->Operate(op);
    }
}

//--------------------------------------------
// main.cpp
#include <iostream>
#include "HFile.h"
#include "XOperator.h"

// 参数传递也没问题
bool Convert2PDF(HFile file)
{
    OpConvert op;
    return file.Operate(op);
}

int main(int argc, char** argv)
{
    // 创建文件就很简单了,也不需要担心释放的问题
    HFile pdf("PdfFilePath.pdf");
    HFile doc("DocFilePath.doc");
    HFile media("MediaFilePath.mov");

    OpOpen op;
    pdf.Operate(op);

    Convert2PDF(doc);
   
    return 0;
}

最后就是Makefile
XFile: main.o XFile.o XOperator.o FileFactory.o HFile.o
    g++ $(CFLAGS) -o XFile main.o XFile.o XOperator.o FileFactory.o HFile.o

main.o: main.cpp HFile.h XOperator.h
    g++ $(CFLAGS) -c main.cpp

XFile.o: XFile.h XFile.cpp
    g++ $(CFLAGS) -c XFile.cpp

XOperator.o: XOperator.h XOperator.cpp
    g++ $(CFLAGS) -c XOperator.cpp

FileFactory.o: FileFactory.cpp FileFactory.h XFile.h
    g++ $(CFLAGS) -c FileFactory.cpp

HFile.o: HFile.cpp HFile.h FileFactory.h
    g++ $(CFLAGS) -c HFile.cpp

clean:
    rm -f *.o XFile
  评论这张
 
阅读(14)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017