当前位置:天才代写 > tutorial > C语言/C++ 教程 > C++的中抽象

C++的中抽象

2017-11-05 08:00 星期日 所属: C语言/C++ 教程 浏览:319

副标题#e#

在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、基类的析构函数必需是一个虚函数(嗯…. 有点恶棍!)

…………….


#p#副标题#e#

上述特点一般而言不会影响我们的抽象,但在一些非凡环境下就很难说了。好比:

假设为某个项目举办二次开拓,得手的资料大概就是一堆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 child<test>();
plist.push_back( par );
..................
}

#p#副标题#e#

#p#分页标题#e#

以上要领用模板的方法来发生工具的署理。利益是完全未损失C++范例安详查抄的特性,class object的一般普通成员函数就可以举办抽象挪用了。缺点是挪用的函数名被事先确定了――但这往往是不能接管的。为了改造这一点我在厥后的利用中引入了member function pointer。代码如下:

#include<list>
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 child<test>( 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++中关于抽象的一些限制并不是我们举办抽象的阻碍。我们应该把它们看作“桥上的雕栏”,他们可以担保我们的逻辑思维沿着正确处所向前进!

接待交换:[email protected]

 

    关键字:

天才代写-代写联系方式