Legend

#

.net开源项目

.net开源项目
http://www.cnblogs.com/apollo086574/archive/2007/10/06/915298.html

列数.NET开源项目
paint
http://www.getpaint.net/index.html

About Apache log4net

log4net is a tool to help the programmer output log statements to a variety of output targets. log4net is a port of the excellent log4j framework to the .NET runtime. We have kept the framework similar in spirit to the original log4j while taking advantage of new features in the .NET runtime. For more information on log4net see the features document.

log4net is part of the Apache Logging Services project. The Logging Services project is intended to provide cross-language logging services for purposes of application debugging and auditing.

http://logging.apache.org/log4net/download.html


Nunit

对应Java中的Junit,非常著名的单元测试工具。

链接:
http://www.nunit.org/

Nlog

一个日志管理库,类似于Log4Net。

链接:
http://www.nlog-project.org/

posted @ 2007-10-06 17:03 Legend 阅读(318) | 评论 (0)编辑 收藏

file2

file

posted @ 2007-08-03 01:54 Legend 阅读(158) | 评论 (0)编辑 收藏

可变参数的实现

http://www.cnblogs.com/kusamba/articles/354830.html

posted @ 2007-05-10 10:18 Legend 阅读(136) | 评论 (0)编辑 收藏

member function pointer

class   test  
{  
public:  
 void   (test::*p)();  
 void   Print(){cout<<"Test"<<endl;}  
 test(){p   =   &test::Print;}  
};  

void   (test::*q)();

posted @ 2007-04-26 15:35 Legend 阅读(116) | 评论 (0)编辑 收藏

inline virtual function

标准C++编程:虚函数与内联

Josée Lajoie and Stanley Lippman

------------------------------------------------------------------------------
----

[This is the last installment of a column that was being published in C++ Repo
rt magazine. Since the magazine ceased publication before this installment cou
ld be published, Josée Lajoie and Stan Lippman were gracious enough to let us
publish it on the CUJ website. — mb]

 

曾经,我们常常在谈及C++时听到一个问题:“虚函数真的应该被申明为内联吗?”现在,
我们很少再听到这个问题了。反过来,我们现在听到的是“你不应该将print()函数内联。
将虚函数申明为内联是错误的。”

这么说有两个主要理由:(1)虚函数是在运行期判决的,而内联是编译期行为,所以不能从
这个(内联)申明上得到任何好处;(2)将虚函数申明为内联将造成此函数在可执行文件中
有多份拷贝,因此我们为一个无论如何都不能内联的函数付出了在空间上的处罚(WQ注,
所谓的内联函数非内联问题)。显然没脑子。

只是它并不真的正确。反思一下理由(1):在很多情况下,虚函数是静态判决的--尤其是
派生类的虚函数调用它的基类版本时。为什么会那么做?封装。一个很好的例子是析构函
数的静态调用链:基类的析构函数被派生类的析构函数触发。除了最初的一个外,所有的
析构函数的调用都是被静态判决的。不让基类的虚析构函数内联,就不能从中获益。这会
造成很大的差别吗?如果继承层次很深,而又有大量的对象需要析构,(答案是)“是的
”。

另外一个例子不涉及析构函数。想像我们正在设计一个图书馆出借管理程序。我们已经将
“位置”放入抽象类LibraryMaterial。当申明print()函数为纯虚函数时,我们也提供其
定义:打印出对象的位置。

class LibraryMaterial {

private:

MaterialLocation _loc; // shared data

// ...

 

public:

// declares pure virtual function

inline virtual void print( ostream& = cout ) = 0;

};

 

// we actually want to encapsulate the handling of the

// location of the material within a base class

// LibraryMaterial print() method - we just don’t want it

// invoked through the virtual interface. That is, it is

// only to be invoked within a derived class print() method

 

inline void

LibraryMaterial::

print( ostream &os ) { os << _loc; }

 

 

接着引入Book类;它的print()函数会输出书名、作者等等。在此之前,它先调用基类的L
ibraryMaterial::print()函数以显示位置信息。例如:

inline void

Book::

print( ostream &os )

{

// ok, this is resolved statically,

// and therefore is inline expanded ...

LibraryMaterial::print();

 

os << "title:" << _title

<< "author" << _author << endl;

}

