taocoding


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

CStatusBar创建进度条问题

发表于 2008-07-06 | 分类于 VC
<DIV class=cnt id=blog_text>
想在状态栏中创建一个进度条,没有在框架窗口中定义进度条,再以状态栏为父窗口创建,而是直接从CStatusBar派生一个类,在其中定义了一个CPropressCtrl成员,按照常规的创子控件思路在OnCreate中创建进度条, int CQTStatusBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CStatusBar::OnCreate(lpCreateStruct) == -1)
   return -1;
// TODO: 在此添加您专用的创建代码
CRect rect;
GetClientRect(&rect);
rect.left=rect.right-150;
if(!m_wndProress)
m_wndProress.Create(WS_CHILD | WS_VISIBLE,rect,this,111);
m_wndProress.MoveWindow(rect,false);   //为了在大小改变时重载位置
m_wndProress.SetRange(0,100);
m_wndProress.SetPos(50);
return 0;
}

结果发现进度条并没有产生,通过调试发现这里的rect根本就没有取到值,换在WM_PAINT消息里面处理,结果正常。纳闷了,难道是OnCreate中状态栏还未创建好吗?应该不是的,估计是MFC设计的问题,CStatusBar的Create函数里面就没让设置大小的函数。

删除CToolBar浮动时的菜单

发表于 2008-06-12 | 分类于 VC
&nbsp; 你可以通过重写ON_WM_WINDOWPOSCHANGED消息处理函数来删除浮动状态下的工具栏实际是系统菜单。这个函数在CToolBar的大小,位置或者Z轴顺序改变时被调用。我们并没有处理WM_SIZE消息处理函数,因为这个函数仅仅只是在大小改变时被调用,而每次当工具栏浮动时并没有被调用。 

       我们可以通过CControlBar类的成员m_pDockBar成员而不是通过直接调用GetParent()来得到工具栏的父窗口。从CToolBar派生一个类,我暂且称之为CToolBarEx,当然你可以选择一个你认为适合的名字。我们仅仅是在工具栏浮动是删除实际是系统菜单,所以检查工具栏是否是正在浮动状态,并确保m_pDockBar是一个合法的指针。

       在你的新类中添加如下成员变量: BOOL m_bMenuRemoved;

       当我们删除系统菜单时将其设置为TRUE,确保仅仅在需要是删除系统菜单。
我们需要得到一个m_pDockBar指针来检查工具栏是否确实是在一个CDockFrameWnd类中,以便可以安全地删除CToolBar的系统菜单。下面是示例代码:

#include <afxpriv.h>

void CXToolBar::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)

{

     CToolBar::OnWindowPosChanged(lpwndpos);

     // should only be called once, when floated.

     if( IsFloating() )

     {

         if( m_pDockBar && !m_bMenuRemoved )

         {

             CWnd* pParent = m_pDockBar-&gt;GetParent();

             if( pParent->IsKindOf(

                           RUNTIME_CLASS(CMiniFrameWnd)))

             {

                 pParent->ModifyStyle( WS_SYSMENU, 0, 0 );

                 m_bMenuRemoved = TRUE;

             }

         }

     }

     else if( m_bMenuRemoved ) {

         m_bMenuRemoved = FALSE;

     }

}
原文网址:www.codejock.com/support/articles/mfc/general/g_8.asp

求素数

发表于 2008-05-23 | 分类于 数据结构/算法
&nbsp;鉴于以前写程序那种不经过仔细思考及分析的不良习惯,觉得画流程翻还是很必要的,而且养成习惯后,对自己的思维锻炼以及高效正确编程有很大的好处。翻开大一时发的《C程序设计》第二章复习了一下,把上面一个很好的例子自己整理了一下,而且发现一个不错的画流程图的工具(Diagram Designer)。以下为全文:

      

问题:将1到1000之间的素数打印出来。 算法描述:“筛选”法,所谓“筛选法”指的是“Eratosthenes筛法”。他采取的方法是,在一张纸上写上1到1000全部整数,然后逐个判断它们是否是素数,找出一个非素数,就把它挖掉,最后剩下的就是素数。 ① 2 3 ④ 5 ⑥ 7 ⑧ ⑨ ⑩……

