posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

     摘要: 介绍LuaPlus: 好用的Lua For C++扩展(修订)LuaPlus是Lua的C++增强,也就是说,LuaPlus本身就是在Lua的源码上进行增强得来的。用它与C++进行合作,是比较好的一个选择。LuaPlus目前版本为:LuaPlus for Lua 5.01 Distribution Build 1080 (February 28, 2004)。大家可以到http://luaplus....  阅读全文

posted @ 2011-08-03 07:42 RTY 阅读(432) | 评论 (0)编辑 收藏

Stable release

The latest stable release of PyInstaller is 1.5.1 (Change Log). See below for download links.

Features

  • Packaging of Python programs into standard executables, that work on computers without Python installed.
  • Multiplatform: works under Windows (32-bit and 64-bit), Linux (32-bit and 64-bit) and Mac OS X (32-bit only, 64-bit in svn, see MacOsCompatibility).
  • Multiversion: works under any version of Python from 2.2 up to 2.7.
  • Flexible packaging mode:
    • Single directory: build a directory containing an executable plus all the external binary modules (.dll, .pyd, .so) used by the program.
    • Single file: build a single executable file, totally self-contained, which runs without any external dependency.
    • Custom: you can automate PyInstaller to do whatever packaging mode you want through a simple script file in Python.
  • Explicit intelligent support for many 3rd-packages (for hidden imports, external data files, etc.), to make them work with PyInstaller out-of-the-box (see SupportedPackages).
  • Full single-file EGG support: required .egg files are automatically inspected for dependencies and bundled, and all the egg-specific features are supported at runtime as well (entry points, etc.).
  • Partial directory EGG support: required .egg directories are automatically inspected for dependencies and bundled, but egg-specific features will not work at runtime.
  • Automatic support for binary libraries used through ctypes (see CtypesDependencySupport for details).
  • Support for automatic binary packing through the well-known  UPX compressor.
  • Optional console mode (see standard output and standard error at runtime).
  • Windows-specific features:
    • Support for code-signing executables.
    • Full automatic support for CRTs: no need to manually distribute MSVCR*.DLL, redist installers, manifests, or anything else; true one-file applications that work everywhere! (seePython26Win)
    • Selectable executable icon.
    • Fully configurable version resource section and manifests in executable.
    • Support for building COM servers.
  • Mac-specific features:

License

PyInstaller is distributed under the GPL license (see the file doc/LICENSE.GPL in the source code), with a special exception which allows to use PyInstaller to build and distribute non-free programs (including commercial ones). In other words, you have no restrictions in using PyInstaller as-is, but any kind of modifications to it will have to comply with the GPL license. See also our FAQ.

posted @ 2011-08-02 07:28 RTY 阅读(503) | 评论 (0)编辑 收藏

在 C++ 中使用 Python script

想要在c++ 中嵌入script 代码, 除了自己写脚本引擎外, lua, python 都可以在c++ 中使用, 另外MonoBind, AngelScript library 都是一些c++ script library, 可以嵌入到c++ 中使用 . 
今天在c++ 中试着嵌入 python 代码 (示例代码在 Python-2.5.2\Demo\embed\ 下)

#include <Python.h>
int main(int argc, char *argv[])
{
  
// Py_NoSiteFlag = 1;
  
// Py_SetPythonHome("D:\\usr\\Python"); // PYTHONHOME

  Py_Initialize();
  PyRun_SimpleString(
"from time import time,ctime\n"
                     
"print 'Today is',ctime(time())\n");
  Py_Finalize();
  
return 0;
}

在运行时可能会产生类似 'import site' failed; use -v for traceback 的错误, 原因是python 在import module 的时候的路径问题. 有3种方法可以解决(以前通过设置环境变量 PYTHONPATH 好像在2.5 已经无效了). 
0. 取消注释 Py_NoSiteFlag = 1; 
这个只是取消import site , 当然如果在代码中要import 啥的话, 还是会出现错误的. 
a. 设置环境变量 PYTHONHOME = D:\usr\Python  
b. 在调用 Py_Initialize 之前调用函数 
Py_SetPythonHome("D:\\usr\\Python");  // 参数是python 的安装目录 