AudioBook类从Book派生,引入了一个二选一的借出策略,并且加入了一些附加信息,比如
讲解员、格式等等。这些都将在它的print()函数中显示出来。在显示这些以前,它先调用
Book::print():

 

inline void

AudioBook::

print( ostream &os )

{

// ok, this is resolved statically,

// and therefore is inline expanded ...

Book::print();

os << "narrator:" << _narrator << endl;

}

在这个例子和析构函数的例子中,派生类的虚方法递增式地扩展其基类版本的功能,并以
调用链的方式被调用,只有最初一次调用是由虚体系决定的。这个没有被命名的继承树设
计模式,如果从不将虚函数申明为内联的话,显然会有些低效。

关于理由(2)的代码膨胀问题怎么说?好吧,思考一下。如果写出,

LibraryMaterial *p =

new AudioBook( "Mason & Dixon",

"Thomas Pynchon", "Johnny Depp" );

// ...

p->print();

此处的print()会内联吗?不,当然不会。这必须在运行期经过虚体系的判决。Okay。它会
导致此处的print()函数有它自己的定义体吗?也不会。调用被编译为类似于这种形式:


// Pseudo C++ Code

// Possible transformation of p->print()

( *p->_vptr[ 2 ] )( p );

那个2是print()函数在相应的虚函数表中的位置。因为这个对print()的调用是通过函数指
针_vptr[2]进行的,编译器不能静态决定被调用函数的位置,并且函数不能被内联。

当然,内联的虚函数print()的定义必须出现在可执行文件中的某处,代码才能正确执行。
也就是说,至少需要一个定义体,以便将它的地址放入虚函数表。编译器如何决定何时产
生那一个定义体的呢?一个实现策略是在产生那类的虚函数表时同时产生那个定义体。这
意味着针对为一个类所生成的每个虚函数表实例,每个内联的虚函数的一个实例也被产生

在可执行文件中,为一个类产生的虚函数表,实际上有多少个?啊,很好,问得好。C++标
准规定了虚函数在行为上的要求;但它没有规定实现虚函数上的要求。既然虚函数表的存
在不是C++标准所要求的,明显标准也没有进一步要求如何处理虚函数表以及生成多少次。
最佳的数目当然是“一次”。例如,Stroustrup的原始cfront实现版本,在大部份情况下
聪明地达成了这一点。 (Stan和Andy Koenig描述了其算法,发表于1990年3月,C++ Repo
rt,“Optimizing Virtual Tables in C++ Release 2.0.”)

此外,C++标准现在要求内联函数的行为要满足好象程序中只存在一个定义体,即使这个函
数可能被定义在不同的文件中。新的规则是说满足规定的实现版本,行为上应该好象只生
成了一个实例。一旦标准的这一点被广泛采用,对内联函数潜在的代码膨胀问题的关注应
该消失了。

C++社群中存在着一个冲突:教学上需要规则表现为简单的检查表vs实践中需要明智地依据
环境而运用规则。前者是对语言的复杂度的回应;后者,是对我们构造的解决方案的复杂
度的回应。何时将虚函数申明为内联的问题,是这种冲突的一个很好的例证。

 

About the Authors
Stanley Lippman was the software Technical Director for the Firebird segment o
f Disney's Fantasia 2000. He was recently technical lead on the ToonShooter im
age capture and playback system under Linux for DreamWorks Feature Animation a
nd consulted with the Jet Propulsion Laboratory. He is currently IT Training P
rogram Chair for You-niversity.com, an e-learning training company. He can be
reached at stanleyl@you-niversity, www.you-niversity.com, and www.objectwrite.
com.

Josée Lajoie is currently doing her Master's degree in Computer Graphics at t
he University Waterloo. Previously, she was a member of the C/C++ compiler dev
elopment team at the IBM Canada Laboratory and was the chair of the core langu
age working group for the ANSI/ISO C++ Standard Committee. She can be reached
at jlajoie@cgl.uwaterloo.ca.

posted @ 2007-04-26 14:55 Legend 阅读(788) | 评论 (0)编辑 收藏

static functions

