动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
电脑书籍下载:程序设计书籍 | 数据库教程书籍 | 平面与多媒体书籍 | 网络通讯书籍 | 系统管理书籍 | 网络安全书籍 | 认证考试书籍
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > C/C++教程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ C/C++教程 ]的信息



本月文章推荐
.用Win32 API枚举应用程序窗.
.C编写Windows服务程序的五个步骤.
.Delphi 8 For .NET 抢先预览.
.学用dbx.
.C++ Builder 创建分布.
.使用Rational进行C++转换的技巧.
.Nokia S60编程环境的建立.
.自定义控件(模板+数据绑定).
.API之打印函数.
.找鞍点.
.正确使用 C++Builder组件缩.
.在DBGrid中实现Copy、Paste功能.
.C++中建立对象间消息连接的一种系.
.学习C++的最大难度是什么?.
.MCI(媒体控制接口)相关知识.
.lzw压缩算法的c语言实现.
.C语言设计初学者的十八颗“地雷”.
.C++操作符重载的变态用途之子类转.
.用ADO压缩Access2000库.
.C程序开发经典实例之5.

理解C++面向对象程序设计中的抽象理论

发表日期:2008-3-8 |


  很多书在一开始就开始学习josephus问题,为了让大家前面学起来较为轻易我把前面涉及到此问题的地方都故意去掉了,现在我们已经学习过了结构体和类,所以放在这里学习可能更合适一些。

  在正式开始学习之前我们先回顾一下如何利用数组和结构体的方式来解决,最后我们再看一下如何利用面向对象的抽象理念进行解决此问题的程序设计,相互对比,找出效率最高,最轻易理解,最方便维护的程序来,说明利用面向对象的抽象理念进行程序设计的好处。

  josephus问题其实就是一个游戏,一群小孩围成一个圈,设置一个数,这个数是个小于小孩总数大于0的一个整数,从第一个小孩开始报数,当其中一个小孩报到你设置的那个数的时候离开那个圈,这样一来反复报下去,直到只剩下最后一个小孩的时候那个小孩就是胜利者,写程序来找出这个小孩。

  以下是数组方法:

  由于数组的限制我们必须预先假设好有多少个小孩,离开的小孩他自身设置为0来标记离开状态。

  代码如下:#include <iostream> 
using namespace std; 
void main() 

  const int num=10; 
  int interval; 
  int a[num]; 
  for(int i=0; i<num; i++) 
  { 
    a[i]=i+1; 
  }  
    cout <<"please input the interval: "; 
  cin >>interval; 
  for(int i=0; i<num; i++) 
  { 
    cout <<a[i] <<","; 
  } 
    cout <<endl; 
 
int k=1; 
int p=-1; 
 
while(1) 

    for(int j=0;j<interval;) 
    { 
        p=(p+1)%num; 
        if(a[p]!=0) 
        { 
            j++; 
        } 
    } 
    if(k==num) 
    { 
        break; 
    } 
    cout<<a[p]<<","; 
    a[p]=0; 
    k++; 

cout <<"\nNo." <<a[p] <<" boy've won.\n"; 
cin.get(); 
cin.get(); 
}  就数组解决来看,程序简短但效率不高可读性也不好,此代码没有什么非凡之处主要依靠一个加1取模的方式往返到首位置,形成环链:p=(p+1)%num;。 更多文章 更多内容请看C/C++技术专题  C/C++进阶技术文档  C/C++相关文章专题,或   以下是利用结构体的方法解决josephus问题:


  当我们学过结构体后,我们了解到结构体自身的成员指针可以指向自身对象的地址的时候,我们很轻易想到解决这个数学问题,用结构体来描述是再合适不过的了,用它可以很完美的描述环形链表。

  代码如下:
#include <iostream>   
#include <string>   
using namespace std;     
 
strUCt Children 

    int number; 
    Children *next; 
}; 
 