具体做法如下: ⑴先将1挖掉(因为1不是素数)。 ⑵用2去除它后面的各个数,把能被2整除的数挖掉,即把2的倍数挖掉。 ⑶用3去除它后面的各数,把3的倍数挖掉 ⑷分别用4,5…各数作为除数去除这些数以后的各数。这个过程一直进行到在除数后面的数已经全被挖掉为止。事实上,只需进行到 上面的算法可以表示为: ⑴挖去1 ⑵用下一个未被挖去的数p去除p后面的各数,把p的倍数挖掉。 ⑶检查p是否小于的整数部分(如果n=1000,则检查p<31?),如果是,则返回⑵继续执行,否则就结束。 ⑷纸上剩下的就是素数。 解题的基本思路有了,但要变成计算机的操作,还要做进一步的分析,如怎样判断一个数是否已被挖掉,怎样找出一个数p的倍数,怎样打印出来未被挖掉的数。 用自顶向下逐步细化的方法来处理这个问题,先进行“顶层设计”,见下图。也可以用流程图进行逐步细化。流程图1表示流程的粗略情况,把要做的三部分工作分别用A、B、C表示。

这三部分还不够具体,要进一步细化。A部分可以细化为图A。先输入n,然后将1输入给X1,2输入X2,1000输入给X1000。 B部分可以细化为图B。 B中的B1和B2不能再分了。B1处理的方法是:使X1=0,即哪个数不是素数,就使它等于0,以后把不等于0的数打印处理就是所求的素鼠表。B3中的循环体内以D标志的部分还要进一步细化,对D细化为图D。

图D中的E部分还不够具体,再进一步细化为图E。

图E中的F部分又细化为图F,因为首先要判断某一个Xj是否已经被挖掉,如已被挖掉则不必考虑被Xi除。至此,已不能也不需要再分解了。 图1中的C部分进行细化,得图C1。

再对图C1中的G部分进行细化,得图G。

至此,已将图1分解为能用三种基本结构表示的基本操作了。将以上这些图组合起来就可以得到最终的总流程图了,根据这个细化了的流程图已经可以用任何高级语言编写程序了。

有时间再把整个流程图组合在一起,然后把对应的程序也写一下,慢慢来吧,要走的路还长呢!   

MFC透明控件的超级简单实现

发表于 2008-05-14 | 分类于 VC

今天在翻出以前写的一个程序时,想改下对话框的背景,结果导致Static控件的背景留下灰色的默认背景色,感觉很不爽,想着也学了这么久MFC了,这个问题今天一定要解决了,大致思路还是知道的,但是由于一直都是在学习,看别人的代码所以真真要自己写还是得仔细琢磨下,经过几番测试发现下面的方法最容易,贴上代码和截图吧:

// CQTTransparentStatic

class CQTTransparentStatic : public CStatic
{
DECLARE_DYNAMIC(CQTTransparentStatic)
public:
CQTTransparentStatic();
virtual ~CQTTransparentStatic();
//响应父类的反射消息
afx_msg HBRUSH CtlColor(CDC /pDC/, UINT /nCtlColor*/);
protected:
DECLARE_MESSAGE_MAP()
};

IMPLEMENT_DYNAMIC(CQTTransparentStatic, CStatic)

CQTTransparentStatic::CQTTransparentStatic()
{

}

CQTTransparentStatic::~CQTTransparentStatic()
{
}

BEGIN_MESSAGE_MAP(CQTTransparentStatic, CStatic)
ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP()

// CQTTransparentStatic 消息处理程序

HBRUSH CQTTransparentStatic::CtlColor(CDC* pDC, UINT nCtlColor)
{
// TODO: 在此更改 DC 的任何属性
// TODO: 如果不应调用父级的处理程序,则返回非空画笔
pDC->SetBkMode(TRANSPARENT);
return (HBRUSH)::GetStockObject(HOLLOW_BRUSH);
}

代码真的是很简单吧,哈哈,

怎么样效果也还不错呢。

消息路由

发表于 2008-05-12 | 分类于 VC

在MSDN上看到的,对理解消息队列很有用。

消息有两种:队列消息和非队列消息。

队列消息的传递方式:系统维护了一个单独的系统消息队列,并为每一个GUI线程维护一个消息队列,当队列消息,比如鼠标,键盘事件引发的消息,将先被放到系统消息队列中,然后按照队列的操作规则,系统一次移除一个消息,并检查该消息,然后发送到产生该目标窗口的线程消息队列中,线程从自己的消息队列中移除消息然后让系统将其发送到窗口过程。

非队列消息:不经过系统消息队列和线程消息队列的迂回,直接发送到目标窗口过程。

在队列消息中WM_PAINT message, the WM_TIMER message, and the WM_QUIT message三种消息是被放在消息队列的队尾的,以确保其他消息的FIFO特性。线程通过GetMessage 从线程消息队列中移除消息, 通过<?XML:NAMESPACE PREFIX = MSHELP /><MSHELP:LINK tabIndex=0 keywords=”_win32_DispatchMessage_cpp”>DispatchMessage</MSHELP:LINK> 驱使系统将消息发送到相应的窗口过程。