类的成员函数分为两种,一种是静态函数,另外一种是非静态函数。例如:
class X
{
public:
 static void display();
 bool getValue();
}
display()为静态函数,getValue即为非静态函数。两种函数在使用的时候是不一样的。静态函数
可以直接由类名来调用,而非静态函数则必须通过某一个对象来调用,例如:
X::display();
X x;
x.getValue();
为什么会出现这样的情况了?这是由于编译器在处理这两种函数的方式不同造成的。静态函数在
运行期只有一份拷贝,所有该类生成的对象共享该函数以及该函数的内部变量。而对于非静态函数,
不同的对象拥有自己的内部变量。

静态成员函数与普通成员函数的差别就在于缺少this指针,没有这个this指针自然也就无从知道name是哪一个对象的成员了。

  根据类静态成员的特性我们可以简单归纳出几点,静态成员的使用范围:

  1.用来保存对象的个数。

  2.作为一个标记,标记一些动作是否发生,比如:文件的打开状态,打印机的使用状态,等等。

  3.存储链表的第一个或者最后一个成员的内存地址。

  为了做一些必要的练习,深入的掌握静态对象的存在的意义,我们以前面的结构体的教程为基础,用类的方式描述一个线性链表,用于存储若干学生的姓名,代码如下:

 

对于静态成员函数的一些限制

1.静态成员函数只能引用这个类的其他静态成员(当然也可以访问全局函数和数据)。
2.静态成员函数没有this指针。
3.同一个函数不能有静态和非静态两种版本,静态成员函数不可以是虚函数。
4.它们不能被声明为const或volatile。
 
静态成员函数也属于整个类,所以可以通过使用类名和作用域分辨符被其本身调用(独立于对象),也可以和对象联系起来调用。
 
实际上,静态成员函数的应用是有限的,使用它的好处是在实际创建任何对象之前可以“预初始化”私有的静态数据。

 

posted @ 2007-04-26 14:50 Legend 阅读(218) | 评论 (0)编辑 收藏

解析__cdecl,__fastcall, __stdcall 的不同

在函数调用过程中,会使用堆栈,这三个表示不同的堆栈调用方式和释放方式。
比如说__cdecl,它是标准的c方法的堆栈调用方式,就是在函数调用时的参数压入堆栈是与函数的声明顺序相反的,其它两个可以看MSDN,不过这个对我们编程没有太大的作用

调用约定

调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。MFC支持以下调用约定:


_cdecl

按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于"C"函数或者变量,修饰名是在函数名前加下划线。对于"C++"函数,有所不同。

如函数void test(void)的修饰名是_test;对于不属于一个类的"C++"全局函数,修饰名是?test@@ZAXXZ

这是MFC缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。


_stdcall

按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于"C"函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号"@"及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。对于"C++"函数,则有所不同。

所有的Win32 API函数都遵循该约定。


_fastcall

头两个DWORD类型或者占更少字节的参数被放入ECX和EDX寄存器,其他剩下的参数按从右到左的顺序压入栈。由被调用者把参数弹出栈,对于"C"函数或者变量,修饰名以"@"为前缀,然后是函数名,接着是符号"@"及参数的字节数,如函数int func(int a, double b)的修饰名是@func@12。对于"C++"函数,有所不同。

未来的编译器可能使用不同的寄存器来存放参数。


  关键字   调用规则 参数传递方向 返回 参数寄存器 堆栈的清除  
  __cdecl   C调用规则 从右向左 EAX 无 调用者  
  __fastcall 寄存器 从左向右 EAX EAX、EBX、ECX 被调用者  
  __stdcall Win32标准 从右向左 EAX 无 被调用者  
  __pascal Pascal 从左向右 EAX 无 被调用者  
  __msfastcall Ms寄存器 从右向左 EAX/EDX ECX、EDX 被调用者   
   
