Kevin Meier
Kevin Meier

Reputation: 2580

Access C++ class member object, but do not allow to override it

I'm learning C++ and i just have a small problem. I have a class which contains a vector<int>. From outside this vector<int> should be accessable, so it should be possible to add/remove/get its elements.

It should not be possible to override the object with a new instance. Here is such an example class (it's minimalized):

class MyClass
{
    public:
        vector<int>& vec() { return _vec; }
    private:
        vector<int> _vec;
};

E.g. the following code works:

MyClass x;
x.vec().push_back(0);
x.vec().push_back(7);
x.vec().push_back(9);
cout << c.vec().size() << endl;

But unfortunately the following code also works:

MyClass x;
x.vec() = vector<int>();

I like to disallow this, but i did only find the solution to return a pointer of type vector<int> *. But i learned pointers are 'evil' and i shouldn't use them directly, i have to use smart pointers. I think for this problem a smart pointer is useless, so i don't know how to solve this simple problem:-/

Or is just a simple pointer the cleanest solution?

best regards

Kevin

-edit-

In general i like to make something that can be used like the follwing C# class:

public class MyClass
{
    public List<int> List { get; private set; }

    public MyClass()
    {
        List = new List<int>();
    }
}

It's just an example and i just thought about how to make this in C++. Maybe i some cases i have much more complex classes than vector<int>/List<int> to include into other classes.

But maybe it is only possible to do this by defining own methods (=interface) to the internal object.

Upvotes: 0

Views: 401

Answers (3)

James Holderness
James Holderness

Reputation: 23001

It seems wrong to me that the only acceptable solution is to provide forwarding functions for potentially all the methods in the vector class. So I would like to propose an alternative answer.

Create a small template class publically derived from vector that hides the operator= method by making it private.

template<class T>
class immutablevector : public vector<T>
{
  private:
    immutablevector &operator=(vector<T>);
};

Then in MyClass, wherever you would have used vector, use immutablevector instead.

class MyClass
{
  public:
    immutablevector<int>& vec() { return _vec; }
  private:
    immutablevector<int> _vec;
};

Now you can safely access all vector functionality via the vec method, but you won't be able to assign a new vector instance.

Upvotes: 3

Bok McDonagh
Bok McDonagh

Reputation: 1447

You might want to consider using functions to only expose the functionality you need:

class MyClass
{
public:
    void push_back(int value) { _vec.push_back(value); }
    size_t size() { return _vec.size(); }

private:
    vector<int> _vec;
};

int main()
{
    MyClass x;
    x.push_back(0);
    x.push_back(7);
    x.push_back(9);
    cout << x.size() << endl;

    return 0;
}

Or alternatively just use a plain vector.

Upvotes: 3

dragos2
dragos2

Reputation: 155

It's a bit strange how you use the private identifier. You set your vector<int> as private and then you create a public method that gives direct access to that variable.

You should instead create public methods get() and push_back()

class MyClass{
     private: vector<int> _vec;
     public: 
         vector<int> get(){ return _vec(); }
         void push_back(int x) { _vec.push_back(x); }
};

//this will work
MyClass x;
x.push_back(0);
x.push_back(7);
x.push_back(9);
cout<<x.get().size()<<endl;

Now there is not way you to directly modify the private variable vector<int> _vec. Keep in mind you will probably need to instantiate _vec in MyClass's constructor.

Upvotes: 3

Related Questions