Message RoutingThe thread removes messages from its queue and directs the system to send them to the appropriate window procedure for processing.

The system uses two methods to route messages to a window procedure: posting messages to a first-in, first-out queue called a message queue, a system-defined memory object that temporarily stores messages, and sending messages directly to a window procedure.

Messages posted to a message queue are called queued messages. They are primarily the result of user input entered through the mouse or keyboard, such as <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_MOUSEMOVE_cpp”>WM_MOUSEMOVE</MSHELP:LINK>, <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_LBUTTONDOWN_cpp”>WM_LBUTTONDOWN</MSHELP:LINK>, <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_KEYDOWN_cpp”>WM_KEYDOWN</MSHELP:LINK>, and <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_CHAR_cpp”>WM_CHAR</MSHELP:LINK> messages. Other queued messages include the timer, paint, and quit messages: <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_TIMER_cpp”>WM_TIMER</MSHELP:LINK>, WM_PAINT, and <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_QUIT_cpp”>WM_QUIT</MSHELP:LINK>. Most other messages, which are sent directly to a window procedure, are called nonqueued messages.

Queued Messages

The system can display any number of windows at a time. To route mouse and keyboard input to the appropriate window, the system uses message queues.

The system maintains a single system message queue and one thread-specific message queue for each graphical user interface (GUI) thread. To avoid the overhead of creating a message queue for non–GUI threads, all threads are created initially without a message queue. The system creates a thread-specific message queue only when the thread makes its first call to one of the User or Windows Graphics Device Interface (GDI) functions.

Whenever the user moves the mouse, clicks the mouse buttons, or types on the keyboard, the device driver for the mouse or keyboard converts the input into messages and places them in the system message queue. The system removes the messages, one at a time, from the system message queue, examines them to determine the destination window, and then posts them to the message queue of the thread that created the destination window. A thread’s message queue receives all mouse and keyboard messages for the windows created by the thread. The thread removes messages from its queue and directs the system to send them to the appropriate window procedure for processing.

With the exception of the WM_PAINT message, the WM_TIMER message, and the WM_QUIT message, the system always posts messages at the end of a message queue. This ensures that a window receives its input messages in the proper first in, first out (FIFO) sequence. The WM_PAINT message, the WM_TIMER message, and the WM_QUIT message, however, are kept in the queue and are forwarded to the window procedure only when the queue contains no other messages. In addition, multiple WM_PAINT messages for the same window are combined into a single WM_PAINT message, consolidating all invalid parts of the client area into a single area. Combining WM_PAINT messages reduces the number of times a window must redraw the contents of its client area.

The system posts a message to a thread’s message queue by filling an <MSHELP:LINK tabIndex=0 keywords=”_win32_MSG_str_cpp”>MSG</MSHELP:LINK> structure and then copying it to the message queue. Information in MSG includes: the handle of the window for which the message is intended, the message identifier, the two message parameters, the time the message was posted, and the mouse cursor position. A thread can post a message to its own message queue or to the queue of another thread by using the <MSHELP:LINK tabIndex=0 keywords=”_win32_PostMessage_cpp”>PostMessage</MSHELP:LINK> or <MSHELP:LINK tabIndex=0 keywords=”_win32_PostThreadMessage_cpp”>PostThreadMessage</MSHELP:LINK> function.

An application can remove a message from its queue by using the <MSHELP:LINK tabIndex=0 keywords=”_win32_GetMessage_cpp”>GetMessage</MSHELP:LINK> function. To examine a message without removing it from its queue, an application can use the <MSHELP:LINK tabIndex=0 keywords=”_win32_PeekMessage_cpp”>PeekMessage</MSHELP:LINK> function. This function fills MSG with information about the message.

After removing a message from its queue, an application can use the <MSHELP:LINK tabIndex=0 keywords=”_win32_DispatchMessage_cpp”>DispatchMessage</MSHELP:LINK> function to direct the system to send the message to a window procedure for processing. DispatchMessage takes a pointer to MSG that was filled by a previous call to the GetMessage or PeekMessage function. DispatchMessage passes the window handle, the message identifier, and the two message parameters to the window procedure, but it does not pass the time the message was posted or mouse cursor position. An application can retrieve this information by calling the <MSHELP:LINK tabIndex=0 keywords=”_win32_GetMessageTime_cpp”>GetMessageTime</MSHELP:LINK> and <MSHELP:LINK tabIndex=0 keywords=”_win32_GetMessagePos_cpp”>GetMessagePos</MSHELP:LINK> functions while processing a message.

