C++的中抽象

2016-02-19 17:59 0 1 收藏

每个人都希望每天都是开心的,不要因为一些琐事扰乱了心情还,闲暇的时间怎么打发,关注图老师可以让你学习更多的好东西,下面为大家推荐C++的中抽象,赶紧看过来吧!

【 tulaoshi.com - 编程语言 】


  在C++中,以类、虚函数等为代表的数据抽象功能一直是C++的核心和难点。这里我想结合自己的使用经验,谈谈对C++中抽象的一点浅薄看法!
  我认为C++的抽象应该是指:从我们需要解决的问题出发,在与该问题相关的一组关联对象中提取出主要的或共有的部分――说简单一点,就是用相同的行为来操作不同的对象。
  从提出问题到找出与该问题相关的对象,这是一个互动的、反复的过程。在对相关对象的抽象中,随着熟悉的深入,我们可能会修改最初的目标,而最初目标的修改又可能使一组新的相关对象被加入进来。如:假设现在要设计一个基于广域网的邮件服务器,首先可能需要通过socket对底层协议进行封装,为高层的pop3、smtp协议提供一组标准的接口。开始为了使问题简化我们可能计划只封装TCP/IP协议,不过基于以下两点我们有理由修改最初的需求:
  1、   pop3、smtp需要的底层接口很简单。除了连接,仅需要发送、接收一块数据的功能
  2、   用socket进行网络编程,大多数常见协议间的差别很小,有许多都仅仅只是初始化和连接不同而已我们只需要做很小的努力就可以兼容大多数常用协议(如:ATM、Ipx、红外线协议等)。
  现在决定修改需求,除了TCP/IP协议,还要支持一些其他的的常用协议。通过对最初目标的修改,除了TCP/IP协议对象,又会有一组相关的协议对象被加入进来。我们可以很轻易从这组相关对象中提出共有的部分,将他抽象到另一个公共对象中。当然,根据具体应用环境不同,这可能并不是最佳方案。
  
  C++中常规的抽象是在一组相互间有“血缘”关系的类中展开的。如:
  Class Parent
  {
  virtual ~Parent(){};
  virtual void GetValue(){ .... };
  virtual void Test(){ ... };
  };
  class child1 :  public parent
  {
  virtual ~child1(){};
  virtual void GetValue(){...};
  virtual void Test(){ ... } const;
  };
  class child2 :  public parent
  {
  virtual ~child2(){};
  virtual void GetValue(){...};
  virtual void Test(){ ... } ;
  };
  (顺便说一句,child1::Test() const 不是基类 parent::Test() 的重载。)
  由上可总结出C++中抽象的一些基本特点:
  1、被抽象对象必须直接或间接派生至某个类对象
  2、假如你不用没有类型安全的操作,如:向下转型操作或强制类型转化操作(像COM那样)。那么派生类中需要抽象的动作必须在某个基类中出现。
  3、     基类的析构函数必须是一个虚函数(嗯.... 有点无赖!)
  ................
  上述特点一般而言不会影响我们的抽象,但在一些非凡情况下就很难说了。比如:
  假设为某个项目进行二次开发,到手的资料可能就是一堆dll、一堆头文件和一堆文档。这些dll里输出了很多的类,其中有一大堆都是离散的、毫无关系的类对象。经过一段时间的开发,你可能发现为了分别操作这些对象,程序中布满了switch...case.../if....else....语句。更扰人的是其实这些对象完全可以从某个基类派生,有些操作完全可以定义成virtual function。但在不能修改source code 的情况下(其实就算有源代码这样的修改也不可行)如何对这组对象进行抽象呢?
  还有一些例子,比如:在MFC中,假设我们从Cdialog派生一组对话框类,假如我们在某个派生类中定义了一个自己的virtual function。那么除了重新在Cdialog和派生类之间再派生一个类层次,我们无法从外部以抽象的方式直接调用这个虚函数。但为了一个派生类和一个virtual function就添加一个类层次,这也太.....  
  将以上特例总结一下:C++中进行抽象的一组类之间必须有“血缘”关系。但在实际应用中我们有
  时候有必要对一组离散的、没有关系的类对象(如来自不同的类库或者根本就没有virtual function)进行一些抽象操作――可能因为工作关系,我接触这种情况的机会比较多。传统的C++没有直接提供这方面的支持。在实际应用中我经常使用如下方法:
  #include list
  
  class parent
  {
  public:
  virtual ~parent(){};
  virtual void DoSomething( void ) const = 0;
  };
  
  template typename T
  class child : public parent
  {
  public:
  virtual ~child()
  {
  delete tu;
  }
  child( ):
  {
  tu = new T;
  }
  void DoSomething( void ) const
  {
  tu-InitObj();
  }
  private:
  T *tu;
  };
  
  class test
  {
  public:
  void InitObj( void )
  {
  ::MessageBox( NULL, "Test", "test...ok!", MB_OK );
  }
  };
  
  int main()
  {
  using namespace std;
  
  list parent* plist;
  parent *par = new childtest();
  plist.push_back( par );
  
  ..................
  }
  以上方法用模板的方式来产生对象的代理。优点是完全未损失C++类型安全检查的特性,class object的一般普通成员函数就可以进行抽象调用了。缺点是调用的函数名被事先确定了――但这往往是不能接受的。为了改进这一点我在后来的使用中引入了member function pointer。代码如下:
  #includelist
  
  class parent
  {
  public:
  virtual ~parent(){};
  
  virtual void do1( void ) const = 0;
  virtual int do2( char* ) const = 0;
  };
  
  template typename T
  class child : public parent
  {
  typedef void (T::*PFUN1)( void );
  typedef int (T::*PFUN2)( char* );
  public:
  virtual ~child()
  {
  delete tu;
  }
  
  //////////////////////////////////////
  child( PFUN1 p1 ):
  fun1(p1), fun2(NULL)
  {
  tu = new T;
  }
  //------------------------------------
  child( PFUN2 p2 ):
  fun1(NULL), fun2(p2)
  {
  tu = new T;
  }
  //-------------------------------------
  child( PFUN1 p1, PFUN2 p2 ):
  fun1(p1), fun2(p2)
  {
  tu = new T;
  }
  ////////////////////////////////////////
  
  int do2( char *pch ) const
  {
  return fun2?(tu-*fun2)( pch ) : -1;
  }
  void do1( void ) const
  {
  fun1?(tu-*fun1)() : -1;
  }
  private:
  T *tu;
  PFUN1 fun1;
  PFUN2 fun2;
  };
  
  class test
  {
  public:
  void test1( void )
  {
  ::MessageBox( NULL, "Test", "test...ok!", MB_OK );
  }
  };
  
  
  int main()
  {
  using namespace std;
  list parent* plist;
  parent *par = new childtest( test::test1 );
  plist.push_back( par );
  
  .........................
  }
  在这个例子中我只引用了两种类型的member function pointer:
  typedef void (T::*PFUN1)( void );
     typedef int (T::*PFUN2)( char* );
  按上面的方法很轻易扩展到其他函数类型。ConstrUCt child( PFUN1 p1, PFUN2 p2 )只是为了说明一个class object可以注册多种方法。更好的做法可能是将函数注册功能独立成一个函数。
          总体来说以上方法只能作为一个特例来看。我们总是应该以常规的C++的方式进行抽象。C++中关于抽象的一些限制并不是我们进行抽象的阻碍。我们应该把它们看作“桥上的栏杆”,他们可以保证我们的逻辑思维沿着正确地方向前进!
  欢迎交流:computer_super@263.net
  

