Roy
Roy

Reputation: 3624

How do you design a C++ class without making a std::vector a public member?

I've seen this question: Class design with vector as a private/public member?, but I don't feel that it answers the question.

I have a class called PrimeSieve that can be initialized as PrimeSieve s(10000) to perform actions such as checking whether a number under 10000 is prime or listing all the primes under 10000. In particular, I'm wondering how to perform the latter function.

Currently, I'm doing this, which I think violates the principles of OOP:

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

The client will never need to change the vector, but how can I still allow the client to iterate through a vector of all of the primes under some number (using things like vector.size()? I've thought about an accessor method that returns the vector by value, but that seems inefficient.

Upvotes: 1

Views: 233

Answers (5)

leftaroundabout
leftaroundabout

Reputation: 120711

Another possibility is do design a special iterator class:

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);}
};

The good thing about this is that the container is now "infinite": primes are calculated lazily as needed, rather than up to a given upper bound.

Upvotes: 1

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361532

I would define the class as:

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 ;
} ;

I think the user of the class should have read-only access to the vector, so I used const_iterator in the typedef definition. Also note that the operator[] is a const member function which means you can only access the value, but cannot modify it.

Usage:

 PrimeSieve sieve(1000); //compute

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

Upvotes: 9

TonyK
TonyK

Reputation: 17114

This is one way to do it:

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

There is no inefficiency here -- returning a reference is at least as efficient as returning a pointer. And the client can iterate through the vector returned by getPrimes (using a const_iterator, naturally).

Upvotes: 6

Alok Save
Alok Save

Reputation: 206546

The basic rule is:
You make the data member private & then provide public/protected member functions to expose the functionality/operations which is provided on the private data member.

You should follow the same rule here.

Upvotes: 1

Cameron Skinner
Cameron Skinner

Reputation: 54346

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

This gives clients access to a const pointer to primes which means they can iterate over it but cannot modify it.

(My syntax may be wrong; it's been a few years since I've done any serious C++)

Upvotes: 1

Related Questions