宝杉的博客

UNIX/LINUX;ACE;SNMP;C++
posts - 33, comments - 23, trackbacks - 0, articles - 0

 

 错误

#include   <iostream.h>
#include   <string.h>

……

string   st("test   string");  

……

error   C2065:   'string'   :   undeclared   identifier  

解释

#include   <string>  

using   namespace   std;  

因为在   using   namespace   std;   情况下, 

#include   <string>     是使用   C++     string   类库; 

#include   <cstring>     是使用   C   的string   操作库函数   ...  

细节 加不加“.h”

#include <iostream.h>

#include <string>

using       namespace      std;

没有错!!

#include <iostream.h>

#include <string.h>

using       namespace      std;

编译有错!!

解释

  “string.h“这个头文件是“旧式c头文件”,而这个文件中没有定义string类(这点应该不奇怪,c语言中哪有什么类啊),这个头文件里面是有关“旧式char-based字符串”的操作函数,注意都是操作char*字符串的“函数”,所以你引用这个头文件,编译器肯定找不到“string”了。  
  “string”这个头文件(没有扩展名)是C++标准化之后的C++头文件,里面才有string类的相关定义(其实,string并不是类,是一个typedef,但是使用的时候不用去管他),而C++标准头文件中的东西都放在namespace   std中了,所以使用的时候要“using   namespace   std”。  
  附:建议楼主不要用"iostream.h",改成“iostream”吧,因为标准已经明确规定不在支持"iostream.h"这种头文件了。

标准写法

#include <iostream>

#include <string>

using       namespace      std;

 

F: 为什么using   namespace   std;  
       要写在include后面?

Q: 因为include的文件包含名字域std  
如果你把using   namespace   std写在前面,编译器就看不到std这个名字

posted @ 2007-08-03 13:01 宝杉 阅读(410) | 评论 (0)编辑 收藏

 

引用即别名,数组不能引用。

引用提高效率,又不在函数中改变。参考:file:///F:/fragments/documents/深入探讨C++中的引用%20-%20KiRa的专栏%20-%20CSDNBlog.mht

 

常引用

常引用声明方式:const 类型标识符 &引用名 = 目标变量名;

const类型 和 & 是分不开的,引用一般定义成const。

 

引用作为返回值

要以引用返回函数值,则函数定义时要按以下格式:

类型标识符 &函数名(形参列表及类型说明)
{

函数体

}

