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 friend
s 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
}
};
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.