被误解的C++——高端开发

longshanks 2007-06-12 03:06:31
诸位留神,我要捅马蜂窝了。
呵呵,玩笑。之所以这么说,因为我打算在这里探讨如何利用C++的特性优化高端编程。高端的编程历来是VB、Delphi、Java、C#等等语言的一亩三分地,如果我敢在这里说个不字,那点口水也能把我淹死。不过,为了C++,豁出去了,就让我一个人挨炸弹吧。
我的案例是一个小小的,不起眼的界面问题。尽管是小小的,不起眼的问题,但它的解决为我们指出在高端编程优化的一种途径。这种构想是否可行,以及是否值得,我不清楚。因为所需的机制,还在标准委员会的讨论之中,我还无法制作完整的案例加以检验。
一切从一个ComobBox开始。
有一次,我从数据库提出一组数据,放入一个ComboBox。ComboBox的每个项目还必须和一个值绑定,这样当选中一个项目的时候,便可以得到一个id,用于数据操作。这是再常规不过的操作了。在Windows API,MFC等库中,可以为每个项目指定一个“Item Data”或者“Item Data Pointer”。前者是个long,对应类型为long或能够转化成long的数据;后者是void*,对应那些非整数类型的数据。
在.net中,技术发展了,利用了OOP的多态。ComboBox的Item是一个Object^类型,我们可以创建一个ref class,重定义ToString()方法,而这个类中依然可以保留其他数据。.net中任何类型都可以多态地赋给Object^类型。ComboBox则调用每个Item的Object::ToString()方法,获得所需的显示内容。于是,ComboBox的Item既可以提供ComboBox所需的输出,也解决了附加数据的问题:
class MyItem
{
public:
MyItem(int id, String^ name) : _id(id), _name(name) {}
public:
int _id;
String ^_name;

String^ ToString() {
return name;
}
};
combobox1.Add(gcnew MyItem(10, “abc”));
这些操作我在以前已经做过无数次了。但这次不同。我不小心踩了个地雷。这次不同于以前,id不再是long,而是String^。但我还以为是long,所以提取出这个id的时候,出了大错:
MyItem^ cur=dynamic_cast<MyItem^>(combobox1.SelectedItem);
cur->…; //运行时错误,cur==nullptr
幸好我用了dynamic_cast,不然还不知怎么样呢。因为放入ComboBox的对象不是MyItem类型,所以这个转换得到的是空句柄。于是,我的程序得到了了一个难看的运行时错误。
“唉,要是强类型多好!”我一声长叹。话音未落,一个念头瞬间闯入了我的脑海,就像漆黑的夜空,划过一道明亮的闪电,照亮了每一个角落。…
呵呵,没那么夸张。但我的确想到了“强类型”。
毋庸置疑,强类型可以为我们提供很多好处。首先,强类型可以减少类型错误,避免不必要的类型转换,确保类型安全;其次,由于ADT(抽象数据类型)的引入,使得类型在拥有数据结构的同时,也描述了外在的行为特征。因此,类型具备了描述业务逻辑的能力。于是,强类型化使得我们可以利用ADT的这些能力,将业务逻辑的约束直接映射到代码中。并且,利用类型的匹配机制,维持了这些约束,使我们得以在编译时拦截诸多与业务逻辑相关的错误;最后,强类型可以参与重载,使得我们可以用统一的形式编写具有相同逻辑含义的代码,以此优化软件开发。
当我想到强类型,立刻联想到模板。我们完全可以利用模板来解决这个问题。
我考虑了三种方案,(所有三种方案,我放在blog里,以节省篇幅),最终选择了一种组合方案:
首先,需要约定业务对象类(以管理员类Admin为例)提供一个默认的显示字符串构造函数,暂且称为DefDisp()。(通常,业务对象类都应该有一个默认的显示函数,为了便于在界面上显示)。然后,定义一个默认显示组织的函数对象:
template<typename T>
struct DefaultDispOp
{
string operator()(const T& item) {
return item.DefDisp();
}
};
最后,将DefaultDispOp作为XComboBox第二参数的默认参数:
template<typename ItemT, typename DispOP=DefaultDispOp<ItemT> >
class XComboBox
{
...
string GetItemDispString(const ItemT& item, DispOp& op) {
return op(item);
}
}
DefDisp()所对应的显示应该是该业务对象最常用的显示,比如对于Admin而言,可能就是全名。如果只需要用默认方式显示的,那么只需简单地用业务对象类实例化XComboBox即可:
XComboBox<Admin> combobox1;
XComboBox<Admin> combobox2;
而对于有特殊显示要求的,再另外提供转换函数对象。
struct AdminDisp1
{
string operator()(const Admin& admin) {
…;
}
};
//用Admin和AdminDisp1实例化XComboBox
XComboBox<Admin, AdminDisp1> combobox1;
三种方案的分析可以看出,模板和泛型编程过度使用,反而不会达到最好的效果。通常,深度的泛型编程(包括元编程)都是在“迫不得已”的情况下使用的。比如,不使用GP,便会造成巨大的开发工作量(就像货币系统那个案例那样),或者根本无法实现(如标准库中的通用算法)。一般情况下,能使用传统技术,优先考虑传统技术,或者简单的泛型技术。
作为一个好事者(我总是一个好事者),我不断地端详XComboBox,发现它像一个东西:容器。没错,ComboBox原本就是一个容器,只是功能更多些而已。既然是个容器,我是否可以把它用在标准算法上呢?当然可以。我们可以把它看作是一个vector或者dequeue或者list,也可以象操作序列容器那样操作XComboBox,只需为XComboBox增加一组成员和typedef:
template<typename ItemT, typename DispOP>
class XComboBox
{
public:

Iterator begin(){…}
Iterator end() {…}
void push_back(const ItemT& item) {…}
void pop_back() {…}

};
这样,我们便可以将一个容器中的业务对象直接copy到XComboBox中去:
XComboBox<Admin> combo1;
vector<Admin> vAdmins;
…//初始化vAdmins,比如来源于某种对象数据系统
copy(vAdmins.begin(), vAdmins.end(), back_inserter(combo1));
更进一步,如果我们使用的数据库结果集也兼容标准库容器。那么,可以用transform算法直接将一个结果集传递到XComboBox中:
struct RS_to_Admin
{
Admin operator()(const STLRecordSet::RowT& row) {
Admin a;
… //用结果集的行初始化业务对象
return a;
}
};
XComboBox<Admin> combo1;
STLRecordSet rs=QueryData(“…”);
tramsform(rs.begin(), rs.end(), back_inserter(combo1), RS_to_Admin());
这些也表明,一旦所有的应用组件,包括数据访问、界面元素等等,都STL化之后,整个应用系统的开发便可以大幅度的简化。在这方面,走在前面的是Mathew Wilson(他的《Imperfect C++》想必很熟吧)。Wilson所开发的STLSoft以及相关的STLxxx系列库为诸多系统包括Unix、MFC、ATL、Internet、COM、.net提供了STL化的包装层。使得标准算法得以发挥最大的作用。
...全文
3369 71 打赏 收藏 转发到动态 举报
写回复
用AI写文章
71 条回复
切换为时间正序
请发表友善的回复…
发表回复
xkyx_cn 2008-04-01
  • 打赏
  • 举报
