Why does this code compile? - c++

What are the exact rules for deciding the access rights for the objects nested into the private sections of other objects?
For example, in the code snipped below, the proxy_t struct is nested into the private section of the abc_t, and yet its methods are available to the main function. Why does it compile at all?
#include <iostream>
#include <valarray>
using namespace std;
class abc_t{
private:
struct proxy_t{
proxy_t operator()(double& a, double& b){ __a=a; __b=b; return *this; }
double a(){ return __a; }
double b(){ return __b; }
private:
double __a, __b;
};
public:
abc_t( const size_t N ){
_a.resize(N,-101.);
_b.resize(N,-202.);
}
double a(size_t j){ return _a[j]; }
double b(size_t j){ return _b[j]; }
proxy_t operator[](const size_t j) { return _proxy(_a[j],_b[j]); }
private:
valarray<double> _a;
valarray<double> _b;
proxy_t _proxy;
};
int main(){
size_t n_elem=10;
abc_t abc(n_elem);
cout<<"direct: "<< abc.a(1)<<" "<<abc.b(1)<<"\n";
cout<<"proxied:"<<abc[1].a()<<" "<<abc[1].b()<<"\n"; // ain't proxy_t::aa() private?
//cout<<abc[1]; // doomed to fail
}

This line is the important one that I'm gonna talk about:
cout<<"proxied:"<<abc[1].a()<<" "<<abc[1].b()<<"\n";
When you call abc[1], this is a public method of abc_t. This is valid.
It returns a proxy_t. Although the declaration of this class (proxy_t) is not defined, you aren't actually using that return variable to create a new object. If you were to do the following, it wouldn't compile.
proxy_t p = abc[1];
It crashes with that because proxy_t is being declared, you are initializing a new object, however that type doesn't exist in that scope. Since you aren't actually declaring any variables of that type, nothing of proxy_t is being created in that scope (which would be illegal).
By proxy_t being private, that simply means you can't create any objects of that type anywhere except from within the abc_t class. However, it's being passed as a return value, which is valid -- no objects are being created/instantiated/declared, just an existing one is being passed.
Then the fun part. With classes, everything by default is private (unless specified otherwise). With structs, everything by default is public. Therefore, proxy_t::a() is public, and therefore CAN be used in main because main happens to have access to a proxy_t object.

You have defined the struct proxy_t as private, but the actual methods it exposes are public. My guess is that your compiler will not allow you to directly instantiate a proxy_t struct in main, but if you return one from class abc_t, it will allow you to call public methods on it.
Perhaps someone who knows the C++ standard can comment if this is correct behaviour for a compiler or not.

You're saying abc[1].a() which says go here:
proxy_t operator[](const size_t j) { return _proxy(_a[j],_b[j]); }
which is public and throws that 1 in for j. Then it returns
_proxy(_a[j],_b[j])
which is calling the private struct that you use to access the a() function

