Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Protected level access to a non-class global function?

50 views
Skip to first unread message

JiiPee

unread,
Feb 17, 2016, 5:58:07 PM2/17/16
to
I have had this many times that I have some global (or static) non-class
function which I want to get access to a certain class but not its
private members. Just to illustrate (not a perfect example..):

class Human
{
public:
string getName();

protected:
int getID() const;

private:
string m_name;
int m_ID; /// humans id
};

So lets say I do not want to expose at all the ID here for some reason.
But I want to give a certain global function access to it:

bool checkHumansLegalStatus(const Human& human)
{
// uses getID...
int id = human.getID();
...
}

So I want only this function to get access to getID but on the other
hand I do not want to make if a friend becouse I do not want it to get
direct acces to the private data members (then it could also get access
to other data members which it does not need). Protected kind of
security would be pretty close what would do the job, but there is no
"protected friend".

What to do? I dont want it to be a friend, to expose ALL privates ...
would be nice if C++ had a "conditional friend" .. so I could say which
members it can get access to , like here.

is there any other way to do this (for a global function)?

Ian Collins

unread,
Feb 17, 2016, 6:06:09 PM2/17/16
to
JiiPee wrote:
> I have had this many times that I have some global (or static) non-class
> function which I want to get access to a certain class but not its
> private members. Just to illustrate (not a perfect example..):
>
> class Human
> {
> public:
> string getName();
>
> protected:
> int getID() const;
>
> private:
> string m_name;
> int m_ID; /// humans id
> };
>
> So lets say I do not want to expose at all the ID here for some reason.
> But I want to give a certain global function access to it:
>
> bool checkHumansLegalStatus(const Human& human)
> {
> // uses getID...
> int id = human.getID();
> ....
> }
>
> So I want only this function to get access to getID but on the other
> hand I do not want to make if a friend becouse I do not want it to get
> direct acces to the private data members (then it could also get access
> to other data members which it does not need). Protected kind of
> security would be pretty close what would do the job, but there is no
> "protected friend".
>
> What to do? I dont want it to be a friend, to expose ALL privates ...
> would be nice if C++ had a "conditional friend" .. so I could say which
> members it can get access to , like here.

In this case, id being (presumably) unique and constant I would make it
a public const member.

Generally, I've never had this issue, it looks like something that
should be addressed in the design. If a friend function only sees a
const version of the objects, what harm can it do?

--
Ian Collins

red floyd

unread,
Feb 17, 2016, 6:12:24 PM2/17/16
to
On 2/17/2016 2:57 PM, JiiPee wrote:
>
> So I want only this function to get access to getID but on the other
> hand I do not want to make if a friend becouse I do not want it to get
> direct acces to the private data members (then it could also get access
> to other data members which it does not need). Protected kind of
> security would be pretty close what would do the job, but there is no
> "protected friend".
>
> What to do? I dont want it to be a friend, to expose ALL privates ...
> would be nice if C++ had a "conditional friend" .. so I could say which
> members it can get access to , like here.
>
> is there any other way to do this (for a global function)?

You might want to look into the "Attorney" class idiom.

http://www.drdobbs.com/friendship-and-the-attorney-client-idiom/184402053

Öö Tiib

unread,
Feb 17, 2016, 7:16:23 PM2/17/16
to
On Thursday, 18 February 2016 00:58:07 UTC+2, JiiPee wrote:
> I have had this many times that I have some global (or static) non-class
> function which I want to get access to a certain class but not its
> private members. Just to illustrate (not a perfect example..):

I have only had such desire with "frozen" code that may not be
changed but that clearly lacks some vital functionality.
The 'private' isn't security. It just avoids accessing by accident
what you don't really want to access. In C++ everything is
accessible when you want to:

#include <iostream>
#include <string>

// frozen class
class Human
{
public:
Human(std::string name, int id)
: m_name(name)
, m_ID(id)
{}

std::string getName() const {return m_name;}

private:
std::string m_name;
int m_ID; /// humans id there are no way to access
};


// robbing template (from Johannes Schaub)
template<typename Tag, typename Tag::type M>
struct Rob
{
friend typename Tag::type get(Tag)
{
return M;
}
};

// preparations to rob Human::m_ID
struct Human_id
{
typedef int Human::*type;
friend type get(Human_id);
};
template struct Rob<Human_id, &Human::m_ID>;


// robbery in action:
bool checkHumansLegalStatus(const Human& human)
{
int id = human.*get(Human_id());
std::cout << "robbed: " << human.getName() << " " << id << '\n';
return id == 42;
}