说明:

  (1)以引用返回函数值,定义函数时需要在函数名前加&

  (2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。

例子:Diary files\C++exams\rtn_ref

 

引用作为返回值,必须遵守以下规则:

(1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。

(2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。

(3)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

(4)引用与一些操作符的重载:

  流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << "hello" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。

posted @ 2007-08-03 13:00 宝杉 阅读(187) | 评论 (0)编辑 收藏

 

在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)

// 被调用函数是以int为参数,以int为返回值
__stdcall int callee(int);

// 调用函数以函数指针为参数
void caller( __cdecl int(*ptr)(int));

// 在p中企图存储被调用函数地址的非法操作
__cdecl int(*p)(int) = callee; // 出错

指针p和callee()的类型不兼容,因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列。 

posted @ 2007-08-03 12:59 宝杉 阅读(505) | 评论 (0)编辑 收藏

 

声明:

先定义函数,void print(string str);

声明一个函数指针,void ( *p )( string ) = NULL;

指向copy函数,p = & print; 或 p = print;

调用指针函数,p( “hello” );

 

可以把多个函数放在一个指针数组里,然后通过数组对应指针方便调用函数。

例子:Diary files\C++exams\pointer_func

 

动态绑定一个函数

void caller(void(*ptr)())

{

ptr();             /* 调用ptr指向的函数 */

}

void func();

int main()

{

p = func;

caller(p); /* 传递函数地址到调用者 */

}

如果赋了不同的值给p(不同函数地址),那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。

posted @ 2007-08-03 12:58 宝杉 阅读(132) | 评论 (0)编辑 收藏

静态联编:运行之前就完成的联编,系统在编译时就决定如何完成某个动作。
动态联编:程序运行之后才完成的联编,系统在运行时动态实现某一动作。
静态多态性:函数重载;运算符重载;
动态多态性:继承;虚函数;
函数重载
1 参数有差别。
2 参数相同,属不同类。
一个重载的例子:Diary files\C++exams\func_reload
 
名字压延:是编译器根据函数重载的不同类型,在编译时改变函数名字,而达到区分的目的。

posted @ 2007-08-03 12:57 宝杉 阅读(135) | 评论 (0)编辑 收藏

友元函数一般在类中声明,如果一个友元需要访问多个类的对象,那么每个类都要声明一次友元函数。

还要注意:友元函数的入口包括多个类,那这些类都要在友元函数之前声明。

如例子:Diary files\C++exams\frnd_vst2_func

如果是类person的两个继承他的子类boy和girl,那么友元函数如何声明和定义。

Diary files\C++exams\frnd_member

这需要注意的地方有:

基类的数据成员共有;构造函数;构造函数初始化表;类的声明先于友元函数,提高了重用性;

基类的数据成员必须共有,因为构造函数会访问到它们,子类的构造函数也会引用基类的构造函数,如果是私有的会是的子类构造函数不能直接访问基类的私有成员,要通过基类的成员函数来访问。

子类:public基类

 

还有写细节问题:

头文件;char *a的声明和使用;分配char*数据;

例如:

char *name;

name = new char[ strlen( s ) + 1 ];

 

友元函数的声明时的入口参数可以只写类型,不写参数名。

例如:

class boy

{

       ……

       void disp( gril & );

}

注意声明时的入口参数可省略,但要写&。

定义时,写成

void disp( gril &x ){      ……       }

posted @ 2007-08-03 12:55 宝杉 阅读(1006) | 评论 (0)编辑 收藏

 

声明:           类    对象;     类       *指针;

                   int  i;           <class>      *this;

 

this指针是一个隐含指针,是成员函数所属对象的指针。

每个成员函数都有一个this指针,this指针指向该函数所属类的对象。

 

使用格式:this -> 成员变量

 

不同的对象调用同一个成员函数,C++会根据成员函数的this指针指向哪一个对象,来调用该对象的成员变量。

 

this指针如何得到对象名?

例如:一个类class me的初始化函数:

void init(char ma, int mb)

{ a = ma; b = mb; }

编译时,被编译器转化为:

       void init(me *this, char ma, int mb)     //多了一个this指针的参数,指向me类的obj

      { this -> a = ma, this -> b = mb; }

posted @ 2007-08-03 12:53 宝杉 阅读(272) | 评论 (0)编辑 收藏

 

   对于只做输入用的指针参数,最好用const,这样避免指针参数被修改。

   比如:对于上面的StringCopy的例子,写成

   void StringCopy (char *strDestination, const char *strSource);         //比较安全。

   但是如果输入参数以值传递的形式传递对象,则改为使用const &最好,因为省去了临时对象的构造和解析的过程,提高效率和安全性。

 

   int printf(……);这个函数的参数不确定,没有严格的类型检查,所以最好不用。

posted @ 2007-08-03 12:52 宝杉 阅读(345) | 评论 (1)编辑 收藏

 

1 介绍

此文描述了组成ACE框架的Reactor模式的设计和执行。Reactor负责处理由一个或多个client并发的传递给一个应用程序的服务请求。应用程序的每个服务由一个分离的event handler(事件句柄)执行,event handler包括一个或多个进程的服务器特殊请求的方法。

       此文描述的Reactor模式的执行,event handler分发是由ACE_Reactor实现的。ACE_Reactor结合I/O事件的分离器,以及其他类型的时间,比如timers和signals。ACE_Reactor的核心实现是基于同步事件分离,比如select或者WaitForMultipleObjects。当分离器指示指定的事件发生了,ACE_Reactor会自动分发预先注册的事件句柄的方法。注册的event handler方法会完成应用程序对应请求事件的服务。

       本文组织如下:第二章描述ACE_Reactor框架主要特性;第三章大致介绍ACE_Reactor实现的OO(面向对象)设计;第四章举了服务器端实现的例子,用以证明ACE_Reactor怎样简化并发的,基于事件的网络应用程序的发展;第五章描述当使用ACE_Reactor开发基于事件的应用程序的设计规则;第六章是结束语。

2 ACE_Reactor的特性

ACE_Reactor提供OO的事件分离机制和消息分发框架,它简化基于事件的应用程序的开发。以下特性是:

OO的事件分离和消息分发接口:

使用ACE_Reactor的应用程序不直接调用底层OS(操作系统)的事件分离API函数。比如select或WaitForMultipleObjects。他们继承ACE Event Handler基类并创建了具体的event handlers。这个类用特定的虚拟函数处理不同类型的事件,比如I/O事件,timer事件,signals(信号量机制),和同步事件。

应用程序用Reactor框架创建具体的event handler,并注册他们。特性1显示了ACE Reactor.的关键组件。这个特性描述执行日子服务的事件句柄,这个在第四章讲述。

posted @ 2007-08-03 12:42 宝杉 阅读(1576) | 评论 (0)编辑 收藏

      ACE中的流包装提供面向连接的通信。流数据传输包装类包括ACE_SOCK_Stream和ACE_LSOCK_Stream,它们分别包装TCP/IP和UNIX域socket协议数据传输功能。连接建立类包括针对TCP/IP的ACE_SOCK_Connector和ACE_SOCK_Acceptor,以及针对UNIX域socket的ACE_LSOCK_Connector和ACE_LSOCK_Acceptor。
      Acceptor类用于被动地接受连接(使用BSD accept()调用),而Connector类用于主动地建立连接(使用BSD connect()调用)。
      下面的例子演示接收器和连接器是怎样用于建立连接的。该连接随后将用于使用流数据传输类来传输数据。

server端代码:
// 环境VC6.0+ACE5.4.2
// proj:ACE stream server
// date:07-7-24
// robin
//

#include "stdafx.h"

#include "ace/Log_Msg.h"
#include "ace/Time_Value.h"
#include "ace/OS.h"


#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Stream.h"

#define SIZE_DATA 18
#define SIZE_BUF 1024
#define NO_ITERATIONS 5

class Server
{
public:
 Server (int port) : server_addr_(port),peer_acceptor_(server_addr_)
 {
  data_buf_ = new char[SIZE_BUF];
 }

 //Handle the connection once it has been established. Here the
 //connection is handled by reading SIZE_DATA amount of data from the
 //remote and then closing the connection stream down.

 int handle_connection()
 {
  // Read data from client
  for(int i=0;i<NO_ITERATIONS;i++)
  {
   int byte_count=0;
   if( (byte_count = new_stream_.recv_n(data_buf_, SIZE_DATA, 0) ) == -1 )
    ACE_ERROR ((LM_ERROR, "%p\n", "Error in recv"));
   else
   {
    data_buf_[byte_count]=0;
    ACE_DEBUG((LM_DEBUG,"Server received %s \n",data_buf_));
   }
  }

  // Close new endpoint
  if (new_stream_.close () == -1)
   ACE_ERROR ((LM_ERROR, "%p\n", "close"));
  return 0;
 }


 //Use the acceptor component peer_acceptor_ to accept the connection
 //into the underlying stream new_stream_. After the connection has been
 //established call the handle_connection() method.
 
 int accept_connections ()
 {
  if (peer_acceptor_.get_local_addr (server_addr_) == -1)
   ACE_ERROR_RETURN ((LM_ERROR,"%p\n","Error in get_local_addr"),1);
  ACE_DEBUG ((LM_DEBUG,"Starting server at port %d\n",
   server_addr_.get_port_number ()));
  
  // Performs the iterative server activities.

  while(1)
  {
   ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
   if (peer_acceptor_.accept(new_stream_, &client_addr_, &timeout)== -1)
   {
    ACE_ERROR ((LM_ERROR, "%p\n", "accept"));
    continue;
   }
   else
   {
    ACE_DEBUG((LM_DEBUG,
     "Connection established with remote %s:%d\n",
     client_addr_.get_host_name(),client_addr_.get_port_number()));

    //Handle the connection
    handle_connection();
   }
  }
 }

private:
 char *data_buf_;
 ACE_INET_Addr server_addr_;
 ACE_INET_Addr client_addr_;
 ACE_SOCK_Acceptor peer_acceptor_;
 ACE_SOCK_Stream new_stream_;
};


int main (int argc, char *argv[])
{
 if(argc<2)
 {
  ACE_ERROR((LM_ERROR,"Usage %s <port_num>", argv[0]));
  ACE_OS::exit(1);
 }

// char *ip;
// ip = new char[strlen("192.168.1.160")];
// Server server(ACE_OS::atoi(ip));  //argv[1])

 Server server(ACE_OS::atoi(argv[1]));
 server.accept_connections();
 return 0;
}

client端:
// proj:ACE stream client
// client
// date:7-24
// robin

#include "stdafx.h"

//******additional*******//
#include "ace/Log_Msg.h"  //ACE_ERROR ACE_DEBUG
#include "ace/Time_Value.h"  // ACE_Time_Value
#include "ace/OS.h"    // ACE_OS::atoi exit
//******additional*******//

#include "ace/SOCK_Connector.h"
#include "ace/INET_Addr.h"

#define SIZE_BUF 128
#define NO_ITERATIONS 5


class Client
{
public:
 Client(char *hostname, int port):remote_addr_(port,hostname)
 {
  data_buf_="Hello from Client";
 }

 //Uses a connector component `connector_’ to connect to a
 //remote machine and pass the connection into a stream
 //component client_stream_
 int connect_to_server()
 {
  // Initiate blocking connection with server.
  ACE_DEBUG ((LM_DEBUG, "(%P|%t) Starting connect to %s:%d\n",
   remote_addr_.get_host_name(),remote_addr_.get_port_number()));
  if (connector_.connect (client_stream_, remote_addr_) == -1)
   ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","connection failed"),-1);
  else
   ACE_DEBUG ((LM_DEBUG,"(%P|%t) connected to %s\n",
   remote_addr_.get_host_name ()));
  return 0;
 }


 //Uses a stream component to send data to the remote host.
 int send_to_server()
 {
  // Send data to server
  for(int i=0;i<NO_ITERATIONS; i++)
  {
   if (client_stream_.send_n (data_buf_,
    ACE_OS::strlen(data_buf_)+1, 0) == -1)
   {
    ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","send_n"),0);
    break;
   }
  }
  //Close down the connection
  close();
 }

 //Close down the connection properly.
 int close()
 {
  if (client_stream_.close () == -1)
   ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","close"),-1);
  else
   return 0;
 }
private:
 ACE_SOCK_Stream client_stream_;
 ACE_INET_Addr remote_addr_;
 ACE_SOCK_Connector connector_;
 char *data_buf_;
};


int main(int argc, char* argv[])
{
 if(argc<3)
 {
  ACE_DEBUG((LM_DEBUG,"Usage %s <hostname> <port_number>\n", argv[0]));
  ACE_OS::exit(1);
 }

 Client client(argv[1],ACE_OS::atoi(argv[2]));
 client.connect_to_server();
 client.send_to_server();
 return 0;
}


运行结果:
cmd里到exe目录下,先启动服务端server.exe 192.168.1.160
如图1:

正在轮询等待。

再到client服务端,同样的方法
运行命令行参数格式 client.exe 192.168.1.160 192
 解析:ACE_DEBUG((LM_DEBUG,"Usage %s <hostname> <port_number>\n", argv[0]));
         命令行参数为 <hostname><port> = <192.168.1.160><192>
         端口是由图1的第二行显示,不是自己设定的。
如图2:

只是照搬书上的例子,后面打算自己分析一下。

posted @ 2007-07-25 10:57 宝杉 阅读(1404) | 评论 (2)编辑 收藏

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