分享

从“集合”实例分析修饰函数返回值的const作用

 心不留意外尘 2016-04-28
http://www./lf426/archive/2008/03/13/44360.html
2008.03
        这段时间在复习C++基础,算法与数据结构,以及学习STL。所以,SDL的教程更新会慢些。因为我还是以自己的项目为核心进行学习的,所以基础知识和游戏设计涉及到图形,控制和多线程的内容学习,应该是会有些交叉的。
        发现这个问题,是因为一直以来思考的一个算法——关于“集合”的实现。这个集合就是数学中的集合,与计算机中数列一个最大的不同在于,集合的元素是互异的。因为这两天在熟悉vector,所以觉得用vector实现集合再合适不过了。STL确实是很好很强大的体系,无论是内存管理,还是链表的实现,让我们可以省很多心。其实关于为什么要实现集合,也是因为我在计划实现类似英雄无敌战场计算移动的一系列算法中,很多地方会用到集合的概念,甚至包括并集和差集等等。也许我想到的算法是很笨拙的,但是在我还没有完全阅读相关的已有代码之前,觉得完全凭自己的认识,实现这些算法还是很有意义的,所以,从学习C++的第一天开始,我就在试图找到解决这些问题的方法,而现在,越来越清晰了,呵呵。
        我的思路很直接也很简单,就是把一个数组中的元素往一个新的数组中填,新填充的元素会遍历新数组中已有的元素,如果与之互异,则填入(push),否则就跳到下一个。以上就已经确立了成员数据(私有)和构造函数。因为我们需要“集合化”了的数组是可以被外部访问的,所以一个最简单的方法就是把成员数据公有——这确实是很简单,而且这样就不会出现今天我们要讨论的问题了;另外一个笨办法是用一个公有方法,返回成员数据的值——我就是这么做的,因为这貌似更符合OOP的“数据隐藏”的精神-_-!!!。很快可以写出头文件:
#ifndef AGGREGATE_H_
#define AGGREGATE_H_

#include <iostream>
#include <vector>
#include <algorithm>

class Aggregate
{
private:
    std::vector<int> agg;
public:
    Aggregate(std::vector<int>& temp);
    const std::vector<int> getAgg() const;
};

#endif
请注意那个红色的const,其实我想说的是,第一次写这个程序的时候,我并没有这个const。一直以来,除了在重载“=”的时候我大概清楚修饰返回值const的作用是可以避免让返回值做左值,其他时候还真不太明白这个const的作用,只是本着C++的精神——能const就const吧-_-!!!。实现文件:
#include "aggregate.h"

Aggregate::Aggregate(std::vector<int>& temp)
{
    for ( std::vector<int>::iterator pTemp = temp.begin(); pTemp != temp.end(); pTemp++ ) {
        bool findSame = false;
        for ( std::vector<int>::iterator pAgg = agg.begin(); pAgg != agg.end(); pAgg++ )
            if ( *pTemp == *pAgg )
                findSame = true;
        if ( findSame == false )
            agg.push_back(*pTemp);
    }
}

const std::vector<int> Aggregate::getAgg() const
{
    return agg;
}
一切都很完美,不是吗?顺手就继续写出一个测试用的程序:
#include "aggregate.h"

void show(int& i);

int main(int argc, char* argv[])
{
    std::vector<int> tempArray;
    int temp;
    bool goon = true;

    while ( goon == true ) {
        std::cout << "#" << tempArray.size()+1 << "= ";
        std::cin >> temp;
        if ( temp == -1 ) {
            goon = false;
            continue;
        }
        tempArray.push_back(temp);
    }

    std::cout << "You've entered " << tempArray.size() << " numbers." << std::endl;

    for_each(tempArray.begin(), tempArray.end(), show);

    std::cout << "----------------------------\n" << "Now, to be aggregate\n";

    Aggregate tempAgg (tempArray);
    std::cout << "There are " << tempAgg.getAgg().size() << " different numbers.\n";
    for_each(tempAgg.getAgg().begin(), tempAgg.getAgg().end(), show);


    return 0;
}

void show(int& i)
{
    std::cout << i << std::endl;
}
很不幸,编译正常的通过了(注意,没有红色的const的时候)。
但是,运行时出现了错误。
运行时错误是件令人很郁闷的事情,因为这意味着编译器不会帮你找到出错的地方。
幸运的是,直觉让我觉得类似tempAgg.getAgg().begin()的用法有问题,所以,我改成了:(紫色那部分代码)
    std::cout << "----------------------------\n" << "Now, to be aggregate\n";

    Aggregate tempAgg (tempArray);
    std::vector<int> tempAggArray = tempAgg.getAgg();
    std::cout << "There are " << tempAggArray.size() << " different numbers.\n";
    for_each(tempAggArray.begin(), tempAggArray.end(), show);
这样,问题是解决了。但是我们回头分析一下,刚才的问题到底出在什么地方呢?
其实,如果我们加上红色的const,使用原来的代码进行编译的时候,编译器是可以指出我们的错误的,确实是tempAgg.getAgg().begin()的用法出了问题。具体的原因包含在<algorithm>里面,我没有仔细去分析,但是我们至少明白了,方法begin()会试图修改其对象的返回值!
        让错误被发现在编译阶段,远远好于被发现在运行时阶段。我想,这就是C++中const最大的作用。所以,总结起来还是C++的一句话,能const,就const吧。:)
posted on 2008-03-13 13:30 lf426 阅读(683) 评论(3)  编辑 收藏 引用 所属分类: 语言基础、数据结构与算法

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多