Since proxy_t is a private member to abc_t, no one except abc_t can use it (i.e. instantiate objects of this type). However, given an existing proxy_t, everybody can invoke its members - because they are public.
The standard is a bit dull here (or I'm looking at the wrong place), but this is my best finding (11.8):
A nested class is a member and as such has the same access rights as any other member. The members of
an enclosing class have no special access to members of a nested class; the usual access rules (Clause 11)
shall be obeyed.
Reading between the lines: Since a nested class is 'just' a member, usual access control is applied when somebody refers to this type (i.e. spells out proxy_t). But for access to members of proxy_t itself, no special access rules apply - if you managed to get a proxy_t object from a privileged source, you can access its members as if it wasn't a nested class.

Related

Accessing private struct of a class using auto

I discovered that next weird code compiles and runs (on VS 2019):
#include <iostream>
class Test
{
private:
struct Priv
{
int a;
};
public:
static Priv WeirdFunc() {return {42};};
};
int main()
{
auto val = Test::WeirdFunc();
std::cout << val.a;
}
Output is 42, no problems here.
The issue I see is that auto keyword allows us to access private structure "Priv".
If I try to replace auto with Test::Priv I get compile error, as expected.
From the articles on the internet I found out that you can have to use auto for lambdas, but this case was never mentioned.
Also, if I try to output "Test::WeirdFunc().a" it also works
So my questions are:
Is it expected behaviour for auto to let us access private structures/classes?
Is it allowed to declare public function that returns private structure?
Is it expected behaviour that we can access private structures/classes if it's return value of function (e.g. "Test::WeirdFunc().a")?
All of that is obviously terrible code style, but I'm curious about whether it's valid c++ code or not
The result of Test::WeirdFunc() is a Priv. This is also the auto-deducted type of val. The auto keyword removes the necessity to name the type of val to be Priv and therefore, the compiler does not complain. As a result, val is of (unmentioned) type Priv and has a public member a, that can be accessed freely.
So the answers to all your questions is: Yes, (as long as you don't "mention" the name of the nested class).
See also: cpp reference on nested classes
So my questions are:
Is it expected behaviour for auto to let us access private structures/classes?
Yes.
Is it allowed to declare public function that returns private structure?
Yes.
Is it expected behaviour that we can access private structures/classes if it's return value of function (e.g. Test::WeirdFunc().a)?
Yes.
All of that is obviously terrible code style, ...
No, not necessarily. Think about e.g. a container class, which defines iterator classes as internal nested types:
class Container {
class iterator {
public:
iterator operator++();
iterator operator++(int);
};
public:
iterator begin();
iterator end();
};
This allows to access the iterator's instances and operations via auto, but not to directly create instances from outside the class.
You have a public interface which exposes a type by means of the type of return value of the public interface. This essentially means your API design exposes private details of the class, and this is not an issue of the C++ language features but of the API design. Note that this doesn't just apply for auto:
using A = decltype(Test::WeirdFunc()); // A is Test::Priv.
A a{}; // well-formed.
It's valid, and here's why:
Access specifiers control access to names.
So, you have no access to the name Priv, but that doesn't mean you have no access to the type it's referring to. And there are other ways to "get to it", such as by using auto.
This is not as crazy as you might think. After all, you can't do any damage with it: if you don't want public things returning instances of "private types" (which aren't, really, but that's fine) then simply don't do that thing.

Why == overloading can access private members of argument [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
why private value of the obj can be changed by class instance?
Consider the following (partial) code:
class Group {
private:
int id;
public:
void set_id(int);
int get_id();
bool operator==(const Group&);
};
bool Group::operator==(const Group& g) {
if(g.id == this->id) { /* id is private? */
return true;
}
return false;
}
The code compiles and results seem proper. However, in the if part of the operator overloading implementation, we are directly accessing the private member of its argument - const Group& g, but isn't such an access invalid?
Your operator== is a member of your Group class. Member functions can access any private members of that class, not only for this, but for any instance they can access.
If you think about it this behaviour is necessary, because otherwise access control would make methods for interaction of two or more instances (swap, copy constructors, operators) impossible, unless the object has a public accessor to any member variable, which is used in such a method. Often enough that isn't desirable from a design point of view. Furthermore it would raise the bar for access control to high ("if I simply make that member public, I can spare me the pain...").
Concluding this code is perfectly valid (although I don't see why the if is necessary, compared to simply using return g.id == this->id;)
Access qualifiers are not controlling access on the instance level, but on the type level. Any member function of a instance of type T can access all the private members of any other instance of the very same type T.
Since the operator== is a member function it can access all the member variables of instances of the class it's member of.
No, because operator== is a member of Group. It's right there in the function name. That means it can access the private members of any object of that class.
If you tried to write it as a free function, that would not have compiled:
bool areEqual(const Group& g1, const Group& g2) {
return g1.id == g2.id;
}

Can a friend function change private data in the class?

I would like to know if a friend function can change private data in the class without using a
pointer and sending out the object.
I mean does a friend function have access like a member function?
For Example:
class myinfo {
private:
char name[20];
int id;
float income;
public:
void showInfo(void);
myinfo(void);
friend void updateInfo(myinfo);
int main ( ) {
myinfo j;
updateInfo(j); // calling the friend function
return 0;
}
void updateInfo(myinfo c) {
strcat(c.name, ":updated");
c.id++;
c.income += 1.1;
Yes, but not the way you've written it... If you want the function to modify the passed in object, accept a reference rather than by value...
It appears you've not learned about references in c++.
// Declaration of function in class
friend void updateInfo(myinfo&);
implementation
void updateInfo(myinfo& c)
{
strcat(c.name, ":updated"); // now modifying passed in instance of c.
c.id++;
c.income += 1.1;
}
Btw. on a side note, prefer to use std::string and also learn about rule of three (specially for non-trivial classes such as this).
Yes, In principle, private and protected members of a class cannot be accessed from outside the same class in which they are declared. However, this rule does not affect friends.
Friends are functions or classes declared with the friend keyword.
If we want to declare an external function as friend of a class, thus allowing this function to have access to the private and protected members of this class, we do it by declaring a prototype of this external function within the class, and preceding it with the keyword friend.
See it here - http://www.cplusplus.com/doc/tutorial/inheritance/

c++ why doesn't a copy of an object allow access to a private variable of the original?

For example,
Number operator+(Number a, Number b) {
return Number(a.x + b.x);
}
Would this cause some kind of "unable to access private member error". I understand that if I don't pass by reference, the Number a, and Number b are copied on the stack and used in the body of the function. However, I don't see why they do not allow access to the originals' private members. How am I misunderstanding the concept of an object? Also how come friend and member function don't need to pass by reference?
operator+ is an unbound function, i.e. it is not a member of Number so, this is the rule, it has no implicit access to private members.
The rule is not affected by you passing Number objects by value or by reference. Access protection is applied to every access to a Number object, even if it is your private, stack-based copy.
There are at least three ways out:
declare Number operator+(Number, Number) a friend of Number
add a public getter for x so the variable is accessible.
implement the += operator as a member of the class and implement the free operator in terms of it: return Number(a) += b;
You're definitely misunderstanding something. 'Pass by reference', 'copied on stack' etc. have absolutely nothing to do with the access rules.
The code above is an error because operator+ is not a member of Number, and (presumably) it's not a friend of Number either. So it cannot access private members. That's all there is to it.
As many have answered operator + is not a member of Number class, it is a global variable. Consider a function Show:
void Show(const Number& numberObj) // const, by-ref is IMMATERIAL
{
std::cout<< numberObj.x;
}
and a method Show:
class Number
{
private:
int x;
public:
void Show()
{
std::cout << x;
}
};
Now, if you replace Show with any overloaded operator, taking 1 or 2 arguments - only the class-member can access the private data, and global implementation cannot.
For this, you need to make global Show a friend of class (in class declaration), and likewise any globally implemented operator.

boost::bind with protected members & context

In the below code, there are two "equivalent" calls to std::for_each using boost:bind expressions. The indicated line compiles, the indicated failing line fails. The best explanation I can find in the standard amounts to "because we said so". I'm looking for "why the standard indicates this behavior". My suppositions are below.
My question is simply: Why does the indicated line compile and the equivalent following line fail to compile (and I don't want because "the standard says so", I already know that - I will not accept any answers that give this as an explanation; I'd like an explanation as to why the standard says so).
Notes: Although I use boost, boost is irrelevant to this question, and the error in various formats has been reproduced using g++ 4.1.* and VC7.1.
#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <algorithm>
class Base
{
protected:
void foo(int i)
{ std::cout << "Base: " << i << std::endl; }
};
struct Derived : public Base
{
Derived()
{
data[0] = 5;
data[1] = 6;
data[2] = 7;
}
void test()
{
// Compiles
std::for_each(data.begin(), data.end(),
boost::bind(&Derived::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
// Fails to compile - why?
std::for_each(data.begin(), data.end(),
boost::bind(&Base::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
}
std::map<int, int> data;
};
int main(int, const char**)
{
Derived().test();
return 0;
}
The indicated line fails with this error:
main.C: In member function 'void Derived::test()':
main.C:9: error: 'void Base::foo(int)' is protected
main.C:31: error: within this context
As noted, the supposedly equivalent statement above compiles cleanly (and if the offending statement is commented out, runs with the expected result of printing “5”, “6”, “7” on separate lines).
While searching for an explanation, I came across 11.5.1 in the standard (specifically, I’m looking at the 2006-11-06 draft):
An additional access check beyond
those described earlier in clause 11
is applied when a non-static data
member or nonstatic member function is
a protected member of its naming class
(11.2)105) As described earlier,
access to a protected member is
granted because the reference occurs
in a friend or member of some class C.
If the access is to form a pointer to
member (5.3.1), the
nested-name-specifier shall name C or
a class derived from C. All other
accesses involve a (possibly implicit)
object expression (5.2.5). In this
case, the class of the object
expression shall be C or a class
derived from C.
After reading this, it became evidently why the second statement failed while the first succeeded, but then the question came up: What is the rationale for this?
My initial thought was that the compiler was expanding the boost::bind templates, discovering that Base::foo was protected and kicking it out because boost::bind<…> was not a friend. But, the more I thought about this explanation, the less it made sense, because if I recall correctly, as soon as you take the pointer to a member (assuming you initially are within access control of the member), all access control information is lost (i.e. I could define a function that returns an arbitrary pointer to a member that alternately returns a public, protected or private member depending on some input and the returner would be none the wiser).
More I thought about it, and the only plausible explanation I could come up with why it should make a difference was in the case of multiple inheritance. Specifically, that depending on the class layout, the member pointer when calculated from Base would be different than that calculated from Derived.
It's all about "context". In the first call the context of the call is Derived which has access to the protected members of Base and hence is allowed to take addresses of them. In the second the context is "outside of" Derived and hence outside of Base so the protected member access is not allowed.
Actually, this seems logical. Inheritance gives you access to Derived::foo and not to Base::foo. Let me illustrate with a code example:
struct Derived : public Base
{
void callPrivateMethod(Base &b)
{
// this should obviously fail
b.foo(5);
// pointer-to-member call should also fail
void (Base::*pBaseFoo) (int) = &Base::foo; // the same error as yours here
(b.*pBaseFoo)(5);
}
};
The reason for this restriction is enforcement of access control across different classes that share a common base.
This is reinforced by notes in Core Language Defects Report defect #385, the relevant part copied here for reference:
[...] the reason we have this rule is that C's use of inherited protected members might be different from their use in a sibling class, say D. Thus members and friends of C can only use B::p in a manner consistent with C's usage, i.e., in C or derived-from-C objects.
As an example of something this rule prevents:
class B {
protected:
void p() { };
};
class C : public B {
public:
typedef void (B::*fn_t)();
fn_t get_p() {
return &B::p; // compilation error here, B::p is protected
}
};
class D : public B { };
int main() {
C c;
C::fn_t pbp = c.get_p();
B * pb = new D();
(pb->*pbp)();
}
The protected status of D::p is something we want the compiler to enforce, but if the above compiled that would not be the case.