回复
mark
michney 2008-04-01
  • 打赏
  • 举报
回复
太长了,
先顶再看
SkyDeng 2008-04-01
  • 打赏
  • 举报
回复
请教一下,那个 String^ 是什么类型,^在这里是个运算符么?
f22fbi 2008-04-01
  • 打赏
  • 举报
回复
学习
AlwaysSLH 2008-04-01
  • 打赏
  • 举报
回复
来晚了,先占个座
^_^
yuyunliuhen 2007-06-21
  • 打赏
  • 举报
回复
都收藏了。
不涉及版权问题吧 ^_^
witkin 2007-06-21
  • 打赏
  • 举报
回复
太深奥了,不知道何时我也能有楼主的水平
仰视了
fantasy00000000 2007-06-21
  • 打赏
  • 举报
回复
发现楼主的几篇文章都是以魔板来说事的,看来这东西太强大了,好好学学
Hylas 2007-06-21
  • 打赏
  • 举报
回复
这也收藏啊, 我晕菜
060 2007-06-21
  • 打赏
  • 举报
回复
收藏
VCLIFE 2007-06-21
  • 打赏
  • 举报
回复
收藏
wanilyer 2007-06-21
  • 打赏
  • 举报
回复
赞一个!很好!
Jedimaster 2007-06-16
  • 打赏
  • 举报
回复
回复人:xenix(早死三年何愁睡) ( 二级(初级)) 信誉:100 2007-6-14 19:03:38 得分:0
?

两大泛型界面库: win32gui和smartwin,有真正的用户吗?几乎没有

=============================================================
有,我就在用赫赫
bombwang 2007-06-16
  • 打赏
  • 举报
回复
狂顶一下
zenner3000 2007-06-16
  • 打赏
  • 举报
回复
小菜鸟一个,顶
kwer 2007-06-16
  • 打赏
  • 举报
回复
谁说 GUI 就不是所谓“高端”?

问这种问题的人是不是学计算机的
你们是不是认为 GUI 很简单呀?
sinall 2007-06-16
  • 打赏
  • 举报
回复
“高层开发”好点。相对于底层开发。
sinall 2007-06-16
  • 打赏
  • 举报
回复
回复人:Wolf0403(废人:独活十年~心如刀割) ( 两星(中级)) 信誉:115 2007-6-13 8:45:04 得分:0
?

GUI 就是所谓“高端”?
同问。
奶糖人五号 2007-06-14
  • 打赏
  • 举报
回复
mark 膜拜一下
FingerStyle 2007-06-14
  • 打赏
  • 举报
回复
把STL中的算法运用到上层开发
我们也可以写一个ui_iterator给控件用


加载更多回复(51)

64,652

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