Home > Enterprise >  class members with different read-only and writable states in different classes
class members with different read-only and writable states in different classes

Time:12-02

i would like a class with some members, that each member can changes in a particular class (each member to have two different states in two different classes, writable and read-only). What is the best way to implement the following problem?

class myRepository 
{
        ... 
        int writableIn_A;
        int writableIn_B;
        ...
};
myRepository repository; 
class A
{
    ...
    void f_A()
    {
        cout << repository.writableIn_A; //ok
        cout << repository.writableIn_B; //ok

        repository.writableIn_A = 10; //ok
        repository.writableIn_B = 20; //compile error
    }
    ...
};
class B
{
    ...
    void f_B()
    {
        cout << repository.writableIn_A; //ok
        cout << repository.writableIn_B; //ok

        repository.writableIn_A = 10; //compile error
        repository.writableIn_B = 20; //ok
    }
    ...
};

CodePudding user response:

You could make writableIn_A and writableIn_B into member functions that return proxy objects. These objects could then be friends with A and B resp.

#include <utility>

template <class T, class U>
class FriendOf {
public:
    friend T;

    explicit FriendOf(U& r) : i(&r) {}

    operator const U& () const { return *i; }

private: // only available to friends:
    template<class V>
    U& operator=(V&& v) {
        *i = std::forward<V>(v);
        return *i;
    }
    U* i;
};

Then return instances of these proxy objects:

class A;
class B;

class SingletonRepository {
public:
    static SingletonRepository& getInstance() {
        static SingletonRepository ins;
        return ins;
    }

    auto writableIn_A() { return FriendOf<A,int>(m_writableIn_A); }
    auto writableIn_B() { return FriendOf<B,int>(m_writableIn_B); }

private:
    SingletonRepository() = default;
    int m_writableIn_A = 0;
    int m_writableIn_B = 0;
};

And the usage will be pretty similar to what you wanted:

class A {
    void f_A() {
        std::cout << SingletonRepository::getInstance().writableIn_A();  // ok
        std::cout << SingletonRepository::getInstance().writableIn_B();  // ok

        SingletonRepository::getInstance().writableIn_A() = 10;  // ok
        // SingletonRepository::getInstance().writableIn_B() = 20;  // error
    }
};
class B {
    void f_B() {
        std::cout << SingletonRepository::getInstance().writableIn_A();  // ok
        std::cout << SingletonRepository::getInstance().writableIn_B();  // ok

        // SingletonRepository::getInstance().writableIn_A() = 10;  // error
        SingletonRepository::getInstance().writableIn_B() = 20;  // ok
    }
};

Demo

CodePudding user response:

The issue is completely unrelated to Singleton. To restrict access you can make things private and to grant a specific class access to the private parts you can make it a friend. For finer control of access of individual members you can inherit from base classes that manage access of only their members:

#include <iostream>

class friend_of_A {
    int x = 0;
    friend struct A;
    public:
    int get_x() { return x; }
};

class friend_of_B {
    int y = 0;
    friend struct B;
    public:
    int get_y() { return y;}
};

struct TheClass : friend_of_A , friend_of_B {

};

struct A {
    A(TheClass& c) {
        std::cout << c.get_x() << c.get_y();
        c.x = 42;
        //c.y = 42; // ERROR
    }
};

struct B {
    B(TheClass& c) {
        std::cout << c.get_x() << c.get_y();
        // c.x = 42;  // ERROR
        c.y = 42;
    }
};

With another layer, you could even grant access only to a int& get_x() for write-access while the member itself can be hidden completely. And perhaps the members in the bases should be protected or TheClass be made a friend as well.

  •  Tags:  
  • c
  • Related