- 浏览: 361836 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
tuspark:
关于javadoc这里讲解的更全面:《javadoc设置》。
Eclipse中生成javadoc【Z】 -
yuexiang1007:
帮我解决了问题,谢谢!!!
java.math.BigInteger使用心得总结 -
netwelfare:
个人感觉,文章对HashMap的遍历分析的有点浅,不如这里的介 ...
HashMap遍历的两种方式【Z】 -
memoryisking:
关于java.math.BigInteger讲解在这里可以看到 ...
java.math.BigInteger使用心得总结 -
巴尾的兔兔帅:
divide应该是除吧?不是减。dividepublic Bi ...
java.math.BigInteger使用心得总结
在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
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 );
}
以上方法用模板的方式来产生对象的代理。优点是完全未损失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++中关于抽象的一些限制并不是我们进行抽象的阻碍。我们应该把它们看作“桥上的栏杆”,他们可以保证我们的逻辑思维沿着正确地方向前进!
从提出问题到找出与该问题相关的对象,这是一个互动的、反复的过程。在对相关对象的抽象中,随着认识的深入,我们可能会修改最初的目标,而最初目标的修改又可能使一组新的相关对象被加入进来。如:假设现在要设计一个基于广域网的邮件服务器,首先可能需要通过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
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 );
}
以上方法用模板的方式来产生对象的代理。优点是完全未损失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++中关于抽象的一些限制并不是我们进行抽象的阻碍。我们应该把它们看作“桥上的栏杆”,他们可以保证我们的逻辑思维沿着正确地方向前进!
发表评论
-
C#设计模式[链接]
2011-01-05 14:19 838http://zhenyulu.cnblogs.com/cat ... -
C/C++预处理、编译、链接过程【Z】
2011-01-05 14:07 1762在Linux下进行C语言编程,必然要采用GNU GCC来编 ... -
c语言输出重定向【Z】
2010-10-03 22:41 2999可以使用重定向操作符将命令输入和输出数据流从默认位置重定向到不 ... -
C++标准库【Z】
2010-09-29 22:42 885C++标准库的内容分为10类: C1.语言支持 C2.输入/ ... -
c语言socket编程指南
2010-09-29 20:39 1265介绍 Socket 编程让你沮丧吗?从man page ... -
kmp算法【Z】
2010-09-24 19:02 782我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件), ... -
虚拟继承、虚函数学习总结【Z】
2010-09-24 16:03 1448虚拟继承、虚函数学习总结 ... -
C++对象内存布局测试总结【Z】
2010-09-24 16:02 1101对于普通的C++对象内存布局,简单得不得了,就不做总结了。这里 ... -
C++隐式成员函数2【Z】
2010-09-24 15:37 9341 编译器自动生成的基本函数 C++编译器会在开发人员没有声 ... -
C++隐式成员函数【Z】
2010-09-24 15:27 1260这篇文章讲述的是C++提供的一些由编译器自 ... -
extern详解【Z】
2010-09-24 14:44 7771 基本解释 extern可 ... -
KMP字符串匹配算法【Z】
2010-09-14 22:44 1148最普通的字符串匹配 ... -
C语言变量存储类型
2010-09-14 19:58 1178C语言变量存储类型 auto static extern ... -
C/C++中的void
2010-09-14 19:54 9451.void的含义 (1)voi ... -
排序算法
2010-09-10 11:10 10481、稳定排序和非稳定排序 简单地说就是所有相等的数经过某种排 ... -
C++ Socket连接实现【转载】
2010-08-31 21:27 2918C++ socket程序 下面是一个C++调用windo ... -
虚函数/纯虚函数
2010-08-31 19:17 5261.首先:强调一个概念 定义一个函数 ... -
纯虚函数
2010-08-31 19:07 1008一、定义. 纯虚函数是在基类 中声明的虚函数,它在基类中没 ... -
C++ 对象的内存布局
2010-08-31 16:38 921转载-->C++ 对象的内存布局 ... -
虚继承
2010-08-31 16:06 783虚拟继承在一般的应用 ...
相关推荐
一个student类,lectureTeatre类,继承抽象module类,通过继承来实现接口
C++抽象机制 重要概念简明讲解 1、类 2、运算符重载 3、派生类 4、模板 5、异常处理 6、类的层次结构
经典C++中级教材:C++抽象编程。英文高清版。带详细书签。欢迎下载
c++实现工厂模式,抽象工厂,c++实现工厂模式,抽象工厂
C++抽象类 实用例子 自己写的代码 决对运行成功
描述C++抽象类的使用以及虚函数、纯虚函数的用法
自己整理的c++抽象工厂模式源码,简单易懂
C++抽象工厂模式项目模板,基于QT控制台程序。关注我即可下载,无需积分,后续将带来更多关于QT的小项目和技术分享。
来源于cppcon里大牛关于cpp抽象数据结构的分享的ppt,较为完善.
C#程序设计-3期(KC008) KC008110100020-C#接口和C++抽象类一样吗?.docx 学习资料 复习资料 教学资源
运用C++,MFC中的宏实现的抽象工厂设计模式,有兴趣的朋友可以参考一下
该资源是博主博客的源代码,博客上有详细讲解Qt/C++关于纯虚函数和抽象基类原理讲解和示例用法解释,博客地址如下: https://blog.csdn.net/naibozhuan3744/article/details/94488200 其中编译环境为QtCreator4.5.0...
用抽象工厂做的程序,里面用到了简单的抽象类模式,做了一个工厂模式开发的c++版本程序!
抽象工厂Red_Shape的C++实现,设计模式中的抽象工厂模式
1. 请创建一个抽象类DataStructure,该类包括下面的成员变量和成员函数: 1) 一个成员变量len,表示里面的元素个数最大值 2) 构造函数DataStructure(int l),将len初始化为0 3) 虚析构函数~DataStructure() 4) ...
我用c++自己编写的用于教学的二叉树的代码。
用少而精的例子展示如何有效地组合C++抽象机制。 .提供了大量面向对象设计转换成C++实现的准则。 .展示了如何用模板支持可重用性。 .描述了重要的大型系统开发问题,包括库结构的设计、异常处理和分布式处理。 . ...
C++数据抽象和问题求解 第6版PDF 压缩第一部分 请下载其它六个部分到同一个目录并解压第一个文件
Java,C#,C++在继承,覆盖和多态,抽象类等几个方面的比较归纳..........................
c++ java 抽象工厂模式