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.
Related
I am referring to one of the exercises mentioned in the book "thinking in c++.
Below code snippet throws an error for the call h.play, which i understand, because
the member i is private. But I was expecting the same error for the call me.play. If i comment the call h.play the code compiles fine. Why there is no error for the call me.play ?
class Buddy {};
template<class T> class My {
int i;
public:
void play(My<Buddy>& s) {
s.i = 3;
}
};
int main() {
My<int> h;
My<Buddy> me, bud;
h.play(bud);
me.play(bud);
}
Thankyou.
[Edit] Is there a way to see what code the compiler has generated for
My<int> h and
My<Buddy> me
? (anything similar to -E compiler flag) ?
Members are always "public" to instances of another object with the same type.
Meaning a My<Buddy> instance (such as me) can access private members of another My<Buddy> instance (such as bud).
Keep in mind that My<int> is a completely different type than My<Buddy>, and so it cannot access those members.
Because the play method is defined as taking a reference to My<Buddy> rather than a My<T>, the effective class is the same type when called on another instance of My<Buddy>. Therefore private members are accessible.
Unlike in languages that just pretend to have strong static type system and generics (looking at you Java), C++ allows you to disambiguate statically parametric types (template types) based on the parameters (the parameters being usually types) the types are templated on.
Note: You can also use a derived (dynamically / late bound) type as a parameter for a statically parametrized type, but it's not relevant in this scenario.
In other words, in C++:
typeid(me) == typeid(bud) will be TRUE
typeid(h) == typeid(me) will be FALSE
even though the type "My" is the same.
You can access the private data-members from the same type as though they were public, but as you can see, the second comparison is false because the operands are not of the same type, therefore you violate the access restrictions of the type.
Also, I don't think there is any way to take a look at the compiler-generated code. (As far as I know.)
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.
In the code snippet, I am able to access the private member variable outside the class scope. Though this should never be done, why is it allowed in this case? Is it a bad practice to receive a returned private variable by reference ?
#include <iostream>
#include <cstdlib>
class foo
{
int x;
public:
foo(int a):x(a){}
int methodOne() { return x; }
int& methodTwo() { return x; }
};
int main()
{
foo obj(10);
int& x = obj.methodTwo();
x = 20; // With this statement, modifying the state of obj::x
std::cout << obj.methodOne();
getchar();
return 0;
}
And regarding this method, what does the return type convey ? And also when should I have return type of this kind ?
int& methodTwo() { return x; }
PS: I am sorry if the subject line is vague. Can someone change it to the content relevant here. Thanks.
private does not mean "this memory may only be modified by member functions" -- it means "direct attempts to access this variable will result in a compile error". When you expose a reference to the object, you have effectively exposed the object.
Is it a bad practice to receive a returned private variable by reference ?
No, it depends on what you want. Things like std::vector<t>::operator[] would be quite difficult to implement if they couldn't return a non-const reference :) If you want to return a reference and don't want clients to be able to modify it, simply make it a const reference.
Returning private members as reference is perfectly valid and the programmer who writes a class is responsible to carefully choose if this should be allowed. This link gives an example when this can be done.
This code:
int& methodTwo() { return x; }
Means that the function returns a reference to an integer. Just like when passing a value by reference to a function, if the return value of methodTwo gets changed, so does the value that methodTwo returned. In this case, class field x.
In the code you have written, this means that you are letting the private variable x escape its scope (a class field) and be passed around in the outside world. This certainly is a bad practice (because x can be changed in ways that may break class foo, but it is certainly allowable.
Remember public/private/protected are compile-time only. Once your application gets compiled, private fields sit next to public fields and there is no protection against modification. The same is true for managed languages like C# and Java.
You should generally avoid returning references because it makes it crazy-hard to understand when constructors/destructors get called. However, returning a reference can be faster. If your method returned a struct type that was HUGE, returning a const reference to that same struct type should only take four-to-eight-bytes (a pointer to that object). However, there are better ways to optimize for this sort of thing.
Like Donotalo said, it is perfectly valid. The idea of having private members is to disallow other classes/functions to access the private member of the class without your permission. If you are happy to make a function to allow other classes/functions to access your private members, the compiler has nothing against that really :-)
Usually, it is useful to have a private member and have a get function to allow other classes/functions to get the value of the function, but only the class will be able to change it.
I am able to access the private member variable outside the class scope
If you are referring to the x in main() then that is different from the x declared in class foo. If you try to access the obj.x then the compiler will definitely complain.
Is it a bad practice to receive a returned private variable by reference ?
There is nothing wrong in "receiving" the reference to a private member. But giving out the reference to a private member makes declaring it private useless. By declaring a variable to be a private member you restrict the access to that member only to the class' methods.
regarding this method, what does the return type convey ? And also when should I have return type of this kind ?
Not sure as to which method you are referring to?!?!?!
Is the passing by reference of a private variable in a class to be directly changed outside that class acceptable practice? Or is this something that the compiler 'should' pick up and prevent?
Example:
//-------------------------------------------
class Others
{
public:
Others() {};
void ChangeIt(string &str) { str = "Changed by Others"; }
};
//-------------------------------------------
class Locals
{
private:
string PrivateString;
public:
Locals() { PrivateString = "Set by Locals"; };
void VisitOthers() { Others o; o.ChangeIt(PrivateString); }
const string GetString() { return PrivateString; }
};
//-------------------------------------------
int main(void)
{
Locals lo;
cout << lo.GetString() << "\n";
lo.VisitOthers();
cout << lo.GetString() << "\n";
return 0;
}
Output:
Set by Locals
Changed by Others
I need to do something like this using other/different objects, private to the owner class, but changeable by others when needed. Last thing I want is for this kind of practice to come back & byte me in the future.
What is essentially worrying me, is that I would like to view the class/struct as basically a pointer to a buffer, and the member's address as offsets into this buffer, so that even if you pass the pointer-value of a member it would be useless without the base-pointer of the class/struct to which it belongs. This is what I instinctively feel should be the case, so that the above example should not even be possible.
There is nothing to prevent, you pass your private member by reference. The function you are calling isn't accessing your private member, it is changing it's own argument (that happens to be the member of some class). The code is OK, but the important thing is that the function you called doesn't keep a reference to your private member.
As the designer of the class, C++ won't prevent you to hand out reference to class private members to anyone. It may however be advisable to restrict such access to only authorized entities e.g. friends, in which case access to such private members is not really a big concern as it is 'by design'.
EDIT 2:
The mutating version of operator[] for a class also typically provides an interface for the external entities to modify the private members.
This is not good practice.
If you want other objects to modify your object, then go for
Friend classes and Friend functions
Passing private members is totally okay. You would indicate that VisitOthers() does not change your object by making it a const method. If the method was:
void VisitOthers() const {Other o; o.visit(PrivateString);}
you would get a compiler error, because you would only allowed to pass PrivateString as a const object. It is very important though that you indicate by const and your comments which methods actually change the state of your object.
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.