2011-12-27 51 views
1

我看到这个问题:Class design with vector as a private/public member?,但我不认为它回答了这个问题。如何设计一个C++类而不将std :: vector作为公共成员?

我有一个叫做PrimeSieve的类,可以初始化为PrimeSieve s(10000)来执行诸如检查10000以下的数字是素数还是列出10000以下的所有素数等操作。特别是,我想知道如何执行后一个函数。

目前,我这样做,我认为这违反了面向对象的原则:

class PrimeSieve { 
public: 
... 
    std::vector<long long> primes; 

客户将永远不需要更换载体,但我怎么还允许客户端通过遍历在一些号码(使用像vector.size()所有的素数的载体?我想过,它返回值向量的访问方法,但似乎效率不高。

回答

9

我会定义类:

class PrimeSieve 
{ 
public: 

    typedef std::vector<long long>::const_iterator const_iterator; 

    const_iterator begin() const { return primes.begin(); } 
    const_iterator end() const { return primes.end(); } 

    long long operator[](int index) const { return primes[i]; } 

    size_t size() const { return primes.size(); } 

    //rest of the members which compute the primes! 

private: 
    std::vector<long long> primes ; 
} ; 

我认为类的用户应该有只读访问矢量,所以我在typedef的定义中使用const_iterator。另请注意,operator[]const成员函数,这意味着您只能访问该值,但无法修改该值。

用法:

PrimeSieve sieve(1000); //compute 

//print to stdout 
std::copy(sieve.begin(), 
      sieve.end(), 
      std::ostream_iterator<long long>(std::cout, " ")); 
+1

这是一个很好的方法,因为它允许稍后随着客户端代码继续工作(在重新编译之后)不变地工作而改变一些实现细节。具体地说,迭代器的实现可以稍后改变为例如生成任意数量的结果(CPU时间允许),而不是具有硬编码的限制,并且最重要的客户端使用 - “begin()”和取消引用/递增它返回的迭代器 - 可以继续工作。这是考虑你的界面中是否真的需要'end()'和'size()'的一个原因:客户可以决定他们什么时候“够用”了吗? – 2011-12-27 09:43:37

+0

感谢您的回答!我对权衡这两种可能性感到好奇 - 这种方法比TonyK提出的方法有哪些优点? – Louis 2011-12-27 10:35:23

+0

@Louis:正如你之前的评论所说,这个解决方案可以灵活地改变*内部*,而不需要客户端改变他们的代码,因为这没有公开实现的内部细节。例如,如果将'std :: vector'更改为'std :: list',则客户端代码不需要更改,因为客户端使用一对迭代器,并且不必担心'PriveSieve'是否内部使用vector或list。[续] – Nawaz 2011-12-27 10:47:26

1
public: 
    const std::vector<long long>* getPrimes() const { return &primes; } 
private: 
    std::vector<long long> primes; 

这使客户获得一个const指针Ť primes这意味着他们可以迭代它,但不能修改它。

(我的语法可能是错误的,它已经有几年,因为我已经做了任何严重的C++)

1

的基本规则是:
你让数据成员private &然后提供public/protected成员函数以公开在private数据成员上提供的功能/操作。

你应该在这里遵循相同的规则。

6

这是做这件事:

class PrimeSieve { 
public: 
    const std::vector<long long>& getPrimes() const { 
    return primes ; 
    } 
private: 
    std::vector<long long> primes ; 
} ; 

这里没有效率 - 返回一提的是至少为返回一个指针一样高效。客户端可以遍历由getPrimes返回的向量(自然使用const_iterator)。

1

另一种可能性是做设计一个特殊的迭代器类:

class PrimeSieve { 
    mutable std::vector<long long> primes; 
public: 

    class const_iterator; 
    friend class const_iterator; 
    class const_iterator{ // should probably inherit from some std::iterator class, not sure there 
    const PrimeSieve *domain; 
    unsigned index; 
    public: 
    const_iterator(const PrimeSieve &d): domain(&d), index(0) {} 
    const long long &operator *() const{return domain->primes[index];} 
    const_iterator &operator++(){ 
     if (++index >= domain->primes.size()) { 
     // calculate a number of "new" primes here 
     } 
     return *this; 
    } 
    } 

    const_iterator begin() const {return const_iterator(*this);} 
}; 

关于这个的好处是,集装箱,现在是“无限”:素数懒洋洋地计算公式需要,而不是达到一个给定的上限。

+1

这是一个很好的模式,但筛选算法是围绕固定的上限设计的。 – Krumelur 2011-12-27 10:31:01

+0

@Krumelur是的,但是扩展算法很容易,所以您可以继续从该边界进行计算,并且如果以与std :: vector相同的方式增加边界,那么计算开销将会分摊。 – leftaroundabout 2011-12-27 11:10:26

相关问题