int main()
{
Human jipee {"Jippee", 42};
return checkHumansLegalStatus(jipee);
}

> So I want only this function to get access to getID but on the other
> hand I do not want to make if a friend becouse I do not want it to get
> direct acces to the private data members (then it could also get access
> to other data members which it does not need). Protected kind of
> security would be pretty close what would do the job, but there is no
> "protected friend".
>
> What to do? I dont want it to be a friend, to expose ALL privates ...
> would be nice if C++ had a "conditional friend" .. so I could say which
> members it can get access to , like here.

I do not actually understand what you want or don't want. The issue may
be that your "class" is getters/setters and its *actual* logic of checking
its invariant is elsewhere outside. IOW design error.

Alf P. Steinbach

unread,
Feb 17, 2016, 8:57:20 PM2/17/16
to
On 2/17/2016 11:57 PM, JiiPee wrote:
> I have had this many times that I have some global (or static) non-class
> function which I want to get access to a certain class but not its
> private members. Just to illustrate (not a perfect example..):
>
> class Human
> {
> public:
> string getName();
>
> protected:
> int getID() const;
>
> private:
> string m_name;
> int m_ID; /// humans id
> };
>
> So lets say I do not want to expose at all the ID here for some reason.
> But I want to give a certain global function access to it:
>
> bool checkHumansLegalStatus(const Human& human)
> {
> // uses getID...
> int id = human.getID();
> ...
> }
>
> So I want only this function to get access to getID but on the other
> hand I do not want to make if a friend becouse I do not want it to get
> direct acces to the private data members (then it could also get access
> to other data members which it does not need). Protected kind of
> security would be pretty close what would do the job, but there is no
> "protected friend".


Apparently you want checkHumansLegalStatus to have the same kind of
access as a function in a derived class would have to members of an
instance of that derived class.

There are many ways, and I would probably just use a `static_cast` with
a little bit of irrelevant formal UB.

But, working entirely within the C++ type system, can go like this:


<code>
#include <string>

namespace zulu {
using std::string;

class Human
{
private:
string name_;
int id_;

protected:
auto id() const
-> int
{ return id_; }

public:
auto name() const
-> string
{ return name_; }

Human( string const& name, int const id )
: name_( name ), id_( id )
{}
};

namespace impl {
class Human_x
: public Human
{
public:
static
auto is_legal( Human const& human )
-> bool
{
int const id = (human.*&Human_x::id)();
return (id == 42);
}
};
} // namespace impl

auto is_legal( Human const& human )
-> bool
{
struct Access: Human
{
static
auto is_legal( Human const& human )
-> bool
{
int const id = (human.*&Access::id)();
return (id == 42);
}
};
return Access::is_legal( human );
}
} // namespace zulu

#include <iostream>
using namespace std;
auto main() -> int
{
zulu::Human const a( "a", 666 );
zulu::Human const b( "b", 42 );

cout << boolalpha << is_legal( a ) << ' ' << is_legal( b ) << '\n';
}
</code>


Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Feb 17, 2016, 8:59:20 PM2/17/16
to
On 2/18/2016 2:56 AM, Alf P. Steinbach wrote:
>

Oh sorry, that `namespace impl` shouldn't be there.

That's what I wrote first, before I moved that class inside the function.

Jeez, why doesn't Thunderbird at least WARN me about these things?


Cheers!,

- Alf

JiiPee

unread,
Feb 18, 2016, 11:30:11 AM2/18/16
to
but we dont need that
class Human_x

it runs without that

JiiPee

unread,
Feb 18, 2016, 11:33:23 AM2/18/16
to
On 18/02/2016 01:56, Alf P. Steinbach wrote:
>
> #include <iostream>
> using namespace std;
> auto main() -> int
> {
> zulu::Human const a( "a", 666 );
> zulu::Human const b( "b", 42 );
>
> cout << boolalpha << is_legal( a ) << ' ' << is_legal( b ) << '\n';
> }
> </code>
>

ok, just compiling and checking... seems to run correctly

JiiPee

unread,
Feb 18, 2016, 11:45:34 AM2/18/16
to
yes, this seems to do the job! Still trying to understand what is
happening here:

int const id = (human.*&Access::id)();

:)

Alf P. Steinbach

unread,
Feb 18, 2016, 6:30:26 PM2/18/16
to
It's quite subtle. Which is why I'd rather use a formally UB
`static_cast`. You can add this declaration:

char* nah = *&Access::id;

to get an idea about it from the compilation error message.
0 new messages