void show(Children *point,int num)//环链输出函数 

    for(int i=1;i<=num;i++) 
    { 
        cout<<point->number<<","; 
        point = point->next; 
    } 

 
void main() 

    int num;//孩子总数 
    int interval;//抽选号码 
    cout<<"请输入孩子总数:"; 
    cin>>num; 
    cout<<"请输入抽选号码:"; 
    cin>>interval; 
     
    Children *josephus = new Children[num];//设置圈的起点指针,并动态开辟堆空间用于存储数据 
 
    Children *point = josephus;//用于初化链表的指针,起始地址与josephus指针相同 
 
    for(int i=1;i<=num;i++) 
    { 
        point -> number = i; 
        point -> next = josephus + i % num;//利用+1取模的方式设置节点的next指针,当到最后的时候自动指向到第一个,形成环链 
        point = point->next;//将位置移到下一饿节点也就是下一个小孩的位置 
    } 
 
    show(point,num); 
 
    Children *cut_point; 
    point=&josephus[num-1];//把起始指针设置在最后一个节点,当进入循环的时候就会从0开始,这样就好让不需要的节点脱离 

    int k=0;//故意设置一个k观察while循环了多少次 
    while(point->next!=point)//通过循环不断的寻找需要放弃的节点 
    { 
        k++; 
        for(int i = 0;i<interval;i++)//找需要放弃的节点位置 
        { 
            cut_point=point;//存储截断位置指针 
            point=cut_point->next;//将point的指针移动到放弃的节点位置,此处也和while循环终止条件有关系 
        } 
        cut_point->next=point->next;//将截断出的next指针设置成放弃处节点的next指针,使放弃处节点也就是不需要的节点脱离 
        cout<<"k:"<<k<<endl; 
    } 
    cout<<"\n最后的赢家:"<<endl<<point->number<<endl<<point<<endl<<point->next<<endl; 
    delete[] josephus; 
    cin.get(); 
    cin.get(); 
}  此代码较为难以理解的部分就是while循环的终止条件的设置,假如读者没有能够理解好这部分注重看下面的图式帮助学习。

  结构体的解法非常重要,对于我们全面理解面向对象的程序设计的抽象问题是基础,必须看明白我们才能够进行后面知识的学习,务必认真对待。

  这段代码比较前一个程序,可读性上有所加强,但仍然不太轻易理解! 更多文章 更多内容请看C/C++技术专题  C/C++进阶技术文档  C/C++相关文章专题,或 理解C++面向对象程序设计中的抽象理论
  为了更轻易学习便于理解,我们的图例是以有两个小孩围成一圈,并且设置报数的数为1的情况来制作的。  上面的两种解决Josephus问题的解决办法从代码上来看,都属于一杆子到底的解法,第二种从结构表达上优于第一种,但是这两个都属于纯粹的过程式程序设计,程序虽然简短,但很难让人看懂,程序的可读性不高,在我们没有学习面向对象的编程之前,聪明的人可能会把各各步骤分解出来做成由几个函数来解决问题。

  思路大致可以分为以下六个部分:

  1.建立结构

  2.初始化小孩总数,和数小孩的数

  3.初始化链表并构成环链

  4.开始通过循环数小孩获得得胜者

  5.输出得胜者

  6.返回堆内存空间

  从表上看这个程序为了便于阅读可以写成六个函数来分别处理这六个过程,的确,这么修改过后程序的可读性是提高了一大步,但是有缺点仍然存在,程序完全暴露在外,任何人都可以修改程序,程序中的一些程序作者不希望使用者能够修改的对象暴露在外,各对象得不到任何的保护,不能保证程序在运行中不被意外修改,对于使用者来说还是需要具备解决Josephus问题算法的能力,一旦程序变的越来越很,,每一个参与开发的程序员都需要通读程序的所有部分,程序完全不具备黑盒效应,给多人的协作开发带来了很大的麻烦,几乎每个人都做了同样的重复劳动,这种为了解决一个分枝小问题写一个函数,最后由很多个解决局部问题的函数组合成的程序我们叫做结构化程序设计,结构化编程较过程化编程相比可读性是提高了,但程序不能轻易的被分割解决一个个大问题的模块,在主函数中使用他们的时候总是这个函数调用到那个函数,假如你并不是这些函数的作者就很难正确方便的使用这些函数,而且程序的变量重名问题带来的困扰也是很让人头痛的……