A thread can use the <MSHELP:LINK tabIndex=0 keywords=”_win32_WaitMessage_cpp”>WaitMessage</MSHELP:LINK> function to yield control to other threads when it has no messages in its message queue. The function suspends the thread and does not return until a new message is placed in the thread’s message queue.

You can call the <MSHELP:LINK tabIndex=0 keywords=”_win32_SetMessageExtraInfo_cpp”>SetMessageExtraInfo</MSHELP:LINK> function to associate a value with the current thread’s message queue. Then call the <MSHELP:LINK tabIndex=0 keywords=”_win32_GetMessageExtraInfo_cpp”>GetMessageExtraInfo</MSHELP:LINK> function to get the value associated with the last message retrieved by the GetMessage or PeekMessage function.

Nonqueued Messages

Nonqueued messages are sent immediately to the destination window procedure, bypassing the system message queue and thread message queue. The system typically sends nonqueued messages to notify a window of events that affect it. For example, when the user activates a new application window, the system sends the window a series of messages, including <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_ACTIVATE_cpp”>WM_ACTIVATE</MSHELP:LINK>, <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_SETFOCUS_cpp”>WM_SETFOCUS</MSHELP:LINK>, and <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_SETCURSOR_cpp”>WM_SETCURSOR</MSHELP:LINK>. These messages notify the window that it has been activated, that keyboard input is being directed to the window, and that the mouse cursor has been moved within the borders of the window. Nonqueued messages can also result when an application calls certain system functions. For example, the system sends the <MSHELP:LINK tabIndex=0 keywords=”_win32_WM_WINDOWPOSCHANGED_cpp”>WM_WINDOWPOSCHANGED</MSHELP:LINK> message after an application uses the <MSHELP:LINK tabIndex=0 keywords=”_win32_SetWindowPos_cpp”>SetWindowPos</MSHELP:LINK> function to move a window.

Some functions that send nonqueued messages are <MSHELP:LINK tabIndex=0 keywords=”_win32_BroadcastSystemMessage_cpp”>BroadcastSystemMessage</MSHELP:LINK>, <MSHELP:LINK tabIndex=0 keywords=”_win32_BroadcastSystemMessageEx_cpp”>BroadcastSystemMessageEx</MSHELP:LINK>, <MSHELP:LINK tabIndex=0 keywords=”_win32_SendMessage_cpp”>SendMessage</MSHELP:LINK>, <MSHELP:LINK tabIndex=0 keywords=”_win32_SendMessageTimeout_cpp”>SendMessageTimeout</MSHELP:LINK>, and <MSHELP:LINK tabIndex=0 keywords=”_win32_SendNotifyMessage_cpp”>SendNotifyMessage</MSHELP:LINK>.

内存设备环境

发表于 2008-05-07 | 分类于 VC
通过使用一个特别为位图操作的设备环境,可以使得应用程序将输出操作在内存中而不是将其发送到实际的设备中。内存设备环境使得系统将一部分内存当作虚拟设备。它就是一个在内存中的位数组,使得应用程序可以使用它为在一个标准的绘图表面创建位图临时存储颜色数据。由于位图是和设备兼容的,因此内存设备环境在某些时候也就当作兼容设备环境。 内存设备环境作为一个特殊的环境存储位图图像。应用程序可以调用 CreateCompatibleDC 创建一个内存设备环境。 内存设备环境中初始的位图只是一个简单的占位符。它的尺寸为1*1像素。在应用程序进行绘制之前,必须通过调用 SelectObject 选择一个恰当宽度和高度的位图到该内存环境中。要创建一个恰当尺寸的位图,可以使用 CreateBitmap , CreateBitmapIndirect , or CreateCompatibleBitmap 三个函数。当位图被选进内存设备环境后,系统用一个足够大的数组取代单位数组来存储指定的矩形像素的颜色信息。 当应用程序传递一个由 CreateCompatibleDC 返回的句柄到绘制函数时,被要求的输出并不会在设备的绘制表面显示。相反,系统会存储线段,曲线,文字或者区域的颜色信息到位数组中。应用程序可以复制存储在内存中的图像到绘制表面通过调用 BitBlt 函数,并将内存设备环境作为源设备环境,窗口或者屏幕设备环境作为目标设备环境。

模板代替虚函数实现多态

