热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

essay浅谈ACM盲区(下)

好了,现在我要给大家讲讲面向对象的一些知识。上次说到了,面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。一般地,面向对象具有继承性、封装性、多态性三个特征。

好了,现在我要给大家讲讲面向对象的一些知识。上次说到了,面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。一般地,面向对象具有继承性、封装性、多态性三个特征。
举个简单的例子吧,现在我让你去用计算器计算3*4的结果,你会这么做呢?仔细想想,流程应该如下。
(1)买一个计算器;
(2)输入3*4;
(3)按下=键,获得结果。
这正好对应这三行代码:
(1)Calculator c;
(2)c.inputFormula(“3*4”);
(3)c.getResult();
所以说,面向对象与现实非常贴合,这就是面向对象受欢迎的原因之一。
有人又会疑惑了,我怎么知道计算器对象具有哪些函数呢,函数的参数扫是什么,返回值又是什么?有没有一个标准或者是文档呢?
很负责的告诉你,有的。计算器有说明书,面向对象就有API。API:application Programming Interface,应用程序编程接口。
例如,这里的计算器类的API如下所示:
这里写图片描述
根据这个API,我们可以随心所欲地使用计算器啦~
然后有人又有疑惑了,你的API中为什么setFormula()函数要重载呢?为什么接收C++的字符串之外还要写一个接收C风格的字符串呢?
这其实就是面向对象的多态性。通俗一点说,就是多种选择随我选。一个面向对象的优质代码,往往就是尽可能多给与对方(使用者)更多的选择。
此外我再通俗地说一下封装性:即内部存储和实现不关我的事。例如在计算器类中,getResult()函数是如何工作的,这个或许是字符串解析吧,或许是利用栈结构,或许是递归……反正我是不知道,也没有必要知道,我只要会用就行了。就好像我们买电视,没有人说一定要知道电视的结构、组成才能看电视吧。面向对象也是一样的原理。
最后则是面向对象的继承性。例如:
(派生)人→学生→研究生
(继承)研究生→学生→人
就是典型的一个继承。
我们写三个类(人、学生、研究生)的“恋爱”方法吧。