2. 其他一些有用的资源 
Python/C API Reference Manual (API 参考) ,  Extending and Embedding the Python Interpreter (扩展及嵌入Python解释器, 主要说明了如何扩展Python, 给Python 写扩展, 其中 5. Embedding Python in Another Application  一章讲述了在C++中嵌入/调用Python 代码 ) 

使用C/C++扩展Python  对文 Extending and Embedding the Python Interpreter 作了精简, 很不错的一篇文章, 但是跳过了一些基础 . 

Building Hybrid Systems with Boost.Python 介绍了使用boost.python 方便python 插件开发,python绑定c++程序 是其中文版本. 

Embedding Python in Multi-Threaded C/C++ Applications 讲了c++在多线程环境如何使用Python , 文 C++多线程中调用python api函数 提供了一个多线程的封装. 

SCXX - A Simple Python/C++ API
http://davidf.sjsoft.com/mirrors/mcmillan-inc/scxx.html

C++扩展和嵌入Python应用 (介绍了一些Python/C API 函数, 以及ext 例子, 一般般) 
http://hi.baidu.com/yunsweet/blog/item/20b08aeebaa2b1282cf534c7.html


3. Python 多线程的使用 

zz http://blog.csdn.net/liguangyi/archive/2007/06/20/1659697.aspx 
今天看了近一天关于多线程的应用中,如何安全调用python方面的资料,开始的时候看的简直头大如斗,被python语言的全局锁(Global Interpreter Lock)、线程状态(Thread State )等都有点绕晕了,后来经过各方面文章和帮助文档的相互参考,发现对于2.4/2.5版本,提供了PyGILState_Ensure, PyGILState_Release,哎,这下可方便大发了。

一、首先定义一个封装类,主要是保证PyGILState_Ensure, PyGILState_Release配对使用,而且这个类是可以嵌套使用的。

#include <python.h>

class PyThreadStateLock
{
public:
    PyThreadStateLock(void)
    {
        state = PyGILState_Ensure( );
    }

    ~PyThreadStateLock(void)
    {
         PyGILState_Release( state );
    }
private:
    PyGILState_STATE state;
};


二、在主线程中,这样处理

    // 初始化
    Py_Initialize();
    // 初始化线程支持
    PyEval_InitThreads();
    // 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。
    PyEval_ReleaseThread(PyThreadState_Get());
   
    // 其他的处理,如启动子线程等
    ......
       
    // 保证子线程调用都结束后
    PyGILState_Ensure();
    Py_Finalize();
    // 之后不能再调用任何python的API

三、在主线程,或者子线程中,调用python本身函数的都采用如下处理

    {
        class PyThreadStateLock PyThreadLock;
        // 调用python的API函数处理
        ......
    }

呵呵,看这样是否非常简单了。


另外还有两个和全局锁有关的宏,Py_BEGIN_ALLOW_THREADS 和 Py_END_ALLOW_THREADS。这两个宏是为了在较长时间的C函数调用前,临时释放全局锁,完成后重新获取全局锁,以避免阻塞其他python的线程继续运行。这两个宏可以这样调用

    {
        class PyThreadStateLock PyThreadLock;
        // 调用python的API函数处理
        ......

        Py_BEGIN_ALLOW_THREADS
        // 调用需要长时间的C函数
        ......
        Py_END_ALLOW_THREADS

        // 调用python的API函数处理
        ......
    }