发表于 2008-04-24 | 分类于 C++
<TABLE style="TABLE-LAYOUT: fixed">

虚函数和继承的实现:

class File {
   public:
      virtual void Open() = 0;
      virtual void Save() = 0;
      virtual void SaveAS(String&) = 0;
      virtual void Close() = 0;
};
class TextFile:public File{
   public:
      void Open();
      void Save();
      void SaveAS(String&);
      void Close();
};
class ImageFile:public File{
   public:
      void Open();
      void Save();
      void SaveAS(String&);
      void Close();
};

// user menu selection to open the file
void menu_open_file(File f_ptr){
   f_ptr->Open();
   ….
   …
}
By using the above code, you would have the following:
File
file_ptr = new TextFile();
menu_open_file(file_ptr);//open the text file
.
.
file_ptr = new ImageFile();
menu_open_file(file_ptr);//open the image file

模板的实现:

class TextFile{
public:
   void Open();
};

class ImageFile{
public:
void Open();
};

//user menu selection to open the file

template<typename T> void menu_open_file(T file){
   file.Open();
}
Using the code:
TextFile txt_file;
ImageFile img_file;
menu_open_file(txt_file);    //open the text file
menu_open_file(img_file);    //open the image file


STL介绍

发表于 2008-04-13 | 分类于 C++

翻译的一篇SGI STL文档还要好多不太会翻译,以后在慢慢领悟吧!

Introduction to the Standard Template Library

标准模板库简介

The Standard Template Library, or STL, is a C++ library of container classes, algorithms, and iterators; it provides many of the basic algorithms and data structures of computer science. The STL is a generic library, meaning that its components are heavily parameterized: almost every component in the STL is a template. You should make sure that you understand how templates work in C++ before you use the STL. 标准模板库,或STL,是一个包括容器类,算法和迭代器的C++库;它提供了许多计算机的基本算法和数据结构。STL是一个泛型库,这意味这它是由很深的参数机制实现的:几乎每一个STL的组件都是模板。你在使用STL之前应该确信你已经懂得了C++的模板。

Containers and algorithms

容器和算法

Like many class libraries, the STL includes container classes: classes whose purpose is to contain other objects. The STL includes the classes vector, list, deque, set, multiset, map, multimap, hash_set, hash_multiset, hash_map, and hash_multimap. Each of these classes is a template, and can be instantiated to contain any type of object. You can, for example, use a vector<int> in much the same way as you would use an ordinary C array, except that vector eliminates the chore of managing dynamic memory allocation by hand. 像许多类库,STL包括容器类:用于包含其他类对象的类。STL包括的容器类有vector, list, deque, set, multiset, map, multimap, hash_set, hash_multiset, hash_map,和hash_multimap。每一个容器类都是模板,而且可以被实例化去包含任何类型的对象。例如你可以使用vector<int>像使用一个原生的C数组,出此之外vector还消除了一些手动动态内存管理的琐碎事情。
       vector<int> v(3);             // Declare a vector of 3 elements.
       v[0] = 7;
       v[1] = v[0] + 3;
       v[2] = v[0] + v[1];           // v[0] == 7, v[1] == 10, v[2] == 17  
       vector<int> v(3);             // 声明一个包含三个元素的vector.
       v[0] = 7;
       v[1] = v[0] + 3;
       v[2] = v[0] + v[1];           // v[0] == 7, v[1] == 10, v[2] == 17  
 


The STL also includes a large collection of algorithms that manipulate the data stored in containers. You can reverse the order of elements in a vector, for example, by using the reverse algorithm.

STL也包括一个很大的算法集合用于处理存储在容器的数据。例如你可以通过使用reverse算法倒序保存在vector中的元素。
       reverse(v.begin(), v.end()); // v[0] == 17, v[1] == 10, v[2] == 7


There are two important points to notice about this call to reverse. First, it is a global function, not a member function. Second, it takes two arguments rather than one: it operates on a range of elements, rather than on a container. In this particular case the range happens to be the entire container v.

在使用reverse时有两个重要点值得注意,第一点是它是一个全局函数,而不是一个成员函数;第二点是它包括两个参数而不是一个参数,容器元素的边界而不是容器。在我们这个例子中,边界即为整个容器。 The reason for both of these facts is the same: reverse, like other STL algorithms, is decoupled from the STL container classes. This means that reverse can be used not only to reverse elements in vectors, but also to reverse elements in lists, and even elements in C arrays. The following program is also valid. 这两点其实是一样的:reverse,像其他的STL算法,是与STL容器类,这意味这reverse不仅可以用于倒序vectors中的元素,还可以用于lists,甚至用于C数组。下面的程序是合法的。
       double A[6] = { 1.2, 1.3, 1.4, 1.5, 1.6, 1.7 };
       reverse(A, A + 6);
       for (int i = 0; i < 6; ++i)
         cout << “A[“ << i << “] = “ << A[i];