更多文章 更多内容请看C/C++技术专题  C/C++进阶技术文档  C/C++相关文章专题,或   那么面向对象的程序设计又是如何解决这些问题的呢?


  面向对象的程序设计的思路是这样的:

  程序 = 对象 + 对象 +对象..........

  这么组合而来的

  对于上面的josephus问题可以把问题分割成如下的方法进行设计(如下图所示) 理解C++面向对象程序设计中的抽象理论
  附件:点击下载(11K, zip压缩文件)  由上图可以看出:

  面向对象的程序设计是由类组合而成的,有类必然有类的对象,程序之间的交互主要是通过对象与对象之间的关系进行操作的。

  由于我们把josephus问题分解成了josephus类和ring类,在主函数中,用户只需要使用josephus类设计其对象明确知道Josephus类的外部接口函数也就是操作该对象的方法initial()就可以了,至于josephus的内部实现又是如何与Ring类进行操作的使用者一概不需要知道,只要拿来用知道接口和接口函数是什么就可以了,这样的程序设计很好的保护了各类成员数据的安全,主函数代码调用极其简单只有建立对象和调用对象方法的操作这两部而已,以后类一旦需要修改,只修改类体本身就可以,而主函数不需要做任何修改,这样就很好的做到了什么人做的事情什么人处理互不冲突。

  程序的代码如下,我把工程文件压缩了作为此帖的附件提供下载,希望读者仔细阅读仔细推敲,真正理解面向对象oop编程的特点和意图。

  主程序test4.cpp#include <iostream> 
#include "josephus.h" 
using namespace std; 
 
void main() 

    Josephus a; 
    a.initial(); 
    cin.get(); 
    cin.get(); 
}   josephus.hclass Josephus 

public: 
     Josephus(int num=10,int interval=1) 
     { 
         Josephus::num=num; 
         Josephus::interval=interval; 
     } 
     void initial(); 
protected: 
    int num; 
    int interval; 
};  josephus.cpp#include <iostream> 
#include "josephus.h" 
#include "ring.h" 
 
using namespace std; 
 
void Josephus::initial() 

    int num,interval; 
    cout<<"请输入孩子总数:"; 
    cin>>num; 
    if(num<2) 
    { 
        cout<<"孩子总数不能小于2,否则不能构成环链!"; 
        return; 
    } 
    cout<<"请输入抽选号码"; 
    cin>>interval; 
    if(interval<1interval>num) 
    { 
        cout<<"请输入抽选号码不能小于1或者大于小孩总数!"; 

        return; 
    } 
    Josephus::num=num; 
    Josephus::interval=interval; 
    Ring a(num); 
    a.ShowRing(num); 
    cout<<endl; 
    for(int i=1;i<num;i++) 
    { 
        a.CountInterval(interval); 
        a.ShowWiner_loser(); 
        a.OutChild(); 
    } 
    cout<<endl<<"胜利者是:"; 
    a.ShowWiner_loser(); 
} 更多文章 更多内容请看C/C++技术专题  C/C++进阶技术文档  C/C++相关文章专题,或   ring.hstruct Children 

    int number; 
    Children *next; 
}; 
 
class Ring 

public: 
    Ring(int num) 
    { 
        josephus = new Children[num]; 
        point = josephus; 
        for(int i=1;i<=num;i++) 
        { 
            point->number = i; 
            point->next = josephus + i % num; 
            point=point->next; 
        } 
        point = &josephus[num-1]; 
    } 
    ~Ring() 
    { 
        delete[] josephus; 
    } 
    void ShowRing(int num); 
    void CountInterval(int interval); 

    void OutChild(); 
    void ShowWiner_loser(); 