4. 可能的错误及解决 
a. 在vs 200x 下 debug 模式出现链接问题 
extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_Dealloc referenced in function _PySwigObject_format
extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_NegativeRefcount referenced in function _PySwigObject_format
extmodule.obj : error LNK2001: unresolved external symbol __imp___Py_RefTotal
extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugFree referenced in function _PySwigObject_dealloc
extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugMalloc referenced in function _PySwigObject_New
extmodule.obj : error LNK2019: unresolved external symbol __imp__Py_InitModule4TraceRefs referenced in function _init_extmodule

主要是因为 Py_DEBUG/Py_TRACE_REFS 引起, 修改 Python\include 下的 pyconfig.h, object.h 两个文件就行了 ... 详见 http://www.nabble.com/link-error-in-debug-mode-td3126668.html 

posted on 2008-08-14 17:55 泡泡牛 阅读(4472) 评论(3)  编辑 收藏 引用 所属分类: Python

评论

# re: 在 C++ 中使用 Python script  2008-08-15 20:34 泡泡牛 

谁知道有什么其他的可以在c++ 里面调用的script 引擎吗?
  回复  更多评论    

# re: 在 C++ 中使用 Python script  2008-09-24 20:10 sheena 

主要是因为 Py_DEBUG/Py_TRACE_REFS 引起, 修改 Python\include 下的 pyconfig.h, object.h 两个文件就行了 ... 详见 http://www.nabble.com/link-error-in-debug-mode-td3126668.html 
这个解释我还是没有看明白,?您能再解释下吗
  回复  更多评论    

# re: 在 C++ 中使用 Python script  2008-09-24 22:17 泡泡牛 

1. 修改 pyconfig.h 

修改 

#ifdef _DEBUG 
# define Py_DEBUG 
#endif 

为 

#ifdef _DEBUG 
//# define Py_DEBUG 
#endif 

修改 

# ifdef _DEBUG 
# pragma comment(lib,"python24_d.lib") 
# else 
# pragma comment(lib,"python24.lib") 
# endif /* _DEBUG */ 

为 

# ifdef _DEBUG 
# pragma comment(lib,"python24.lib") 
# else 
# pragma comment(lib,"python24.lib") 
# endif /* _DEBUG */ 


2. object.h 
修改 
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS) 
#define Py_TRACE_REFS 
#endif 

为 

#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS) 
// #define Py_TRACE_REFS 
#endif

posted @ 2011-07-28 07:24 RTY 阅读(781) | 评论 (0)编辑 收藏

Bitdefender 全方位安全杀毒软件激活码(序列号)/Bitdefender Internet Security正版激活码
 说明:以下激活码(序列号)适用Bitdefender Internet Security 2011
BitDefender Internet Security 2011正版激活码一年期,可激活最新版本2011
激活码 67PIDQD

BitDefender Internet Security 2011激活码一枚【LA0G】(365天)
激活码 NGELA0G


BitDefender Internet Security 2011激活码一枚【5X3Q】(180天)
激活码 SQA5X3Q


BitDefender Internet Security 2011激活码一枚【14A2】(283天)
14A20BF746E7C46DC941


BitDefender Internet Security 2011最新激活码(180天)

激活码
5LLHJ7I         356天
AIFRUVN         173天
N7T5033         173天
5UZXTCE         175天
XLWWGV0         1051天


BitDefender Internet Security 2011激活码【NDS0】(152天)
激活码 QVUNDS0


BitDefender Internet Security 2011可叠加180天激活码两枚
激活码: LTHGXPX
激活码: LFWHQ4Y


BitDefender Internet Security 2011最新激活码(180天)两枚
激活码: 4J24PJJ
激活码: YVKAS47

posted @ 2011-07-26 22:24 RTY 阅读(745) | 评论 (0)编辑 收藏

看到const 关键字,C++程序员首先想到的可能是const 常量。这可不是良好的条件反射。如果只知道用const 定义常量,那么相当于把火药仅用于制作鞭炮。const 更大的魅力是它可以修饰函数的参数、返回值,甚至函数的定义体。