This example uses a range, just like the example of reversing a vector: the first argument to reverse is a pointer to the beginning of the range, and the second argument points one element past the end of the range. This range is denoted [A, A + 6); the asymmetrical notation is a reminder that the two endpoints are different, that the first is the beginning of the range and the second is one past the end of the range.

这个例子中使用的区间,就像在倒序vector中使用的:第一个参数是指向倒序的区间的开始,第二个参数是指向超过区间的第一个元素。这个区间表示的是[A,A+6],非对称的符号提示两点区间端点是不同的,第一个端点是区间的起始点,第二个是超过区间的第一个点。

Iterators

迭代器

In the example of reversing a C array, the arguments to reverse are clearly of type double*. What are the arguments to reverse if you are reversing a vector, though, or a list? That is, what exactly does reverse declare its arguments to be, and what exactly do v.begin() and v.end() return? 在倒序C数组的例子中,传递给reverse的参数比较清晰就是double*。那么当你倒序一个vector或者list时传递给reverse的参数是什么呢?也就是,reverse声明的参数类型到底是什么,v.begin()和v.end()返回的是什么呢? The answer is that the arguments to reverse are iterators, which are a generalization of pointers. Pointers themselves are iterators, which is why it is possible to reverse the elements of a C array. Similarly, vector declares the nested types iterator and const_iterator. In the example above, the type returned by v.begin() and v.end() is vector<int>::iterator. There are also some iterators, such as istream_iterator and ostream_iterator, that aren’t associated with containers at all. 答案是传递给reverse的参数是迭代器,一个泛型指针。指向它们自己的是迭代器,为什么可以倒序C数组中的元素呢。类似地,vector声明了内嵌类型的iterator and const_iterator。在上面的例子中,v.begin()和v.end()返回的类型是vector<int>::iterator。还有一些其他的迭代器,比如istream_iterator和ostream_iterator,它们并没有和容器相关联。 Iterators are the mechanism that makes it possible to decouple algorithms from containers: algorithms are templates, and are parameterized by the type of iterator, so they are not restricted to a single type of container. Consider, for example, how to write an algorithm that performs linear search through a range. This is the STL’s find algorithm. 迭代器是一种使得算法与容器分离的机制:算法是模板,被迭代器的类型参数化,所以他们没有限制非要在一个单独类型的容器上。考虑这样一个例子,怎么写一个算法实现在一个区间上线性查找。STL的find即是这样的算法:       template <class InputIterator, class T>
       InputIterator find(InputIterator first, InputIterator last, const T& value) {
           while (first != last && first != value) ++first;
           return first;
       }
find要求三个参数:两个迭代器定义了一个区间,一个value用于在区间中查找。它在区间[first,last)中检查每一个迭代器,从开始到结束,在找到一个指向value的迭代器或者到达区间尾时停止。


Find takes three arguments: two iterators that define a range, and a value to search for in that range. It examines each iterator in the range [first, last), proceeding from the beginning to the end, and stops either when it finds an iterator that points to value or when it reaches the end of the range.

First and last are declared to be of type InputIterator, and InputIterator is a template parameter. That is, there isn’t actually any type called InputIterator: when you call find, the compiler substitutes the actual type of the arguments for the formal type parameters InputIterator and T. If the first two arguments to find are of type int and the third is of type int, then it is as if you had called the following function.

First和last被声明为InputIterator类型,是一个模板参数类型。实际上并没有叫做InputItearot的类型:当你调用find时,编译器会用实参类型替换型参InputIteartor和T。假如传递给find的前面两个参数是int,第三个参数是int的话,实际上你调用的函数是下面这样的:
       int find(int first, int last, const int& value) {
           while (first != last && *first != value) ++first;
           return first;
       }


## Concepts and Modeling

概念和模型