protected: 
    Children *josephus; 
    Children *point; 
    Children *cut_point; 
};  ring.cpp#include <iostream> 
#include "ring.h" 
 
using namespace std; 
void Ring::ShowRing(int num) 

        point=josephus;//也可以写成point=point->next;但前着效率高一点点 
        for(int i=1;i<=num;i++) 
        { 
            cout<<point->number<<","; 
            point=point->next; 
        } 
        point=&josephus[num-1];//输出过后恢复point应该在的位置 

void Ring::CountInterval(int interval)//数小孩 

    for(int i=0;i<interval;i++) 
    { 
        cut_point = point; 
        point = cut_point->next; 
    } 

void Ring::OutChild() 

    cut_point->next = point->next;//将不要节点断离 
    point=cut_point; 

void Ring::ShowWiner_loser() 

    cout<<point->number<<","; 
}  程序中需要注重的小地方是在这里class Josephus 

public: 
     Josephus(int num=10,int interval=1) 
     { 
         Josephus::num=num; 
         Josephus::interval=interval; 
     } 
     void initial(); 
protected: 
    int num; 
    int interval; 
};  代码中的 Josephus::num=num;
Josephus::interval=interval;   使用域区分符的目的就是为了区分成员变量和局部变量Josephus(int num=10,int interval=1)

  相信读者认真读完程序认真理解后应该就可以理解面向对象程序设计的用意和好处了,切记认真推敲!

  大家看到面向对象程序设计的解决办法,可能觉得它的代码太多了,会怀疑它执行的效率是否足够好,呵呵!

  这里只能这么说,程序的效率不是单单看程序的长短来看的,优秀的程序应该是便于维护,关系清楚的,面向对象的程序设计其实和过程式或者是结构化程序设计的思路是不冲突的,在不同的地方使用不同的方法,优势互补才是正道! 更多文章 更多内容请看C/C++技术专题 
 C/C++进阶技术文档  C/C++相关文章专题,或
上一篇:C++类对象的复制-拷贝构造函数 人气:360
下一篇:C++面向对象编程入门:构造函数与析构函数 人气:394
浏览全部C/C++的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-7-24 Sablog-X v2.0 预览版
2008-7-24 帝国备份王EmpireBak 2008 正式版
2008-7-24 网趣网上购物系统时尚版 v8.2
2008-7-24 纵横B2B电子商务系统XYECS!B2B v
2008-7-24 e路小说小偷 v1.2.0723
2008-7-24 凌风美女图片站程序 v2.2
2008-7-24 TOM15电影收索程序
2008-7-24 清风信息自动采集生成系统 v1.0
2008-7-24 QQ邮箱编辑器 v1.0 (小小菜刀ASP
2008-7-19 UltraEdit 简体中文增强版 14.10
2008-7-19 CentOS 5.2 i386 LiveCD
2008-7-19 Snapture多功能相机 v1.4
2008-7-19 iAcces中文输入法 v1.0Build016
2008-7-19 Cookbook烹饪秘籍 v2.5
2008-7-19 苹果专用DVD转换工具 v1.1.59汉化
2008-7-19 Modem修复软件ZiPhone修改版04.0
2008-7-19 AgileMessenger即时通讯工具美化
2008-7-19 Sketches画图软件 v0.7b6破解版


  发表评论
姓 名: 验证码:
内 容:
[ 汉字翻译拼音 ] [ 广告代码 ] [ 符号对照表 ] [ 进制转换 ] [ 经典小工具 ] [ 个税计算 ] [ 汉字简繁转换 ] [ 普通单位换算 ] [ 公制单位换算 ]
[ 生辰老黄历 ] [ 国内电话区号 ] [ 国家代码与域名缩写 ] [ 文字加密解密 ] [ 健康查询 ] [ 万年历 ] [ 手机号码查询 ] [ ip搜索 ] [ Google PR查询 ]
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号