| 网站首页 | 测试咨讯 | 新手入门 | 专注性能 | 测试技术 | 测试管理 | 测试工具 | 开发社区 | 工具下载 | 资料下载 | 测试论坛 | 

[CNTester联盟群]交流群:34446273/21968356/64461572 白盒群:18400216 自动化群:2706508 性能群:4498858 外包群:59649884 管理群(需有管理经验):64442523

新手入门
 入门指南
 经验之谈
测试咨讯
 行业新闻
 网站动态
 人才就业
 CNTester基金
 标准规范
专注性能
 性能测试知识
 性能测试工具
 程序设计性能
 数据库性能
 Web应用服务器性能
 操作系统性能
 服务器与网络性能
测试技术
 用例设计
 性能测试
 自动化测试
 Web测试
 面向对象测试
 综合技术
 阶段性测试
 行业类测试
测试管理
 项目管理
 项目案例
 质量管理
 软件过程
测试工具
 Mercury系列
 Rational系列
 测试管理工具
 性能测试工具
 功能测试工具
 单元测试工具
 其它测试工具
开发社区
 Java技术
 DotNet技术
 C技术
 数据库技术
 操作系统
 服务器与中间件
工具下载
 测试工具
 开发工具
 企业工程
 网络通信
 媒体桌面
 游戏娱乐
 其他工具
资料下载
 测试资料
 程序设计
 数据库
 操作系统
 应用服务器
 电子期刊
 其他资料
 
 
您现在的位置: 中国测试员网站 >> 开发社区 >> C技术 >> 文章正文
  [推荐]深度探索C++对象模型           ★★★ 【字体:
深度探索C++对象模型
作者:雷神    文章来源:火龙果    点击数:    更新时间:2007-7-5    

《深入C++对象模型》一书没有什么可以被成为重点的东西,感觉每一个字都不应该放过,全是重点。

深度探索C++对象模型(1)

第一章:关于对象(Object Lessons)读完这一章使我想到了一个很久以前看到的一个笑话,编写一个HELLO WORLD的程序,随着水平和职务的不一样,程序代码也随着变化。当初看时完全当作笑话来看,现在看来写此笑话的人水平不一般。如果要使你的代码能够最大限度的适应不同的运行环境,和最大限度的复用,则在设计和编写的过程中需要考虑的问题很多,因此代码已变的不在具有C语言的简洁,高效。而牺牲了这些优势换来的是更好的封装。当然如果你只是要打印Hello World则不必这样做了。

以C++的思维方式解决问题,对于对C语言已经很熟悉的人来说会很不能适应。需要一段时间来适应,不然会将代码写的似是而非。而且不能邯郸学步,必须从思想上彻底的C++(OO),如果只是依葫芦画瓢,那结果很可能是用C++的语法编写C式的程序。本人曾经犯的典型的低级的错误之一,就是无意识的一个类无限制的扩充,完全没有考虑到类的多层结构(基类-派生类),需要属性或方法便在类中增加,虽然也用到了多态、重载等一些OO的设计方式,但最后这个类庞大无比,除了在当前系统中任劳任怨的工作外,一点复用的可能都没有,如果另一个系统还需要一个类似的东西,那只能重新设计实现一个新的类。并且最致命的是在维护更新时带来得麻烦,需要不断全部编译不说,而且代码在用了大量注释后,在过一段时间读起来也是一件重脑力劳动。及失去了C的简洁清晰和高效,也不完全具备C++的面向对象的特性。这根本不能叫C++程序。(我想有时间重写一下以前代码也会有很多收获,温故而知新吗)C和C++在编程思想上是相互矛盾的。这也就是说如果你想学C++,完全可以不学C,只需要一本好书和一个不太笨的大脑再加上努力就可以了,如果你已有C的经验在一定的情况下反而会捣乱。