One very important question to ask about any template function, not just about STL algorithms, is what the set of types is that may correctly be substituted for the formal template parameters. Clearly, for example, int or double may be substituted for find‘s formal template parameter InputIterator. Equally clearly, int or double may not: find uses the expression *first, and the dereference operator makes no sense for an object of type int or of type double. The basic answer, then, is that find implicitly defines a set of requirements on types, and that it may be instantiated with any type that satisfies those requirements. Whatever type is substituted for InputIterator must provide certain operations: it must be possible to compare two objects of that type for equality, it must be possible to increment an object of that type, it must be possible to dereference an object of that type to obtain the object that it points to, and so on. 一个关于模板函数的非常重要的问题,不仅仅是STL算法,是正确的替换形式模板参。明显地,例如,int和double也许会替换find的形式模板参数Input- Iterato。同样地,int或者double也许不会:find使用表达式*first,解引用运算符对一个int或者double类型没有任何意义。一个简单的答案是,find也许显示定义了一个需求类型集合,它会这些参数能满足需求的时候被实例化(也就是不满足要求的会报错了)。能够替换InputIterator的参数必须提供能够以下操作:它必须可以比较两个类型是否相等,它必须可以自增,而且还可以解引用获得它指向的元素,等等。 Find isn’t the only STL algorithm that has such a set of requirements; the arguments to for_each and count, and other algorithms, must satisfy the same requirements. These requirements are sufficiently important that we give them a name: we call such a set of type requirements a concept, and we call this particular concept Input Iterator. We say that a type conforms to a concept, or that it is a model of a concept, if it satisfies all of those requirements. We say that int is a model of Input Iterator because int provides all of the operations that are specified by the Input Iterator requirements. STL算法中并不是只要Find有这样的一个需求集合,for_each和count的参数,还要其他的算法同样需要满足同样的要求。这些需求是足够重要的,我们给他们起个名字:我们称这样的类型需求集合为概念,这样一个特殊的概念叫做输入迭代器。我们称满足这样要求的概念为一个模型。Int是一个Input Iterator因为int提供了所有Input Iterator要求的的操作。 Concepts are not a part of the C++ language; there is no way to declare a concept in a program, or to declare that a particular type is a model of a concept. Nevertheless, concepts are an extremely important part of the STL. Using concepts makes it possible to write programs that cleanly separate interface from implementation: the author of find only has to consider the interface specified by the concept Input Iterator, rather than the implementation of every possible type that conforms to that concept. Similarly, if you want to use find, you need only to ensure that the arguments you pass to it are models of Input Iterator. This is the reason why find and reverse can be used with lists, vectors, C arrays, and many other types: programming in terms of concepts, rather than in terms of specific types, makes it possible to reuse software components and to combine components together.

Refinement

精巧

Input Iterator is, in fact, a rather weak concept: that is, it imposes very few requirements. An Input Iterator must support a subset of pointer arithmetic (it must be possible to increment an Input Iterator using prefix and postfix operator++), but need not support all operations of pointer arithmetic. This is sufficient for find, but some other algorithms require that their arguments satisfy additional requirements. Reverse, for example, must be able to decrement its arguments as well as increment them; it uses the expression –last. In terms of concepts, we say that reverse‘s arguments must be models of Bidirectional Iterator rather than Input Iterator. Input Iterator事实上是一个非常弱的概念:它强加了很少的要求。一个Input Iterator必须提供一个指针算术的子集(它必须可以去通过前缀或者后缀的++递增一个Input Iterator),但是不需要提供所以的指针运算。这些对于find来说已经足够了,但是其他的一些算法需要一些额外的要求。例如Reverse必须可以通过–实现递减。按照概念的说法,我们说Reverse的参数为Bidirectional Iterator模型而非Input Iterator。 The Bidirectional Iterator concept is very similar to the Input Iterator concept: it simply imposes some additional requirements. The types that are models of Bidirectional Iterator are a subset of the types that are models of Input Iterator: every type that is a model of Bidirectional Iterator is also a model of Input Iterator. Int*, for example, is both a model of Bidirectional Iterator and a model of Input Iterator, but istream_iterator, is only a model of Input Iterator: it does not conform to the more stringent Bidirectional Iterator requirements. Bidirectional Iterator的概念和Input Iterator非常相似: 它仅仅加了一些额外的要求。Bidirectional Iterator的模型也是一个Input Iterator的子集: 任何Bidirectional Iterator 的模型同时也是一个Input Iterator 的模型。 例如, Int*,既是 Bidirectional Iterator 的模型也是一个Input Iterator 的模型, 但是istream_iterator仅仅是一个的模型Input Iterator: 它并没有符合Bidirectional Iterator更严格的要求。 We describe the relationship between Input Iterator and Bidirectional Iterator by saying that Bidirectional Iterator is a refinement of Input Iterator. Refinement of concepts is very much like inheritance of C++ classes; the main reason we use a different word, instead of just calling it “inheritance”, is to emphasize that refinement applies to concepts rather than to actual types. 我们描述Input Iterator和Bidirectional Iterator的关系时说Bidirectional Iterator是一个更精巧的InputIterator。精巧概念非常像C++类的派生,我们用一个不同的词的主要原因是强调精巧是应用与概念而不是实际的类型。 There are actually three more iterator concepts in addition to the two that we have already discussed: the five iterator concepts are Output Iterator, Input Iterator, Forward Iterator, Bidirectional Iterator, and Random Access Iterator; Forward Iterator is a refinement of Input Iterator, Bidirectional Iterator is a refinement of Forward Iterator, and Random Access Iterator is a refinement of Bidirectional Iterator. (Output Iterator is related to the other four concepts, but it is not part of the hierarchy of refinement: it is not a refinement of any of the other iterator concepts, and none of the other iterator concepts are refinements of it.) The Iterator Overview has more information about iterators in general. 除了我们已经讨论的两个外实际上还要更多的迭代器类型:五种迭代器类型分别为Output Iterator, Input Iterator, Forward Iterator, Bidirectional Iterator和Random Access Iterator; Forward Iterator 是一个精巧的Input Itearot, Bidirectional Iterator是一个更精巧的 Forward Iterator, Random Access Iterator 是一个更精巧的Bidirectional Iterator. (Output Iterator 和其他四中迭代器相关,但不是派生和精巧关系) Iterator Overview 有更多的关于iterators的一般信息. Container classes, like iterators, are organized into a hierarchy of concepts. All containers are models of the concept Container; more refined concepts, such as Sequence and Associative Container, describe specific types of containers.

