PrOpoLo
PrOpoLo

Reputation: 113

Removing constness from reference returned by const accessor method versus adding a non-const accessor method

Let's consider the following code:

Class MyVeryAccessibleClass
{
public:
    const std::vector<int>& getVect() const {return vect_m;};
private:
    std::vector<int> vect_m;
};

Class MyInitClass
{
   MyInitClass() : importantInt_m{10}{};
   void init();
protected:
    int importantInt_m;
};

My project is built in a way that it has to be MyInitClass::init() that initializes or modifies MyVeryAccessibleClass::vect_m.

Some other classes will also have access to MyVeryAccessibleClass::vect_m but I don't want them to be able to modify it, they should only be able to read it.

I thought of 2 solutions:

  1. Casting away the constness of getVect() in init (and only there). This is the solution I am leaning towards, but I've read that const_cast should be avoided so I am not sure this is correct:
MyInitClass::init()
{
   MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
   auto vect_l& = const_cast<std::vector<int>&> (class_l ->getVect());
   vect_l.push_back(importantInt_m);
}
  1. Adding a non-const accessor to MyVeryAccessibleClass. I don't really like this solution because it means that if in another part of the code I use a pointer to MyVeryAccessibleClass, it will call the non-const accessor, and this accessor should only ever be used in MyInitClass::init()
Class MyClass
{
public:
    const std::vector<int>& getVect() const {return vect_m;};
    // I've read that I could also call the const accessor from here, but that is not really the point
    std::vector<int>& getVect() {return vect_m;}; 
private:
    std::vector<int> vect_m;
};

MyInitClass::init()
{
   MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
   auto vect_l& = class_l ->getVect();
   vect_l.push_back(importantInt_m);
}

MyOtherClass::doStuff()
{
   MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
   // I don't want that. 
   // I guess one could precise const auto vect_l& to call the const accessor or use the new std::as_const
   // But not everybody is familiar with that and I felt like I should not even allow the possibility of making a mistake
   auto vect_l& = class_l->getVect();
   // Mistake far less obvious than this one but that modifies the vector:
   vect_l.push_back(15);
}

Is there a better solution that I didn't think of ? And if not, should I go with solution 1 or solution 2 ? My sentiment was that since I only ever want to modify MyVeryAccessibleClass::vect_m in MyInitClass::init, it was OK to do a const_cast there and not have a non-const accessor in MyVeryAccessibleClass.

Upvotes: 1

Views: 109

Answers (1)

Shreyan Avigyan
Shreyan Avigyan

Reputation: 183

You can declare your class MyInitClass as a friend of MyVeryAccessibleClass.

Let's see the code in action.

class MyVeryAccessibleClass
{
    friend class MyInitClass;
private:
    const std::vector<int> vect_m;
}

Now Let's look at the MyInitClass constructor.

MyInitClass::init()
{
   MyVeryAccessibleClass* class_l = methodToGetMyVeryAccessibleClassInOneWayOrAnother();
   auto vect_l& = class_l->vect_l;
   vect_l.push_back(importantInt_m);
}

Upvotes: 1

Related Questions