- 浏览: 369209 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
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 872http://zhenyulu.cnblogs.com/cat ... -
C/C++预处理、编译、链接过程【Z】
2011-01-05 14:07 1802在Linux下进行C语言编程,必然要采用GNU GCC来编 ... -
c语言输出重定向【Z】
2010-10-03 22:41 3030可以使用重定向操作符将命令输入和输出数据流从默认位置重定向到不 ... -
C++标准库【Z】
2010-09-29 22:42 923C++标准库的内容分为10类: C1.语言支持 C2.输入/ ... -
c语言socket编程指南
2010-09-29 20:39 1297介绍 Socket 编程让你沮丧吗?从man page ... -
kmp算法【Z】
2010-09-24 19:02 818我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件), ... -
虚拟继承、虚函数学习总结【Z】
2010-09-24 16:03 1486虚拟继承、虚函数学习总结 ... -
C++对象内存布局测试总结【Z】
2010-09-24 16:02 1134对于普通的C++对象内存布局,简单得不得了,就不做总结了。这里 ... -
C++隐式成员函数2【Z】
2010-09-24 15:37 9711 编译器自动生成的基本函数 C++编译器会在开发人员没有声 ... -
C++隐式成员函数【Z】
2010-09-24 15:27 1302这篇文章讲述的是C++提供的一些由编译器自 ... -
extern详解【Z】
2010-09-24 14:44 8141 基本解释 extern可 ... -
KMP字符串匹配算法【Z】
2010-09-14 22:44 1186最普通的字符串匹配 ... -
C语言变量存储类型
2010-09-14 19:58 1216C语言变量存储类型 auto static extern ... -
C/C++中的void
2010-09-14 19:54 9741.void的含义 (1)voi ... -
排序算法
2010-09-10 11:10 10901、稳定排序和非稳定排序 简单地说就是所有相等的数经过某种排 ... -
C++ Socket连接实现【转载】
2010-08-31 21:27 2951C++ socket程序 下面是一个C++调用windo ... -
虚函数/纯虚函数
2010-08-31 19:17 5481.首先:强调一个概念 定义一个函数 ... -
纯虚函数
2010-08-31 19:07 1043一、定义. 纯虚函数是在基类 中声明的虚函数,它在基类中没 ... -
C++ 对象的内存布局
2010-08-31 16:38 961转载-->C++ 对象的内存布局 ... -
虚继承
2010-08-31 16:06 815虚拟继承在一般的应用 ...
相关推荐
根据给定的信息,我们可以深入探讨C++中的抽象类与继承机制。下面将详细介绍如何通过抽象类和继承在C++中实现特定的功能。 ### 概述 在这个示例中,我们有三个具体的类:`Student`、`Lecture` 和 `Module`,它们都...
C++抽象机制是C++编程语言中用于构建复杂软件系统的核心特性,它允许程序员通过类、运算符重载、派生类、模板和异常处理等工具来创建抽象的数据类型和行为,以更好地模拟现实世界的问题。以下是这些概念的详细解释:...
本书名为《C++抽象编程》,由斯坦福大学的Eric S. Roberts撰写,英文版。该书是一本经典的C++中级教材,书中的内容经历了重大修订,目的是使教材的内容更接近于工业界使用C++的方式,以便更容易地将斯坦福大学教授...
在C++中,抽象工厂模式通过接口和抽象类来实现,可以有效地隔离了客户端与具体产品的耦合。 首先,我们来看一下抽象工厂模式的主要角色: 1. **抽象工厂(Abstract Factory)**:这是模式的核心,定义了一组创建...
在这个"C++抽象工厂模式"项目模板中,我们可以通过QT控制台程序来理解并实践这种模式。 首先,让我们详细探讨一下抽象工厂模式。在软件工程中,当系统需要创建一系列相关或相互依赖的对象时,但又不希望客户端代码...
总的来说,C#接口和C++抽象类虽然在目的上相似,都是为了实现多态性,但在实际使用和语法规则上有着显著的不同。选择使用哪种取决于具体的需求和设计目标,以及你正在使用的编程语言的特性。理解这些差异对于编写...
自己整理的c++抽象工厂模式源码,简单易懂
在C++编程语言中,抽象类是一个非常重要的概念,它为其他类提供了一种模板或者接口,但不能被实例化。抽象类通过包含至少一个纯虚函数来定义,这些函数没有具体的实现,需要由派生类来重写。在本实例中,我们将深入...
### C++中的抽象数据类型(ADT) #### 道格拉斯·C·施密特教授的分享 在由道格拉斯·C·施密特教授(Vanderbilt University教授,电子工程与计算机科学系)分享的一份PPT中,详细介绍了C++支持的抽象数据类型...
在C++编程语言中,抽象类是一种特殊类型的类,它被设计用来作为其他类的基类,用于定义接口,但通常不能直接实例化。抽象类的主要特性是包含至少一个纯虚函数,这使得它们成为创建多态性基础的基石。在本资源中,...
在C++中,抽象工厂通常由以下组件构成: 1. **抽象工厂接口**:定义了一组创建产品对象的抽象方法,这些产品属于同一产品族。例如,我们可以有一个`IFactory`接口,其中包含`CreateProductA()`和`CreateProductB()`...
该资源是博主博客的源代码,博客上有详细讲解Qt/C++关于纯虚函数和抽象基类原理讲解和示例用法解释,博客地址如下: https://blog.csdn.net/naibozhuan3744/article/details/94488200 其中编译环境为QtCreator4.5.0...
下面将详细探讨`Red_Shape`抽象工厂的C++实现及其相关知识点。 首先,我们来理解一下抽象工厂模式的基本结构。抽象工厂通常由以下几个部分组成: 1. **抽象工厂接口(Abstract Factory)**:这是定义一个用于创建...
C++的抽象类还可以包含非虚函数,而Java和C#的抽象方法必须在子类中实现。 在继承树中,接口在Java和C#中扮演重要角色。Java的接口完全是抽象的,不允许有方法实现。C#中的接口也类似,但C#4.0引入了“默认接口实现...
用抽象工厂做的程序,里面用到了简单的抽象类模式,做了一个工厂模式开发的c++版本程序!
我用c++自己编写的用于教学的二叉树的代码。
《数据抽象和问题求解-C++语言描述(第四版)源码》是一本深度探讨C++编程中的数据抽象和问题解决策略的专业书籍。在学习C++编程的过程中,数据抽象是核心概念之一,它涉及到如何设计和实现复杂系统,以及如何通过...
在C++和Java这两种编程语言中,抽象工厂模式的应用相当广泛,特别是在需要跨平台或者需要一组相关的对象协同工作时。 首先,我们来看看C++中的抽象工厂模式。在C++中,我们通常通过定义接口(纯虚函数)来实现抽象...
C++数据抽象和问题求解,给你一种使用C++解决复杂问题的绝佳方法。
在C++中,由于不支持接口,我们通常用抽象类来模拟接口,但需要注意避免在“接口”类中包含数据成员和不必要的构造/析构函数,以保持接口的纯粹性。 总结来说,抽象类和接口都是面向对象设计中的重要工具,它们帮助...