TheWaterProgrammer
TheWaterProgrammer

Reputation: 8229

C++ : How to ensure that a class member variable is modifiable only within a certain method

I am using C++ 14 with clang on MacOS Sierra. I want to enforce a rule by design. Following is the rule.

I have a member variable in my class say:

unsigned int m_important_num;

There are 4 methods in my class.

fun1();
fun2();
fun3();
fun4();

Objective:
I want only fun2() to be able to change the value of m_important_num.

Question:
Is it possible to make it compiler error if any method other than fun2() changes the variable? One possible way is to declare it const somehow empower fun2() to change const variables? Is this a good solution? Or are their any better solutions?

Secondary question:
Is it a wrong design to try do such a thing?

Upvotes: 6

Views: 3017

Answers (6)

Andriy Tylychko
Andriy Tylychko

Reputation: 16256

You already got lots of good answers to your primary question. I'll try to address the secondary one.

Is it a wrong design to try do such a thing?

It's hard to say w/o knowing more about your design. In general anything like this detected during a code review would raise a big red flag. Such a protection makes sense in a case of a big class with convoluted logic/implementation. Otherwise why would you like to go an extra mile and make your code much more complicated? The fact you seek for this can indicate your class became unmanageable.

I'd recommend to consider splitting it to smaller parts with better defined logic where you won't worry such mistakes can happen easily.

Upvotes: 1

cantordust
cantordust

Reputation: 1612

I know there are lots of good answers, but there is also an option that you sort of alluded to in your question:

One possible way is to declare it const somehow empower fun2() to change const variables?

#include <iostream>

using uint = unsigned int;

class Test
{
    const uint num;

public:

    Test(uint _num)
        :
          num(_num)
    {}

    uint get_num() const
    {
        return num;
    }

    void can_change_num(uint _new_num)
    {
        uint& n(const_cast<uint&>(num));
        n = _new_num;
    }

    void cant_change_num(uint _new_num)
    {
//      num = _new_num; // Doesn't compile
    }

};

int main()
{
    Test t(1);

    std::cout << "Num is " << t.get_num() << "\n";

    t.can_change_num(10);

    std::cout << "Num is " << t.get_num() << "\n";

    return 0;
}

Produces

Num is 1
Num is 10

Upvotes: 1

max66
max66

Reputation: 66200

I little variant (if I understand correctly) of the Jeffrey solution: put the variable in an inner class and make it private; create a public getter and make func2() friend to the inner class.

I mean

struct foo
 {
   int f1 () { return b0.getVal(); }; // you can read `val` everywhere
   void f2 () { b0.val = 42; }; // you can write `val` in f2()
   void f3 () { /* b0.val = 42; ERROR ! */ }; // but only in f2()

   class bar
    { 
      private: 
         int val = 24;

      public:
         int getVal () { return val; }

      friend void foo::f2 ();
    };

   bar b0;
 };

In other words: friend is your friend.

Upvotes: 2

Jarod42
Jarod42

Reputation: 217135

Sort of, with additional layer:

class S1 {
public:
    void fun2() { /*Modify m_important_num */ }
    unsigned int getImportantNum() const { return m_important_num;}
private:
    unsigned int m_important_num;
};
class S2 : private S1
{
public:
    void fun1();
    using S1::fun2; // or void fun2() {S1::fun2();}
    void fun3();
    void fun4();
};

As Yakk commented, if func2 need access to S2 members, CRTP can solve that:

template <typename Derived>
class S1 {
public:
    void fun2() { asDerived().foo3(); /*Modify m_important_num */ }
    unsigned int getImportantNum() const { return m_important_num;}
private:
    Derived& asDerived() { return stataic_cast<Derived&>(*this); }
private:
    unsigned int m_important_num;
};
class S2 : private S1<S2>
{
    // friend class S1<S2>; // If required.
public:
    void fun1();
    using S1::fun2; // or void fun2() {S1::fun2();}
    void fun3();
    void fun4();
};

Upvotes: 11

Everyone
Everyone

Reputation: 1825

If you want to prevent a method from modifying any member in the class you can use the trailing const identifier:

class something{
private:
  unsigned int var;

public:
  void fun1() const;
  void fun2();
  void fun3() const;
  void fun4() const;     
}

Here, only fun2() will be able to modify the variable.

Upvotes: 1

Jeffrey
Jeffrey

Reputation: 11400

Encapsulate it down. Put m_important_num in its own class. Aggregate it in your existing class. Have a getter for it. Then put fun2() as a member function of your inner class.

Upvotes: 10

Related Questions