本章是对对象模型的一个大略浏览。既然我们选择了C++而不是C作为开发工具,那我们的编程思想也应该转为C++的,而不能再延续C的Procedural方式。我们必须学会C++的思考方式。采用抽象数据类型或用一个多层的class体系对数据以及数据处理函数进行封装,只有摆脱C程序的使用全局数据的惯性,才能充分发挥出C++对象模型的强大威力。

在C++中有两种数据成员static和nonstatic,以及三种成员函数static、nonstatic和virtual。C++对象模型对内存空间和存取时间做了优化,nonstatic的数据成员被置于类对象之内,而static数据成员被置于类对象之外。static和nonstatic成员函数被放在类对象之外。而virtual函数是由类对象的一个指向vtbl(虚函数表)的指针vptr来进行支持。而vptr的设定和重置由类的构造函数、析构函数以及copy assignment运算符自动完成。

我们设计的每一个类几乎都要有一个或多个构造函数、析构函数和一个Assignment运算符。他们的作用是构造函数产生一个新的对象并确定它被初始化。析构函数销毁一个对象并确定它已经被适当的清理(避免出现内存泄露的问题),Assignment运算符给对象一个新值。

这是第一章的第一部分,由于雷神最近几天在做模式小组的主页,时间周转不开了。本想写完整个一章再发,考虑一下还是先发一部分吧。原因有2。1、第一章的后半部可能又要拖上10天半个月的。2、笔记实在难写,我不愿意将笔记做成将书上的重点再抄一边,而是喜欢尽量将自己的理解描述出来,谁知第一章便如此的难以消化,已经反复读了3遍,还是有些夹生。所以本着对大家和自己负责的态度,雷神准备再看它3遍在说。突然发现自己的C++还差的很远,好可怕呀。

深度探索C++对象模型(2)

笔记贴出后,有朋友便给我提出了一个很好的建议,原文如下:
史列因:我刚看了你写的“深度探索C++对象模型(1)”,感觉很不错。不过我有一个建议:你说“谁知第一章便如此的难以消化,已经反复读了3遍,还是有些夹生”是很自然的。第一章是一个总览,如果你能全看懂,后面的就没什么看的必要了。第一章的内容后面都有详细介绍,开始只要有个大概印象就可以了。这本书中很多内容都是前后重复的。我建议你先不管看懂看不懂,只管向后看,之后再从头看几遍,那样效果好得多。
我想史列因说的应该是一种非常好的阅读方式,类似《深度探索C++对象模型》这样的技术书籍,需要的是理解,和学习英文不同,不能靠死记硬背,如果出现理解不了的情况,那你不妨将书放下,打一盘红警(俺骄傲的说,我是高手)。或者跳过去也是一个不错的方法。好了,我们还是继续研究C++的对象模型吧。

简单的对象模型

看书上的例子(注释是表示solt的索引)
Class Point
{
public:
Point(float xval); //1
virtual ~Point(); //2

float x() const; //3
static int PointCount(); //4
protected:
virtual ostream& print(ostream &os) const; //5
float _x; //6
static int _point_count; //7
}
每一个Object是一系列的Slots,每一个Slots指向一个members。

表格驱动对象模型

当构造对象时便会有一个类似指针数组的东西存放着类数据成员在内存中位置的指针,还有指向成员函数的指针。为了对一个类产生的所有对象实体有一个标准的表达,所以对象模型采用了表格,把所有的数据成员放在数据成员表中,把所有的成员函数的地址放在了成员函数表中,而类对象本身有指向这两个表的指针。

为了便于理解,雷神来举个不恰当的例子说明一下,注意是不很恰当的例子

我们把写字楼看成一个类,写字楼中的人看成是类的数据成员,而每一个租用写字楼的公司看成类的成员函数。我们来看一个实体,我们叫它雷神大厦。雷神大厦的物业管理部门需要登记每个出入写字楼的人,以便发通行证,并且需要登记每个公司的房间号,并制作了一个牌子在大厅的墙上。实际上这便是类的对象构造过程。你可以通过大厅墙上的公司列表找到任何一家在雷神大厦租房的公司,也可以通过物业提供的花名册找到任何一个出入雷神大厦的人。