C++   Builder中几种调用规则的比较  

 1.   名字分解:  
          没有名字分解的函数  
                  TestFunction1 //   __cdecl   calling   convention  
                  @TestFunction2 //   __fastcall   calling   convention  
                  TESTFUNCTION3 //   __pascal   calling   convention  
                  TestFunction4 //   __stdcall   calling   convention  
          有名字分解的函数  
                  @TestFunction1$QV //   __cdecl   calling   convention  
                  @TestFunction2$qv //   __fastcall   calling   convention  
                  TESTFUNCTION3$qqrv //   __apscal   calling   convention  
                  @TestFunction4$qqrv //   __stdcall   calling   convention  
          使用   extern   "C"   不会分解函数名  
   
          使用   Impdef   MyLib.def   MyLib.dll   生成   def   文件查看是否使用了名字分解  
   
  2.   调用约定:  
          __cdecl   缺省  
              是   Borland   C++   的缺省的   C   格式命名约定,它在标识符前加一下划线,以保留  
          它原来所有的全程标识符。参数按最右边参数优先的原则传递给栈,然后清栈。  
                  extaern   "C"   bool   __cdecl   TestFunction();  
              在   def   文件中显示为    
                  TestFunction @1  
              注释:   @1   表示函数的顺序数,将在“使用别名”时使用。  
   
          __pascal   Pascal格式  
              这时函数名全部变成大写,第一个参数先压栈,然后清栈。  
                  TESTFUNCTION @1 //def   file  
   
          __stdcall   标准调用  
              最后一个参数先压栈,然后清栈。  
                  TestFunction @1 //def   file  
   
          __fastcall   把参数传递给寄存器  
              第一个参数先压栈,然后清栈。  
                  @TestFunction @1 //def   file  
   
  3.   解决调用约定:  
              Microsoft   与   Borland   的   __stdcall   之间的区别是命名方式。   Borland   采用  
          __stdcall   的方式去掉了名字起前的下划线。   Microsoft   则是在前加上下划线,在  
          后加上   @   ,再后跟为栈保留的字节数。字节数取决于参数在栈所占的空间。每一个  
          参数都舍入为   4   的倍数加起来。这种   Miocrosoft   的   Dll   与系统的   Dll   不一样。  
   
  4.   使用别名:  
              使用别名的目的是使调用文件   .OBJ   与   DLL   的   .DEF   文件相匹配。如果还没有  
          .DEF   文件,就应该先建一个。然后把   DEF   文件加入   Project。使用别名应不断  
          修改外部错误,如果没有,还需要将   IMPORTS   部分加入   DEF   文件。  
                  IMPORTS  
                  TESTFUNCTIOM4   =   dllprj.TestFunction4  
                  TESTFUNCTIOM5   =   dllprj.WEP @500  
                  TESTFUNCTIOM6   =   dllprj.GETHOSTBYADDR @51  
              这里需要说明的是,调用应用程序的   .OBJ   名与   DLL   的   .DEF   文件名是等价的,  
          而且总是这样。甚至不用考虑调用约定,它会自动匹配。在前面的例子中,函数被  
          说明为   __pascal,因此产生了大写函数名。这样链接程序不会出错。

其他连接

http://blog.csdn.net/lotomer/archive/2006/06/28/844658.aspx

posted @ 2007-04-26 14:46 Legend 阅读(617) | 评论 (1)编辑 收藏

About D3D

http://blog.csdn.net/neoragex2002/archive/2007/01/27/1495786.aspx

http://www.cnblogs.com/wangdaniu/archive/2006/09/25/514334.html

posted @ 2007-04-16 00:44 Legend 阅读(154) | 评论 (0)编辑 收藏

确保资源为对象所有

C++编程规范

利器在手,不要再徒手为之
C++语言所强制施行的构造函数/析构函数对称反映了资源获取/释放函数对,比如fopen/fclose, lock/unlock, new/delete, malloc/free的本质的对称性,这使得具有资源获取的构造函数和具有资源释放的析构函数的基于栈(或引用计数)的对象成为了自动化资源管理和清除的极佳工具

posted @ 2007-04-16 00:33 Legend 阅读(130) | 评论 (0)编辑 收藏

About auto_ptr

auto_ptr 实现代码
auto_ptr实现代码 (摘自<<More Effective c++>> Page 293)2006年09月11日 星期一 20:24template <class T>
class auto_ptr
{
public:
    explicit auto_ptr(T*p = 0) : pointee(p){}
   
    template<class U> auto_ptr(auto_ptr<U>& r);

    ~auto_ptr(){delete pointee;}

    template<class U> auto_ptr<T>& operator=(auto_ptr<U>& r);

