0

I have a class let us call it Person:

class Person{
private:
    void move(x,y,z);
}

I have another class called PersonController:

class PersonController{
public:
    void control(){
        while(some_thing){
             //do some calculations
             controlled_person_->move(some_values); //Wrong Accessing to a private member
        }
    }
private:
    Person* controlled_person_;
}

Both Person and PersonController are part of the public interface of the library I am designing.

I want PersonController to be able to call move from Person. However, I do not want anyone to access this function (move) from the public interface.

The easy way to sovle the problem is add a friendship so PersonController can access private members of Person. However, as far as I read the friend keyword was not introduced to solve these kind of problems and using it here would be a bad practice.

  • Is this correct? Should I avoid friend here?
  • Does this mean my design is broken?
  • Any alternative suggestions?
Humam Helfawi
  • 19,566
  • 15
  • 85
  • 160
  • 1
    Are those classes part of the same logical interface? Meaning, you can't have a `Person` without a `PersonController`? – StoryTeller - Unslander Monica Dec 17 '17 at 20:44
  • No, you can have a `Person` without a `PersonController` – Humam Helfawi Dec 17 '17 at 20:45
  • Your first two questions are unanswerable in SO's format. Should you avoid it? Who knows. It may be the simplest and most correct solution, depending on your entire design. Allow me to reverse the tables on this. Is there anything inside `Person` that `PersonController` should not be allowed to touch? – StoryTeller - Unslander Monica Dec 17 '17 at 20:52
  • Yes of course. Person Name for example is something that it should not be touched. PersonController is just a movement controller. – Humam Helfawi Dec 17 '17 at 20:54
  • 2
    @HumamHelfawi, I think there is a design error you are trying to overcome with `friend`ship. I am guessing the function `Person::move` moves an object to a new location. That means a `Person` has location. Ideally, that does not sound like intrinsic data of `Person`. Can you you decouple those concepts so that a different class is responsible for tracking locations of `Person`s? You can use that class to move a `Person`. – R Sahu Dec 17 '17 at 20:58

3 Answers3

5

From what you said in comments, it seems you are interested in only allowing PersonController to touch that one member function. The way to do that and only that, is to make the door public, but add a private key for it:

class Person{
public:
    class MovePrivilege {
        move_privilege() = default; // private c'tor
        friend class PersonController; // only PersonController may construct this
    }; 

    void move(MovePrivilege, x,y,z);
};

class PersonController{
public:
    void control(){
        while(some_thing){
             //do some calculations
             controlled_person_->move(MovePrivilege{} , some_values);
        }
    }
private:
    Person* controlled_person_;
};

The type MovePrivilege has a private c'tor. So it can only be constructed by its friends. And it is also required for calling move. So while move is public, the only classes that may call it are the friends of MovePrivilege.

This essentially gives you a fine grained control over who may call move. If this is obtrusive and you can't change move itself, a variant of the attorney client idiom may be appropriate instead.

You do have options at your disposal. Direct firend-ship is just the bluntest tool.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
1

That is exactly the sort of problem that friend is meant for. While friendship should be minimized if your design needs it there is no reason not to use it.

I see non-use of friend a lot like the continuing dislike of 'goto', there are simply times where using it will make a design far cleaner.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
-1

Yes your design is not correct.

Classes are an expanded concept of data structures: like data structures, they can contain data members, but they can also contain functions as members. You can read more here

So PersonController (If it only control person class) should not be a class because it is not concept of data structures Check if it is possible to merge them or design another way.

There are many ways to do it.If you want to design it like what you do now you can use protected access controller for your function and Create derived class but it's not a good design again.

You can use friend function here too but it isn't an object oriented concept again(But the easiest way).

You should rethink about your design if you want to design it OO.Because you can't access private function from other class in object oriented programming ,It breaks encapsulation so C++ won't let you do that.

However your question depends on opinions too.

M4HdYaR
  • 1,124
  • 11
  • 27
  • 1
    Not sure why this answer has been downvoted. I agree with the argument that the data and the methods that act on it should be part of the same type. Having "-er" ending type names is a code smell that indicates procedural programming rather than object oriented design. – Kerri Brown Dec 17 '17 at 23:46
  • @MoonMoo I'm not sure too :)) – M4HdYaR Dec 18 '17 at 07:03