const 是constant 的缩写,“恒定不变”的意思。被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多C++程序设计书籍建议:“Use const whenever you need”。

1.用const 修饰函数的参数

如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加const 修饰,否则该参数将失去输出功能。const 只能修饰输入参数:

如果输入参数采用“指针传递”,那么加const 修饰可以防止意外地改动该指针,起到保护作用。

例如StringCopy 函数:

void StringCopy(char *strDestination, const char *strSource);

其中strSource 是输入参数,strDestination 是输出参数。给strSource 加上const修饰后,如果函数体内的语句试图改动strSource 的内容,编译器将指出错误。

如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const 修饰。

例如不要将函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A 为用户自定义的数据类型。

对于非内部数据类型的参数而言,象void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A 类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。

为了提高效率,可以将函数声明改为void Func(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临时对象。但是函数void Func(A &a) 存在一个缺点:

“引用传递”有可能改变参数a,这是我们不期望的。解决这个问题很容易,加const修饰即可,因此函数最终成为void Func(const A &a)。

以此类推,是否应将void Func(int x) 改写为void Func(const int &x),以便提高效率?完全没有必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。

问题是如此的缠绵,我只好将“const &”修饰输入参数的用法总结一下。

 

对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是提高效率。例如将void Func(A a) 改为void Func(const A &a)。

 

对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &x)。

2 用const 修饰函数的返回值
如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。例如函数
const char * GetString(void);
如下语句将出现编译错误:
char *str = GetString();
正确的用法是
const char *str = GetString();
如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。
例如不要把函数int GetInt(void) 写成const int GetInt(void)。
同理不要把函数A GetA(void) 写成const A GetA(void),其中A 为用户自定义的数据类型。
如果返回值不是内部数据类型,将函数A GetA(void) 改写为const A & GetA(void)的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。
函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。

例如:
class A
{
A & operate = (const A &other); // 赋值函数
};
A a, b, c; // a, b, c 为A 的对象

a = b = c; // 正常的链式赋值
(a = b) = c; // 不正常的链式赋值,但合法
如果将赋值函数的返回值加const 修饰,那么该返回值的内容不允许被改动。上例中,语句 a = b = c 仍然正确,但是语句 (a = b) = c 则是非法的。
3 const 成员函数
任何不会修改数据成员的函数都应该声明为const 类型。如果在编写const 成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误,这无疑会提高程序的健壮性。以下程序中,类stack 的成员函数GetCount 仅用于计数,从逻辑上讲GetCount 应当为const 函数。编译器将指出GetCount 函数中的错误。
class Stack
{
public:
void Push(int elem);
int Pop(void);
int GetCount(void) const; // const 成员函数
private:
int m_num;
int m_data[100];
};
int Stack::GetCount(void) const
{
++ m_num; // 编译错误,企图修改数据成员m_num
Pop(); // 编译错误,企图调用非const 函数
return m_num;
}
const 成员函数的声明看起来怪怪的:const 关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。
关于Const函数的几点规则:

a. const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
b. const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
c. const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
e. 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的

posted @ 2011-07-26 07:14 RTY 阅读(237) | 评论 (0)编辑 收藏

const类型定义:指明变量或对象的值是不能被更新,引入目的是为了取代预编译指令 

**************常量必须被初始化*************************