容器类,像迭代器一样被组织进一个概念中。所以的容器都是概念Container的模型;更加精巧的概念,比如说Sequence and Associative Container, 描述了更特别的容器。

##

下面这部分暂时不翻译,以后看需要时在看。

Other parts of the STL

If you understand algorithms, iterators, and containers, then you understand almost everything there is to know about the STL. The STL does, however, include several other types of components. First, the STL includes several utilities: very basic concepts and functions that are used in many different parts of the library. The concept Assignable, for example, describes types that have assignment operators and copy constructors; almost all STL classes are models of Assignable, and almost all STL algorithms require their arguments to be models of Assignable. Second, the STL includes some low-level mechanisms for allocating and deallocating memory. Allocators are very specialized, and you can safely ignore them for almost all purposes.

Finally, the STL includes a large collection of function objects, also known as functors. Just as iterators are a generalization of pointers, function objects are a generalization of functions: a function object is anything that you can call using the ordinary function call syntax. There are several different concepts relating to function objects, including Unary Function (a function object that takes a single argument, i.e. one that is called as f(x)) and Binary Function (a function object that takes two arguments, i.e. one that is called as f(x, y)). Function objects are an important part of generic programming because they allow abstraction not only over the types of objects, but also over the operations that are being performed.


循环不变式

发表于 2008-04-13 | 分类于 C++

//invariant:we have written r rows so far.
int r=0;
//setting r to 0 makes the invariant true
while(r!=rows)
{
//we can assume that the invariant is true here
//writting a row of output makes the invariant false
std::cout<<std::endl;
//incrementing i makes the invarian true again
++r;
}

上面这个循环很简单,就是要使循环体执行n次,但是从中我们可以发现一个循环不变式,那就是“we have written r rows so far”,循环不变式要成立只需当1while开始之前循环不变式成立,2当我们执行到循环体尾部时循环不变式成立。当我们将i设为0时,此时我们一次都没有循环显然循环不变式成立,因为我们此时还没有输出一行,当我们输出一行后,此时循环不变式即为假了,但是++r使得循环不变式又为真了,因此我们可以得出此循环不变式是成立的,当最后跳出循环体时,r==rows了,即我们已经输出了rows行了!

PS:从Accelerated C++上面看到一个概念,真的是一本不错的书。

又是指针和数组

发表于 2008-03-02 | 分类于 C++
<TABLE style="TABLE-LAYOUT: fixed">

#include <stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
int i;
int ptr=(int)(&a+1);
printf(“ptr=%p/n”,ptr);
for(i=0;i<5;i++)
   printf(“%p/n”,a+i);
printf(“%d,%d/n”,(a+1),(ptr-1));
}

以下是输出

ptr=0013FF64
0013FF50
0013FF54
0013FF58
0013FF5C
0013FF60
2,5

哎,想了半天才发现是&a+1而不是a+1真是粗心啊!


1…13141516

billowqiu

157 日志
33 分类
10 标签
GitHub E-Mail
© 2020 billowqiu
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.3