C++的对象模型

C++对象模型是从简单对象模型派生得来,并对内存空间和存取时间做了优化。它引入了虚函数表(virtual table)的方案。每个类产生一堆指向虚函数的指针,放在表格中。每个类的对象被添加了一个指针(vptr),指向相关的虚函数表(virtual table)。而这个指针是由每一个类的constructor、destructor和copy assignment运算符自动完成。

我们还用上面的雷神大厦举例,物业管理为了提高效率,对长期稳定的公司和人员不再登记,指对不稳定或不能确定的公司进行登记,以便于管理。

得出结论,C++对象模型和双表格对象模型相比,提高了空间和存储时间的效率,却失去了弹性。

试想一下,没有整个雷神大厦人员和公司的名录,如果他们发生变化,则需要物业管理部门做很多工作。重新确定长期稳定的公司和人员是那些。对应应用程序则需要重新编译。(这次更离谱,但为了保持连贯,大家请进行理解性的思考,不要局限字面的意思)

这篇笔记是分成多次一点点写的,甚至每天抽出一个小时都不能保证(没办法最近实在忙),因此可能会有不连贯,如果你读起来很不爽认为雷神的思维短路了,那属于正常。不过雷神还是再上传之前努力的将思路进行了一下整理。希望能把这些支言片语串起来。

深度探索C++对象模型(3)

多态是一种威力强大的设计机制,允许你继承一个抽象的public接口之后,封装相关的类型,需要付出的代价就是额外的间接性--不论是在内存的获得,或是在类的决断上,C++通过class的pointer和references来支持多态,这种程序风格就称为"面向对象". 这篇笔记主要解决了几个常常被人问到的问题。
1、C++支持多重继承吗?
2、结构和类的区别是什么?
3、如何设计一个面向对象的模型?

