Give access to a class to a private member of another class

3

I have a class to call class A that contains an object of class B .

class A{
  B objeto_b;
};

I need that A can access a private method of class B . Why do I want it to be private then? Because that method I only want to be invoked from a method of the class A , and not that it is public and that it can be invoked by any other part of my program.

Why do not I make the class a friend? Because I just need to guarantee access to that method, not the rest of the private fields.

What solution do you propose?

    
asked by candidatopardo 10.04.2018 в 19:24
source

3 answers

2

The solution would be to use friend , but you have to be careful, because when using friend we create a coupling between classes that is brutal (more coupling than inheritance) ... and also makes it easier for someone to access directly to the variables member of a class skipping all the protections had and for having.

For cases like this I usually resort to an intermediate class that gives me access to what I want and nothing more:

template<class T>
class PassKey
{
  friend T;

  PassKey() = default;
  PassKey(PassKey const&) = default;

  PassKey & operator=(PassKey const&) = delete;
};

Simple class more than can not ... it has neither state nor functions ... it only has the base constructor and the copy constructor enabled and they are private above ... How to use it?

The key is in the friend that you have inside. This class can only be created by type T , which will be the type to which we want to give access to a function of another class:

class B
{
public:
    void funcionProtegida(PassKey<A>)
    { }
};

class A
{
public:

  void Func()
  { objeto_b.funcionProtegida(PassKey<A>{}); }

private:
  B objeto_b;
};

This code compiles, whereas if another class tries to call funcionProtegida the compiler will not leave it:

class C
{
public:

  void Func()
  {
    objeto_b.funcionProtegida(PassKey<A>{}); // Error: PassKey<A>() es un constructor privado
    objeto_b.funcionProtegida(PassKey<C>{}); // Error: No se puede convertir de PassKey<C> a PassKey<A>

  }

private:
  B objeto_b;
};

The main advantages of this system are:

  • you get a very expressive code ... in the function itself you see that it has an access requirement, as well as who can access it.
  • The use of friend is restricted to an empty class, which generates very little coupling
  • Easily reusable system

Cons:

  • Understanding how the template works can take a few minutes
answered by 11.04.2018 / 08:36
source
3

You can execute a private function of B using a pointer to that function; the complication consists of obtaining the pointer in itself since when pointing to a private data you can not access either. For that you can make a single friendly function whose definition is not accessible more than from A :

A.hpp
#include "B.hpp"

struct A {
    void f(); // Función que accede a una función privada de B
private:
    B objeto_b;
};
B.hpp
struct B {
    using Bfp = void (B::*)(); // Atajo al tipo de función void() de B
private:
    friend Bfp dame_acceso(); // Función amiga
    void f(); // Función privada de B
};

The object B has a single function as a friend, so no type of access is granted to A ; function dame_acceso returns a function pointer void B::() but has no definition. We will hide the definition of dame_acceso in the code file of A :

A.cpp
#include "A.hpp"

// Esta definición sólo es visible aquí
B::Bfp dame_acceso() {
    return &B::f;
}

void A::f() {
    // Llamamos la función privada de B a través del puntero a función
    (objeto_b.*dame_acceso())();
}

Since the definition of dame_acceso is in the code file of A , the definition will not be visible to other classes and other classes will not be able to obtain the private function pointer of B . If you try to define another dame_acceso in another translation unit, the program will fail to link.

You can see this example working in Wandbox 三 へ (へ ਊ) へ ハ ッ ハ ッ .

Another idea.

The pointer to member function is extremely complicated, you can achieve the same with less code by passing a reference to B to dame_acceso :

A.hpp
#include "B.hpp"

struct A {
    void f(); // Función que acceder a una función privada de B
private:
    B objeto_b;
};
B.hpp
struct B {
private:
    friend void dame_acceso(B &); // Función amiga
    void f(); // Función privada de B
};
A.cpp
#include "A.hpp"

// Esta definición sólo es visible aquí
void dame_acceso(B &b) {
    b.f();
}

void A::f() {
    // Llamamos la función privada de B a través del puntero a función
    dame_acceso(objeto_b);
}
    
answered by 11.04.2018 в 10:45
1

The solution using access modifiers is to use the friendly switch, but not between classes A and B but between a method of class A and class B . In this way, only the method will be a friend of class B having access to its attributes and other methods, but the rest of class A will not have access to B, as well as other external classes.

For example (using Visual Studio C ++, which is what I have on hand):

#include "stdafx.h"
#include "iostream"

using namespace std;

class B;

class A
{
public:
    A();
    int RestaA(B);//Este es el método que utilizaremos para acceder al método de B
};


class B
{
public:
    B(int parametroNumero1 = 0, int parametroNumero2 = 0) : numero1(parametroNumero1), numero2(parametroNumero2) {}
private:        
    int numero1;
    int numero2;
    int RestaB()//Este es el método B, es privado por lo que no es accesible por ninguna clase      
    {
            return numero1 - numero2;
    };
    friend int A::RestaA(B b);//Declaramos como amigo el método RestaA, por lo que ahora solo este método puede acceder a los atributos y métodos de B
};


int A::RestaA(B b)
{
    return b.RestaB();//Podemos ejecutar sin problema el método RestaB de B
}

int _tmain(int argc, _TCHAR* argv[])
{

    A a;
    B b(25, 10);
    cout << a.RestaA(b) << endl; //Ejecutamos el método RestaA de la clase A el cual internamente ejecuta el método RestaB de la clase B.

    return 0;
}

In this way, we keep class B private and its implementation hides the other classes including class A, except for the RestaA method of that class because it is a friend.

    
answered by 11.04.2018 в 00:08