class Person {
    int age;
    //……
    void love()
    {
        cout<<"fall in love at will"<
class Student:public Person
{
    int age;
    //……
    void love()
    {
        cout<<"fall in love seriously"<
class Postgraduate:public Student
{
    int age;
    //……
    void love()
    {
        cout<<"fall in love maturely"<

总而言之,这三类人是“随心所欲的恋爱”,“认真的恋爱”,“成熟的恋爱”。如果这个时候定义一个研究生对象gth,调用“恋爱”方法后,输出的肯定是“成熟的恋爱”。

//方法(函数)覆盖(重写)


Postgraduate gth;
gth.love();

/* 输出: fall in love maturely */

这个就称为方法(函数)覆盖(重写)。当然这里的覆盖并不是指一定访问不到了,只是使用起来好像是访问不到了。如果想要完全覆盖,需要使用虚函数。这里就不再赘述。
下面的概念很有趣。对于自然界很多物体(具体的或抽象的),一般都可以建立对象(实例化)。但是,对于一部分概念,其一般为一类统称,一般不希望其实例化,例如水果、动物、蔬菜……例如,“xxx,给我拿一个水果来。”这句话其实就是有问题的。
但是,“水果”作为一个概念,的确拥有一些属性(例如VC含量,重量)和方法(吃、存储)等。所以我们希望定义一个类,其指定了一部分属性和方法(方法空实现),该类不可实例化,只能通过继承后再实例,达到自然界的高度仿真。
我们需要纯虚函数来实现这个规律。
我们先写水果类:

class Fruit
{
private:
    double vcContent;
    double weight;
public:
    virtual void eat()=0;
    virtual void store()=0;
};

再写苹果类:

class Apple:public Fruit
{
public:
    void eat()
    {
        cout<<"just eat it :)"<void store()
    {
        cout<<"stored in shadow"<

最后是main()函数

void main()
{
// Fruit fruit; //Error
    Apple apple;
    apple.eat();
    apple.store();
}

最后,我们来一个生动的实战例子,来说明面向对象是如何编程的。

NOJ实战 1058
Tom和Jerry在10*10的方格中:
…..
……*…
..
……….
…*.C….
…..
…*……
..M……*
.….
..……
C=Tom(猫)
M=Jerry(老鼠)
*=障碍物
.=空地
他们各自每秒中走一格,如果在某一秒末他们在同一格中,我们称他们“相遇”。注意,“对穿”是不算相遇的。
他们移动方式相同:平时沿直线走,下一步如果会走到障碍物上去或者出界,就用1秒的时间做一个右转90度。一开始他们都面向北方。
编程计算多少秒以后他们相遇。
我们简要的对这个现实世界的产物进行抽象和建模:
这里写图片描述
然后我们回想,为什么位置和方向都是向量呢?看下面一张图就能明了。
这里写图片描述
接下来,我们就可以进行代码的编写工作啦~

#include
#define LENGTH 10
using namespace std;
/* The directions: down: (1 , 0) left: (0 , -1) up: (-1, 0) right: (0 , 1) */
class Vector
{
private:
    int x,y;
public:
    Vector()
    {
        x=y=0;
    }
    void setX(int x)
    {
        this->x=x;
    }
    void setY(int y)
    {
        this->y=y;
    }
    int getX()
    {
        return x;
    }
    int getY()
    {
        return y;
    }
    void setUp()
    {
        setX(-1);
        setY(0);
    }
    void setDown()
    {
        setX(1);
        setY(0);
    }

    void setLeft()
    {
        setX(0);
        setY(-1);
    }
    void setRight()
    {
        setX(0);
        setY(1);
    }
    bool operator==(Vector v)
    {
        return getX()==v.getX() && getY()==v.getY();
    }
    void output()
    {
        cout<<"("<","<")"<//void operator=(Vector &v);
    //void Vector(Vector const &v);
};

class Cat
{
private:
    Vector position;
    Vector direction;
public:
    Cat()
    {
        position.setX(0);
        position.setY(0);
        direction.setUp();
    }
    void setPosition(Vector position)
    {
        this->position=position;
    }
    Vector getDirection()
    {
        return direction;
    }

    Vector getPosition()
    {
        return position;
    }
    void turnRight()
    {
        if(direction.getX()==-1 && direction.getY()==0)            //up
            direction.setRight();
        else if(direction.getX()==1 && direction.getY()==0)        //down
            direction.setLeft();
        else if(direction.getX()==0 && direction.getY()==-1)    //left
            direction.setUp();
        else if(direction.getX()==0 && direction.getY()==1)        //right
            direction.setDown();
        else return;
    }
    Vector getNextPosition()
    {
        Vector newVector;
        newVector.setX(position.getX()+direction.getX());
        newVector.setY(position.getY()+direction.getY());
        return newVector;
    }
};

class Mouse:public Cat
{
public:
    Mouse():Cat()
    {
        ;
    }
};

class Labyrinth
{
private:
    char lab[LENGTH][LENGTH];
    Cat tom;
    Mouse jerry;
public:
    void read()
    {
        int i,j;
        char tpchar;
        Vector position;
        for(i=0;ifor(j=0;j>tpchar;
                if(tpchar=='C')
                {
                    lab[i][j]='.';
                    position.setX(i);
                    position.setY(j);
                    tom.setPosition(position);
                }
                else if(tpchar=='M')
                {
                    lab[i][j]='.';
                    position.setX(i);
                    position.setY(j);
                    jerry.setPosition(position);
                }
                else lab[i][j]=tpchar;
            }
        }
    }
    bool legal(Vector position)
    {
        if(    position.getX()<0 || position.getX()>=LENGTH
            || position.getY()<0 || position.getY()>=LENGTH
            || lab[position.getX()][position.getY()]=='*' )
            return false;
        return true;
    }
    int getDirectionId(Vector direction)
    {
        if(direction.getX()==-1 && direction.getY()==0)            //up
            return 0;
        else if(direction.getX()==1 && direction.getY()==0)        //down
            return 1;
        else if(direction.getX()==0 && direction.getY()==-1)    //left
            return 2;
        else if(direction.getX()==0 && direction.getY()==1)           //right
            return 3;
        else return -1;
    }
    bool isVisited(unsigned short visited[LENGTH][LENGTH][LENGTH][LENGTH])
    {
        int mouseDirection=getDirectionId(jerry.getDirection());
        int catDirection=getDirectionId(tom.getDirection());
        int bit=catDirection*4+mouseDirection;
        int element=
            visited[tom.getPosition().getX()][tom.getPosition().getY()]
                      [jerry.getPosition().getX()][jerry.getPosition().getY()];
        int bitElement=(element>>bit)%2;
        if(bitElement==1)
            return true;
        else
        {
            visited[tom.getPosition().getX()][tom.getPosition().getY()]
                      [jerry.getPosition().getX()][jerry.getPosition().getY()]
                +=(1<return false;
        }
    }
    int run()
    {
        int cnt=0;
        unsigned short visited[LENGTH][LENGTH][LENGTH][LENGTH]={0};
        while(true)
        {
            if(tom.getPosition()==jerry.getPosition())
                return cnt;
            if(isVisited(visited))
                return -1;
            if(!legal(tom.getNextPosition()))
                tom.turnRight();
            else tom.setPosition(tom.getNextPosition());
            if(!legal(jerry.getNextPosition()))
                jerry.turnRight();
            else jerry.setPosition(jerry.getNextPosition());
            cnt++;
        }
        return -1;
    }
};

int main()
{
    Labyrinth lab;
    lab.read();
    cout<return 0;
}

/* 输出结果:49 */

最后我们进行一个小结:
浅谈ACM盲区:
1.界面友好
2.编程规范
(1)变量和函数的命名规范
(2)变量和函数的命名格式(驼峰式)
(3)缩进
(4)注释:尽量用英文来保证兼容性
(5)可移植性、函数封装与模块耦合
3.非实用方法
4.实用性编程
5.面向对象编程


推荐阅读
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
author-avatar
暮迟_MCz_P
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有