C++支持多重继承(JAVA和C#不支持多重继承),虽然我想我可能一辈子用不到它这一特性(C++是雷神的业余爱好),但至少我要知道它可以。典型的多重继承是下面这个:
//iostream 从istream 和 ostream 两个类继承。
class iostream:public istream,public ostream
{......};

结构struct和类class到底有没有区别?VCHELP上前几天还看到一个帖子在讨论这个问题。其实结构和类真的没什么区别,不过我们需要掌握的是什么时候用结构好,什么时候用类好,当然这没有严格的规定。通常我们混合使用它们,从书上的例子,我们可以看出为什么还需要保留结构,并且书上给出了一个方法:
struct C_point{.......}; //这是一个结构
class Point
{
public:
operator C_point(){return _c_point;}
//....
private:
C_point _c_point;
//....
}
这种方法被成为组合(composition).它将一个对象模型的全部或部分用结构封装起来,这样做的好处是你既可以在C++中应用这个对象模型,也可以在C中应用它。因为struct封装了class的数据,使C++和C都能有合适的空间布局。

面向对象模型是有一些彼此相关的类型,通过一个抽象的base class(用来提供接口),被封装起来。真正的子类都是通过它派生的。当然一个设计优秀的对象模型还必须考虑很多的细节问题,雷神根据自己的理解写出一个面向对象模型的代码,大家可以看看,高手请给指出有没有问题。

思路:我想要实现一个人员管理管理的对象模型,雷神一直在思考一个人员管理的组件(当然最终它会用C#实现的一个业务逻辑对象,并通过数据库控制对象和数据库进行交互,通过WEB FORM来显示界面)。这里借用一下自己的已经有的的想法,用C++先进行一下实验,由于只是为了体会面向对象的概念,我们采用面向对象的方法实现一个链表程序,而且没有收集信息的接口。信息从mina()函数显式给出。
这个对象模型应该可以实现对人员的一般性管理,要求具备以下功能:
创建一个人员信息链表
添加、删除人员信息
显示人员信息

//*************************************************
//PersonnelManage.cpp
//创建人:雷神
//日期:
//版本:
//描述:
//*************************************************

#include <iostream.h>
#include <string.h>
//基类,是此对象模型的最上层父类
class Personnel
{
friend class point_list; //用来实现输出链表,以及插入或删除人员的功能.
protected:
char serial_number[15];//编号
char name[10];//名称
char password[15]//口令
Personnel *pointer;
Personnel *next_link;
public:
Personnel(char *sn,char *nm,char *pwd)
{
strcpy(serial_number,sn);
strcpy(name,sm);
strcpy(password,pwd);
next_link=0;
}
Personnel()
{
serial_number[0]=NULL;
name[0]=NULL;
password[0]=NULL;
next_link=0;
}
void fill_serial_number(char *p_n)
{
strcpy(serial_number,p_n);
}
void fill_name(char *p_nm)
{
strcpy(name,p_nm);
}
void fill_password(char *p_pwd)
{
strcpy(password,p_pwd);
}

virtual void addnew(){}
virtual void display()
{
cout<<"\n编号:"<<serial_number<<"\n";
cout<<"名字:"<<name<<"\n";
cout<<"口令:"<<password<<"\n"
}
};
//下面是派生的子类,为了简单些我在把子类进行了成员简化。
//思路:由父类派生出成员子类,正式成员要求更详细的个人资料,这里省略了大部份.
//并且正式成员可以有一些系统的操作权限,这里省略了大部份。
//正式成员子类
class Member:public Personnel
{
friend class point_list;
private:
char member_email[50];
char member_gender[10];
double member_age;
public:
Member(char *sn,char *nm,char *pwd,char *em,char *gd,double ag):Personnel(sn,nm,pwd)
{
strcpy(member_email,em);
strcpy(member_gender,gd);
member_age=age;
}
Member():Personnel()
{
member_email[0]=NULL;
member_gender=NULL;
member_age=0.0;
}
void fill_email(char *p_em)
{
strcpy(member_email,p_em);
}
void fill_gender(char *p_gd)
{
strcpy(member_gender,p_gd);
}
void fill_age(double ages)
{
member_age=ages;
}

void addnew()
{
pointer=this;
}
void display()
{
Personnel::display()
cout<<"电子邮件:"<<member_email<<"\n";
cout<<"性别:"<<member_gender<<"\n";
cout<<"年龄"<<member_age<<"\n";
}
};

//好了,我们还需要实现一个超级成员子类和一个项目经理的子类.
//这是超级成员类
class Supermember:public Member
{
friend class point_list;
private:
int sm_documentcount;//提交的文档数
int sm_codecount;//提交的代码段数
public:
Supermember(char *sn,char *nm,char *pwd,char *em,char *gd,double ag,int dc,int cc):Member(sn,nm,pwd,gd,ag)
{
sm_documnetcount=0;
sm_codecount=0;
}
Spupermember():Member()
{
sm_documentcount=0;
sm_codecount=0;
}
void fill_documentcount(int smdc)
{
sm_documentcount=smdc;
}
void fill_codecount(int smcc)
{
sm_codecount=smcc;
}

void addnew()
{
pointer=this;
}
void display()
{
Member::display()
cout<<"提交文章数:"<<sm_documentcount<<"\n";
cout<<"提交代码段数"<<sm_codecount<<"\n";
}
};

//实现友元类
class point_list
{
private:
Personnel *location;
public:
point_list()
{
location=0;
}
void print();
void insert(Personnel *node);
void delete(char *serial_number);
}
//显示链表
void point_list::print()
{
Personnel *ps=location;
while(ps!=0)
{
ps->display();
ps=ps->next_link;
}
}
//插入链表
void point_list::insert(Personnel *node)
{
Personnel *current_node=location;
Personnel *previous_node=0;
while(current_node!=0 && (strcmp(current_node->name,node->name<0)
{
previous_node=current_node;
current_node=current_node->next_link;
}
node->addnew()
node->pointer->next_link=current_node;
if(previous_node==0)
location=node->pointer;
else
previous_node->next_link=node->pointer;
}

//从链表中删除
void point_list::delete(char *serial_number)
{
Personnel *current_node=location;
Personnel *previous_node=0;
while(current_node!=0 && strcmp(current_node->serial_number,serial_number)!=0)
{
previous_node=current_node;
current_node=current_node->next_link;
}
if(current_node !=0 && previous_node==0)
{
location=current_node->next_link;
}
else if(current_node !=0 && previous_node!=0)
{
previous_node->next_link=current_node->next_link;
}
}

//这是主函数,我们显式的增加3个Supermember信息,然后在通过编号删除一个
//我们没有从成员再派生出管理成员,所以没有办法演示它,但我们可以看出要实现它并不难
//注意:此程序没有经过验证,也许会有BUG.
main()
{
point_list pl;
Supermember sm1("000000000000001","雷神","123456","lsmodel@ai361.com","男",29.9,10,10);
Supermember sm1("000000000000002","木一","234567","MY@ai361.com","男",26.5,20,5);
Supermember sm1("000000000000003","落叶夏日","345678","LYXR@ai361.com","男",24.8,5,15);
//如果我们还派生了管理人员,可能的方式如下:
//Managemember mm1("000000000000004","ADMIN","888888","webmaster@ai361.com","男",30,5,15,......);

//下面是将上面的3个人员信息加到链表中
pl.insert(&sm1);
pl.insert(&sm2);
pl.insert(&sm3);
//对应管理人员的 pl.insert(&mm1);

//下面是显示他们
//下面是显示人员列表
pl.print();

//下面是删除一个人员信息
pl.delete("000000000000001");
//我们再显示一次看看.
cout<

[1] [2] [3] 下一页

文章录入:fy818    责任编辑:fy818 
  • 上一个文章:

  • 下一个文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
     
    最新热点 最新推荐 相关文章
    · 面向对象设计与编程核心技术
    · Tomcat系统安全管理与权限管理
    · 雅虎公司C#笔试题
    · 利用Java事件处理机制实现录制、回放功能
    · apache+tomcat+mysql负载均衡和集群
    · Linux 指令大全
    · 应用服务器内存泄露问题诊断一例
    · 追求代码质量: 软件架构的代码质量
    · 对话 UNIX
    · 关于一些算法问题与朋友的讨论
    · 对话 UNIX
    · nmon 性能:分析 AIX 和 Linux 性能的免费
    · 追求代码质量: 谨防紧密耦合!
    · 应用服务器内存泄露问题诊断一例
    · Linux 指令大全
    · C 编程最佳实践
    · LPI 证书 101 考试准备,第2部分 [正则表
    · LPI 证书 101 考试准备,第1 部分 [使用L
    · Linux 究竟是什么?
    · 利用Java事件处理机制实现录制、回放功能
    C++面向对象编程入门:构造函
    C语言高效编程的四大绝招
    C++内存对象大会战
    C入门
    高质量C++/C编程指南
    初学者学习C++的50条忠告
     
     
     
    ======> [CNTester联盟群]交流群:34446273/21968356/64461572 白盒群:18400216 自动化群:2706508 性能群:4498858 外包群:59649884 管理群(需有管理经验):64442523
    | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 网站公告 | 管理登录 | 

    Copyright@2007 by CNTester.com 中国测试员网站 桂ICP备07005590

    本站为开源免费网站,非商业赢利性组织。本站文章部分从网络搜索获取,如果您认为某些侵犯了您的权益,麻烦您联系本站,我们会尽快删除相关内容,同时也希望您的谅解,我们的初衷是为了让更多人去学习这方面的知识,让行业有更好的发展。

    联系电话: 15021358905