cons的作用
   (1)可以定义const常量         例如:
             const int Max=100;
             int Array[Max];        
   (2)便于进行类型检查            例如:
             void f(const int i) { .........}
        编译器就会知道i是一个常量,不允许修改;
   (3)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。
        还是上面的例子,如果在函数体内修改了i,编译器就会报错;
        例如: 
             void f(const int i) { i=10;//error! }
    (5) 为函数重载提供了一个参考。
         class A
         {
           ......
           void f(int i)       {......} file://一个函数
           void f(int i) const {......} file://上一个函数的重载
            ......
          };
     (6) 可以节省空间,避免不必要的内存分配。
         例如:
              #define PI 3.14159         file://常量宏
              const doulbe  Pi=3.14159;  file://此时并未将Pi放入ROM中
              ......
              double i=Pi;               file://此时为Pi分配内存,以后不再分配!
              double I=PI;               file://编译期间进行宏替换,分配内存
              double j=Pi;               file://没有内存分配
              double J=PI;               file://再进行宏替换,又一次分配内存!
         const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
     (7) 提高了效率。
           编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

使用const
   (1)修饰一般常量,常数组,常对象
   修饰符const可以用在类型说明符前,也可以用在类型说明符后。      例如:   
           int const x=2;  或  const int x=2;

       int const a[5]={1, 2, 3, 4, 5};    或  const int a[5]={1, 2, 3, 4, 5};

           class A;      const A a;  或     A const a;
     
   (2)修饰指针
        const int *A;   或  int const *A; //const修饰指向的对象,A可变,A指向的对象不可变
        int *const A;              //const修饰指针A,     A不可变,A指向的对象可变 
        const int *const A;      //指针A和A指向的对象都不可变
   (3)修饰引用
        const double & v;      该引用所引用的对象不能被更新
 (4)修饰函数的返回值:
        const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下:
            const int Fun1(); 
            const MyClass Fun2();
   (5)修饰类的成员函数:
        const修饰符也可以修饰类的成员函数,格式如下:
            class ClassName 
     {
             public:
                  int Fun() const;
                    .....
             };
        这样,在调用函数Fun时就不能修改类里面的数据 
    (6)在另一连接文件中引用const常量
         extern const int i;     //正确的引用
         extern const int j=10;  //错误!常量不可以被再次赋值
   


*******************放在类内部的常量有什么限制?
  
        class A
        {
         private:
           const int c3 = 7;               // err
           static int c4 = 7;               // err
           static const float c5 = 7;  // err
          ......
  };
 初始化类内部的常量
        1 初始化列表:
         class A
         {
          public:
                A(int i=0):test(i) {}
          private:
                const int i;
          };
         2 外部初始化,例如:
         class A
         {
          public:
                A() {}
          private:
                static const int i;  
          };
          const int A::i=3; 

posted @ 2011-07-26 07:13 RTY 阅读(199) | 评论 (0)编辑 收藏

1.虚函数
1.1虚函数的作用
虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
class Time{
  public:
    Time(int=0,int=0,int=0);
    void show();
  protected:
    int hour;
    int min;
    int sec;
};
 
class LocalTime:public Time{
  public:
    LocalTime(int=0,int=0,int=0,string="+8");
    void show();
  protected:
    string zone;
};
 
Time::Time(int h,int m,int s):hour(h),min(m),sec(s){}
 
void Time::show(){
  cout<<hour<<":"<<min<<":"<<sec<<endl;
}
 
LocalTime::LocalTime(int h,int m,int s,string z):Time(h,m,s),zone(z){}
 
void LocalTime::show(){
  cout<<hour<<":"<<min<<":"<<sec<<"@"<<zone<<endl;    
}
 
int main(){
  Time t;
  LocalTime lt;
  Time *pt=&t;
  pt->show();
  pt=&lt;
  pt->show();
  system("PAUSE");
  return EXIT_SUCCESS;
}
结果:
0:0:0
0:0:0
这里通过指针找到派生类,但无法调用派生类show()。如果使用虚函数。
将基类Time中的show()函数声明为虚函数, 其余不变。
class Time{
  public:
    Time(int=0,int=0,int=0);
    virtual void show();
};
结果:
0:0:0
0:0:0@+8
本来,基类指针是指向基类对象的,如果用它指向派生类对象,则进行指针类型转换,将派生类对象的指针先转换为基类指针,所以基类指针指向的是派生类对象中的基类部分。在程序修改前,是无法通过基类指针去调用派生类对象中的成员函数的。
虚函数突破这一限制,在派生类的基类部分中,派生类的虚函数取代了基类原来的虚函数,因此在使用基类指针指向派生类对象后,调用虚函数时就调用了派生类的虚函数。
 
1.2虚函数的使用方法
【1】在基类用virtual声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便地被调用。
 
【2】在派生类中重新定义此函数,要求函数名、函数(返回)类型、函数参数个数和类型与基函数的虚函数相同。如果在派生类中没有对基类的虚函数重定义,则派生类简单地继承直接基类的虚函数。
有一种情况例外,在这种情况下派生类与基类的成员函数返回类型不同,但仍起到虚函数的作用。即基类虚函数返回一个基类指针或基类引用,而子类的虚函数返回一个子类的指针或子类的引用。
class Base{
  public:
    virtual Base *fun(){
      cout<<"Base's fun()."<<endl;
      return this;
    }
};
 
class Derived:public Base{
  public:
    virtual Derived *fun(){
      cout<<"Derived's fun()."<<endl;
      return this;
    }
};
 
void test(Base &x){
  Base *b;
  b=x.fun();
}
 
int main(){
  Base b; 
  Derived d;
  test(b);
  test(d);   
  system("PAUSE");
  return EXIT_SUCCESS;
}
结果:
Base's fun().
Derived's fun().
 
【3】C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数(符合2中定义的函数)都自动成为虚函数。
 
【4】定义一个指向基类对象的指针变量,并使其指向同一类族中的某个对象。通过该指针变量调用此函数,此时调用的就是指针变量指向的对象的同名函数。
 
1.3声明虚函数的限制
【1】只能用virtual声明类的成员函数,使它成为虚函数,而不能将类外的普通函数声明为虚函数。
 
【2】一个成员函数被声明为虚函数后,在同一类族中的类就不能再定义一个非virtual的但与该虚函数具有相同参数(个数与类型)和函数返回值类型的同名函数。
 
【3】静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象。
 
【4】inline函数不能是虚函数,因为inline函数是不能在运行中动态确定其位置的。即使虚函数在类的内部定义,编译时,仍将其视为非inline的。
 
【5】使用虚函数,系统要有一定的空间开销。当一个类带有虚函数时,编译器会为该类构造一个虚函数表(virtual function tanle,vtable),它是一个指针数组,存放每个虚函数的入口地址。
2.虚析构函数
class Time{
  public:
    Time(int=0,int=0,int=0);
    ~Time(){
      cout<<"Time destructor"<<endl;
    }       
  protected:
    int hour;
    int min;
    int sec;
};           
 
class LocalTime:public Time{
  public:
    LocalTime(int=0,int=0,int=0,string="+8");
    ~LocalTime(){
      cout<<"LocalTime destructor"<<endl;
    }
  protected:
    string zone;
};                 
 
Time::Time(int h,int m,int s):hour(h),min(m),sec(s){}
 
LocalTime::LocalTime(int h,int m,int s,string z):Time(h,m,s),zone(z){}
 
int main(){
  Time *p=new LocalTime;//指向派生类
  delete p;  
  system("PAUSE");
  return EXIT_SUCCESS;
}
结果:
Time destructor
从结果可以看出,执行的还是基类的析构函数,而程序的本意是希望执行派生类的析构函数。此时将基类的析构函数声明为虚析构函数,
virtual ~Time(){
  cout<<"Time destructor"<<endl;
}
结果:
LocalTime destructor
Time destructor
如果将基类的析构函数声明为虚函数,由该基类所派生的所有派生类的析构函数也自动成为虚函数。
把基类的析构函数声明为虚函数的好处是,如果程序中delete一个对象,而delete运算符的操作对象是指向派生类对象的基类指针,则系统会调用相应类的析构函数。
构造函数不能声明为虚函数。
3.纯虚函数
virtual void show()=0;//纯虚函数
这里将show()声明为纯虚函数(pure virtual function)。纯虚函数是在声明虚函数时被“初始化”为0的虚函数。
声明纯虚函数的一般形式为,
virtual 函数类型 函数名(参数列表)=0;
纯虚函数没有函数体;最后的“=0”并不代表函数返回值为0,它只起形式上的作用,告诉编译器“这是纯虚函数”;这个一个声明语句,最后有分号。
声明纯虚函数是告诉编译器,“在这里声明了一个虚函数,留待派生类中定义”。在派生类中对此函数提供了定义后,它才能具备函数的功能,可以被调用。
纯虚函数的作用是在基类中为其派生类保留了一个函数的名字,以便派生类根据需要对它进行定义。
如果在一个类中声明了纯虚函数,而在其派生类中没有对该函数定义,则该函数在派生类中仍为纯虚函数。
4.抽象类
将不用来定义对象而只作为一种基本类型用作继承的类,称为抽象类(abstract class),由于它常用作基类,通常称为抽象基类。凡是包含纯虚函数的类都是抽象类。
如果在派生类中没有对所有的纯虚函数进行定义,则此派生类仍然是抽象类,不能用来定义对象。
可以定义指向抽象类数据的指针变量。当派生类成为具体类后,就可以用这个指针指向派生类对象,然后通过该指针调用虚函数。

posted @ 2011-07-26 06:59 RTY 阅读(455) | 评论 (0)编辑 收藏

1.  Qt 全局宏定义

Qt版本号:

 QT_VERSION :  (major << 16) + (minor << 8) + patch

检测版本号:

QT_VERSION_CHECK(major, minor, patch)((major<<16)|(minor<<8)|(patch))

当使用命名空间时的一些宏定义:

namespace QT_NAMESPACE {} //命名空间定义

# define QT_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name

# define QT_USE_NAMESPACE using namespace ::QT_NAMESPACE;

# define QT_BEGIN_NAMESPACE namespace QT_NAMESPACE {

# define QT_END_NAMESPACE }

# define QT_BEGIN_INCLUDE_NAMESPACE }

# define QT_END_INCLUDE_NAMESPACE namespace QT_NAMESPACE {

# define QT_BEGIN_MOC_NAMESPACE QT_USE_NAMESPACE

# define QT_END_MOC_NAMESPACE

# define QT_FORWARD_DECLARE_CLASS(name) /

    QT_BEGIN_NAMESPACE class name; QT_END_NAMESPACE /

    using QT_PREPEND_NAMESPACE(name);

 

# define QT_FORWARD_DECLARE_STRUCT(name) /

    QT_BEGIN_NAMESPACE struct name; QT_END_NAMESPACE /

    using QT_PREPEND_NAMESPACE(name);

Q_GLOBAL_STATIC(type, name)用于定义一个全局的静态变量(线程安全的).用它来初始化一个对象指针(函数指针).

Q_GLOBAL_STATIC_WITH_ARGS(type, name, arguments):同上,可带参数.

 

Q_UNUSED():通常用于某个函数的参数,表明该参数未在方法体中使用.

常用数据类型:

qint8, quint8, qint16, quint16, qint32, quint32, qint64, quint64, qlonglong(=int64), qulonglong(=uint64)

quintptr, qptrdiff, 作为指针是一样大的.如:

      sizeof(void *) == sizeof(quintptr)

      && sizeof(void *) == sizeof(qptrdiff)

Qt有用的类型定义:uchar, ushort, uint, ulong

实用内联函数:qAbs(), qRound(), qRound64(), qMin(), qMax(), qBound();

try-catch宏:

#ifdef QT_NO_EXCEPTIONS

#  define QT_TRY if (true)

#  define QT_CATCH(A) else

#  define QT_THROW(A) qt_noop()

#  define QT_RETHROW qt_noop()

#else

#  define QT_TRY try

#  define QT_CATCH(A) catch (A)

#  define QT_THROW(A) throw A

#  define QT_RETHROW throw

#endif

每个QT_TRY对应一个QT_CATCH,不要在catch语句块中使用异常实例.

 

调试相关函数:

qDebug(), qWarnig(), qCritical(), Q_ASSERT()

 

其他一些函数:

该宏用于定义某个类,禁止拷贝

#define Q_DISABLE_COPY(Class) /

    Class(const Class &); /

    Class &operator=(const Class &);

qgetenv(), qputenv(), qIntCast(double 或float). qsrand(uint seed), qrand()

2. Qt的内存管理函数

void *qMalloc(size_t size);

void qFree(void *ptr);

void *qRealloc(void *ptr, size_t size);

void *qMallocAligned(size_t size, size_t alignment)

void *qReallocAligned(void *oldptr, size_t newsize, size_t oldsize, size_t alignment)

void qFreeAligned(void *ptr)

void *qMemCopy(void *dest, const void *src, size_t n);

void *qMemSet(void *dest, int c, size_t n);

注: 数组下标为-1的地址对于数组来说是越界访问了,但是这个地址是有意义的.这个地址就是所申请的数组存储空间的首地址的向前偏移一个单位(也就是偏移一个当前数组类型所对应的字节数)所对应的地址。这个地址由于没有跟着数组空间一起初始化,所以其中的数据是不确定的.如果是正在被系统或者其他应用程序使用中的地址空间,那么可以被访问,其中的数据的意义取决于被系统或者其他应用程序所写入的数据,但是访问后,有可能会引起系统或者其他应用程序异常。如果是没有被使用的地址,那么就是一个野地址,那么其中的数据是随机的,无意义的

 

3. 环境变量设置函数

qputenv():与putenv()基本类似,由于VC2005后废除了putenv()函数,所有定义了此函数,在VC环境中调用替代的函数,其他平台调用标准C库函数putenv().

qgetenv():获取某个环境变量的值.

 

4.自定义输出函数

QtMsgHandler qInstallMsgHandler(QtMsgHandler h)

其中:typedef void (*QtMsgHandler)(QtMsgType, const char *);

利用该函数可定制自己的调试信息输出.

 

5. 断言

Q_ASSERT(bool test):当断言失败时,打印出警告信息,包含了源码文件名和行号.

void Q_ASSERT_X(bool test, const char *where, const char *what)

 

void Q_CHECK_PTR(void *pointer):检测非法指针,如果指针为0,打印警告信息.

 

6.系统信息类QsysInfo

posted @ 2011-07-26 06:53 RTY 阅读(4209) | 评论 (0)编辑 收藏

     摘要: 比起源码级别的模块化,二进制级别的模块划分使得各模块更加独立,各模块可以分别编译和链接,模块的升级不会引起其它模块和主程序的重新编译,这点对于大系统的构建来说更加实用。AD:继续 Qt编写模块化插件式应用程序 (上篇) 的内容继续介绍,本节介绍的是Qt编写模块化插件式应用程序 (下篇),我们先来看内容。2. 编写Animal插件——BilDog和BilP...  阅读全文

posted @ 2011-07-26 06:42 RTY 阅读(576) | 评论 (0)编辑 收藏

     摘要: 比起源码级别的模块化,二进制级别的模块划分使得各模块更加独立,各模块可以分别编译和链接,模块的升级不会引起其它模块和主程序的重新编译,这点对于大系统的构建来说更加实用。AD:动态链接库技术使软件工程师们兽血沸腾,它使得应用系统(程序)可以以二进制模块的形式灵活地组建起来。比起源码级别的模块化,二进制级别的模块划分使得各模块更加独立,各模块可以分别编译和链接,模块的升级不会引起其它模块和主程序的重新...  阅读全文

posted @ 2011-07-26 06:40 RTY 阅读(511) | 评论 (0)编辑 收藏

仅列出标题
共31页: First 11 12 13 14 15 16 17 18 19 Last