|
[ From Pompi Dev Blog ]
Here is a neat little way I found to make one class access the privates of another class, without using friend or direct inheritance. Take a look at this code:
class A {
public:
class Observer {
protected:
int GetPrivate(A & a) {return a.ValueA;};
};
private:
int ValueA;
};
class B: public A::Observer {
public:
void Foo (A & a) {
Do something with GetPrivate(a);
}
};
Class B cannot access the privates of class A directly, but it inherits a subclass of A that can access the privates of A given as a parameter. Since I have just tried this "pattern" recently, I am not sure what is the direct benefit of this.
I believe a benefit can be in the sense of making a programmer's life easier. Programming languages play several parts. They provide us powerful functionality, but they also suppose to give us ease of use. You can program anything on assembly, but it would be really difficult to write a big game in assembly. If you do not expose privates via a getter, you give the programmer one less method to think about when he need to use the class's instance for something.
Can you think how you would use this "pattern"? Do you think there is no use for it? Tell me what you think.
|
By the way, some of us *have* written "big game[s] in assembly".
You youngsters don't even know you're born. ;)
It's a cute trick Ofer, it allows more granularity for exposing internals than the all-or-nothing "public, private or friend", since you can write multiple Observers for different sets of private members. Most programmers won't be anal enough to want to use it, but it's there for the taking.
but i prefer this:
class A {
private:
class Observer {
public:
Observer(A &refA) : refA(refA) {}
int GetPrivate() { return refA.v; }
private:
A &refA;
};
public:
Observer GetObserver() { return Observer(*this); }
private:
int v;
};
i'm not sure why the subclass B is necessary.
Michael C, I don't completly follow your example, but I think it is equivalent to having a public getter of the private variable.
The trick I showed allows to expose part of the internals(friend expose all the internals) to part of the classes(getter expose it to everything).
Of course you could work around it, but a programming language is not all about functionality, it's also about concepts, abstraction and informality.
This is how I understand it.
Paul, sometimes you have two classes which can't inherit each other, but you want to access each other's privates.
I have thought about it more, I think this is useful. In the sense that 'private' is useful. You could write a program without any private members, right? If you take any existing C++ program, and replace all 'private:' with 'public:', the program will still compile and have the same functionality. But will it be the same?
i'm more curious about what you originally intended. i guess i was thinking about it invertedly -- providing restricted access when the default is read/write. but it seems like providing direct read access to private members is rep. exposure, which is dangerous. i'm curious whether you have any specific cases where to use this.
class EntityInterface
{
public:
EntityInterface() { }
virtual ~EntityInterface() { }
virtual int GetHealth() const = 0;
};
class Entity : public EntityInterface
{
public:
Entity( const int& aHealth = 25 ) : health( aHealth ) { }
~Entity() { }
protected:
int GetHealth() const { return health; }
private:
int health;
};
class Frog
{
public:
Frog() { }
~Frog() { }
int GetHealth( const EntityInterface& entity )
{ return entity.GetHealth(); }
};
#include
using namespace std;
int main()
{
Entity entity;
Frog frog ;
int health = frog.GetHealth( entity );
cout << health << endl;
return 0;
}
What is important to say is, there is no holy grail here. I suggested to do something in a specific way. There are many ways to do the same thing in programming. Usually there is no one way which is better than all other to all the situations.
Coding is also a matter of convineice rather than just functionality. Eventually, you should choose what you feel comfortable with.
I came across this "pattern" when I wanted to wrap two DX interface, in which I had to call the private of one class with the private of the other class as a parameter. This is the context I thought about this.
Again, you write code not only for the computer, you also write it in a way that will be easy for you to handle it.
This is because the observer pattern is a different pattern all together used mainly for callbacks in input handlers etc...
I think an alternative is to have 2 classes one called Accessor and the other called Mutator and then only inherit whatever is required depending on the situation.
The other problem I see is if you have one class that needs access to 2 separate Accessor classes then the syntax is not as simple due to ambiguity.
ie:
class A {
public:
class Accessor {
protected:
int GetPrivate(const A& a) const {return a.ValueA;};
};
private:
int ValueA;
};
class B {
public:
class Accessor {
protected:
int GetPrivate(const B& b) const {return b.ValueA;};
};
private:
int ValueA;
};
class C: public A::Accessor, public B::Accessor {
public:
void Foo (A & a) {
cout << A::Accessor::GetPrivate( a );
}
void Foo(B & b) {
cout << B::Accessor::GetPrivate( b );
}
};
Yea, I guess observer wasn't the best name. Also, you don't have to call the method GetPrivate, it was a name I picked because class A had no actual meaning. But specifying the classes to differentiate between the accessors can also work. Like you did.
Thanks.