    T& operator*() const {return *pointee;}
    T* operator->() const {return pointee;}
    T* get() const {return pointee;}
    T* release(){
        T* old = pointee;
        pointee = 0;
        return old;
    }

    void reset(T*p = 0){
        if(pointee != p) {
            delete pointee;
            pointee = p;
        }
    }

private:
    T* pointee;
    template<class U> friend class auto_ptr<U>;
};

template<class T>
    template<class U>
    inline auto_ptr<T>::auto_ptr(auto_ptr<U>& r)
    : pointee(r.release()) {}

template<class T>
    template<class U>
    inline auto_ptr<T>& operator=(auto_ptr<U>& r){
        if(this != &r) reset(r.release());
        return *this;
    }

另外 SGI C++中的auto_ptr
/*
 * Copyright (c) 1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  Silicon Graphics makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 */

#ifndef __SGI_STL_MEMORY
#define __SGI_STL_MEMORY

#include <stl_algobase.h>
#include <stl_alloc.h>
#include <stl_construct.h>
#include <stl_tempbuf.h>
#include <stl_uninitialized.h>
#include <stl_raw_storage_iter.h>


#if defined(__STL_MEMBER_TEMPLATES)

__STL_BEGIN_NAMESPACE

template <class _Tp> class auto_ptr {
private:
  _Tp* _M_ptr;

public:
  typedef _Tp element_type;
  explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
  auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
  template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
    : _M_ptr(__a.release()) {}
  auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
    if (&__a != this) {
      delete _M_ptr;
      _M_ptr = __a.release();
    }
    return *this;
  }
  template <class _Tp1>
  auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
    if (__a.get() != this->get()) {
      delete _M_ptr;
      _M_ptr = __a.release();
    }
    return *this;
  }
  ~auto_ptr() __STL_NOTHROW { delete _M_ptr; }

  _Tp& operator*() const __STL_NOTHROW {
    return *_M_ptr;
  }
  _Tp* operator->() const __STL_NOTHROW {
    return _M_ptr;
  }
  _Tp* get() const __STL_NOTHROW {
    return _M_ptr;
  }
  _Tp* release() __STL_NOTHROW {
    _Tp* __tmp = _M_ptr;
    _M_ptr = 0;
    return __tmp;
  }
  void reset(_Tp* __p = 0) __STL_NOTHROW {
    delete _M_ptr;
    _M_ptr = __p;
  }

  // According to the C++ standard, these conversions are required.  Most
  // present-day compilers, however, do not enforce that requirement---and,
  // in fact, most present-day compilers do not support the language
  // features that these conversions rely on.
 
#ifdef __SGI_STL_USE_AUTO_PTR_CONVERSIONS

private:
  template<class _Tp1> struct auto_ptr_ref {
    _Tp1* _M_ptr;
    auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
  };

public:
  auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
    : _M_ptr(__ref._M_ptr) {}
  template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW
    { return auto_ptr_ref<_Tp>(this->release()); }
  template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
    { return auto_ptr<_Tp1>(this->release()); }

#endif /* __SGI_STL_USE_AUTO_PTR_CONVERSIONS */
};

__STL_END_NAMESPACE
#endif /* member templates */

#endif /* __SGI_STL_MEMORY */


// Local Variables:
// mode:C++
// End:
 
auto_ptr 注意事项

1.auto_ptr不能共享管理的指针的所有权,并且指针是从堆上分配的
2.不能用于管理指针数组,因为它在析构的时候调用的是delete而不是delete[];并且c++类库中还没有具有auto_ptr语意学的指针数组。
3.auto_ptr是解决特殊问题的智能指针的一种,它和引入了引用记数的是智能指针是不一样的,一般来讲,根据auto_ptr的特性,应用unconstant是一种不安全的做法。
4.它不能应用容器中,因为这会涉及到copy以及assignment,这是不安全的,在语言以及库中已经做了预防,会在编译时报错。
总体来说如果把auto_ptr作为函数自变量或者返回值来用的话,就好像把函数内栈上分配的空间地址返回,很不安全。

posted @ 2007-04-16 00:21 Legend 阅读(216) | 评论 (0)编辑 收藏

仅列出标题
共3页: 1 2 3