来源:https://www.tulaoshi.com/n/20160219/1616537.html

延伸阅读
引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确、灵活地使用引用,可以使程序简洁、高效。 引用简介 引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。 引用的声明方法:类型标识符 &引用名=目标变量名; :int a; int &ra=a; //定义引用ra,它是变量a...
<C++实践系列C++中的引用(reference) 作者:张笑猛 提交者:eastvc 发布日期:2003-11-22 14:44:07 原文出处:http://objects.nease.net/ 1.简介 2.引用的语法 3.引用使用技巧     3.1 引用和多态     3.2 作为参数     3.3 作为返回值     3.4 什么时候使用引用 4....
Java跨平台的特性使Java越来越受开发人员的欢迎,但也往往会听到不少的抱怨:用Java开发的图形用户窗口界面每次在启动的时候都会跳出一个控制台窗口,这个控制台窗口让本来非常棒的界面失色不少。怎么能够让通过Java开发的GUI程序不弹出Java的控制台窗口呢?其实现在很多流行的开发环境例如JBuilder、Eclipse都是使用纯Java开发的集成环境...
简介 对于很多初学者来说,往往觉得回调函数很神秘,很想知道回调函数的工作原理。本文将要解释什么是回调函数、它们有什么好处、为什么要使用它们等等问题,在开始之前,假设你已经熟知了函数指针。 什么是回调函数? 简而言之,回调函数就是一个通过函数指针调用的函数。假如你把函数的指针(地址)作为参数传递给另一个...
1.引言 C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。 !-- frame contents -- !-- /frame contents -- 作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的...

经验教程

304

收藏

75
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部