Access rights of a nested class of a nested class - c++

In C++ a nested class has access rights to all members of the enclosing class. Does this also apply to a nested class of a nested class?
This code
#include <iostream>
class A
{
public:
class B
{
public:
B() { std::cout << A::x << std::endl; }
class C
{
public:
C() { std::cout << A::x << std::endl; }
};
};
private:
static const int x { 0 };
};
int main()
{
A::B b;
A::B::C c;
}
compiles without warning on g++ 7.2. However, it is unclear to me that this conforms to the standard. The standard draft (N4727 14.7) says:
A nested class is a member and as such has the same access rights as any other member.
However, in the example above C is not a member of A, it is a member of a member. Is the standard ambiguous here? Is g++ behavior portable?

However, in the example above C is not a member of A, it is a member of a member.
Yes this is well-defined behavior; the access right is transfered from B.
According to the standard [class.access]/2,
A member of a class can also access all the names to which the class has access.
And [class.mem]/1,
Members of a class are data members, member functions, nested types, enumerators, and member templates and specializations thereof.
C is a nested class of B, it's also the member of B, then C can access names what B could access to, including A::x. For the same reason, C::C is the member of C, it could access names what C could access to, so accessing A::x in C::C is fine.

The behavior is well-defined and in-line with the standard wording. What you are missing is the relevant wording of [class.access]p2, which strengthens that which you have already quoted:
A member of a class can also access all the names to which the class has
access. A local class of a member function may access the same names that the
member function itself may access.
This means that the accessibility is transitive. If C has access to the same entities as B, it also means that C has access to the entities in A, as B has access to them.
class A {
class B {
class C {
C() { A::x; /* well-defined */ }
};
};
static int x;
};

Related

How private/protected/public affect the ABI?

What I want is for some class members to be sometimes private and others times public. These members are supposed to be accessible by some modules and inaccessible by others.
Imaging this class:
class Foo {
public:
...
private:
...
protected:
...
internal:
int x;
};
In module X the internal is defined as:
#define internal public
and in module Y it's defined as:
#define internal private
So the real question is if this trick is acceptable by the standard or if it will change the signature of the class (or its members) in any way.
I know that friend and PIMPL are for this kind of job but friend can get extremely messy and PIMPL's performance (an indirection and the fact that you can't inline) are not acceptable for the codebase I'm working on.
It is an ODR violation and hence invokes undefined behaviour. (See also basic.def.odr]/6.1 "each definition of D shall consist of the same sequence of tokens").
However, a common implementation is that public, private, protected have no impact on class layout so it will work.
You are skating on thin ice; there is nothing to stop a compiler putting all the public members first, then the protected ones, then the private ones. More to the point, in general, the order of declaration is required to be the order in memory so
struct T {char a; int b; char c};
is required to have a, then b, then c. This is to ensure C compatability. However, there is no requirement on the ordering of elements with different access (See [class.mem]/9.2 p13: "Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (Clause 11)". So given
struct T {char a; int b; private: char c};
the compiler can reorder the members and put c in the gap between a and b.
Final note to EJP and others who think these are declarations not defintions: I have given two definitions of T above; a declaration would look like struct T;.
Edit: Thanks to Fanael for the cite from the standard.
The C++ originally seemed to consider that private members could be placed somewhere other than next to public members, perhaps so they could be a protected region in hardware, so it is conceivable that the public and private sections could be moved relative to each other.
It is possible to test your code without redefining public / private using tricks by Herb Stutter GOTW 76 and completed to a fully functional system with this data here litb safer private member access
Given a class as follows....
struct A {
A(int a):a(a) { }
private:
int a;
};
A class robber is required...
template<typename Tag, typename Tag::type M>
struct Robber {
friend typename Tag::type get(Tag) {
return M;
}
};
A utility class allowing multiple steals....
template<typename Tag, typename Member>
struct TagBase {
typedef Member type;
friend type get(Tag);
};
Declaring a theft intent becomes
struct A_f : TagBase<A_f, int A::*> { };
template struct Robber<A_f, &A::a>;
Then stealing the data....
int main() {
A a(42);
std::cout << "proof: " << a.*get(A_f()) << std::endl;
}

C++ Outer class access Inner class's private - why forbidden

Hello I am wondering why C++ standard allows us in nested classes to access outer class's private fields, while it forbids to access inner class's private fields from the outer class. I understand, that this example:
class OuterClass{
public:
class InnerClass{
public:
void printOuterClass(OuterClass& outer) {cout << outer.m_dataToDisplay;};
};
private:
int m_dataToDisplay;
};
is fine, because thing, that Inner class sometimes can be complicated. But I think following scenario is also fine:
class Algorithm{
public:
class AlgorithmResults{
public:
void readAlgorithmResult();
private:
void writeAlgorithmResult();
};
void calculate(AlgorithmResults& results, Arguments...){
//calculate stuff
results.writeAlgorithmResult(results);
}
};
For me this structure makes perfect sense, although it is not allowed in C++. I also noticed, that for some time both were allowed in Java, but now second example is also forbidden.
What is the reason, that first example is allowed and another is denied?
Essentially, within a scope names declared earlier in that scope are valid and can be used directly (unless they're shadowed). Code outside a scope can't directly use names declared inside the scope. E.g. code after a curly braces block, can't directly use variables declared inside that block (an example of indirect use is when the outside code has access to a pointer to a static variable inside the curly braces block).
For the second example, just make Algorithm a friend of AlgorithmResults:
class AlgorithmResults
{
friend class Algorithm;
The nested classes could access outer class's private fields, because it's a member of the outer class, just same as the other members.
[class.access.nest]/1
A nested class is a member and as such has the same access rights as any other member.
On the other hand, the outer class doesn't have special access rights on the nested class, they're just normal relationship.
The members of an enclosing class have no special access to members of a nested class; the usual access rules ([class.access]) shall be obeyed. [ Example:
class E {
int x;
class B { };
class I {
B b; // OK: E​::​I can access E​::​B
int y;
void f(E* p, int i) {
p->x = i; // OK: E​::​I can access E​::​x
}
};
int g(I* p) {
return p->y; // error: I​::​y is private
}
};
— end example ]
Counter question: Why would you want to allow it?
If you need an outer class have access to an inner class' private internals, you can befriend:
class Foo {
public:
class Frob {
friend class Foo;
int privateDataMember;
};
Foo () {
Frob frob;
frob.privateDataMember = 3735928559;
}
};
C++ has no device to unfriend, so allowing default private access to an outer class would steal you a class design tool and yield reduced default encapsulation.

Inner class access to private members of outer, according to ISO 2003

As described in ISO C++ 2003
§11.8 Nested classes [class.access.nest]
The members of a nested class have no special access to members of an
enclosing class, nor to classes or functions that have granted
friendship to an enclosing class; the usual access rules (clause 11)
shall be obeyed. 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.
[Example:
class E {
int x;
class B { };
class I {
B b; // error: E::B is private ERROR 1
int y;
void f(E* p, int i)
{
p->x = i; // error: E::x is private ERROR 2
}
};
int g(I* p)
{
//return p->y; // error: I::y is private ERROR 3
}
};
int main()
{}
—end example]
So I think that clang and g++ are wrong as they compile this code successfully.
Or do I understand something wrong?
Standard says about "have no special access", but not about "have no access at all". Nested class is a same member of outer class as any other member.
It is not clearly said in C++03 standard, but C++11 contains it explicitly:
11.7 Nested classes [class.access.nest]
1 A nested class is a member and as such has the same access rights as any other member.
This behaviour has changed since 2003. The relevant clause in Working Draft N4926 (C++17) now reads:
§11.7 Nested classes [class.access.nest]
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.
So the access is one way: nested class members can access enclosing class members, but not vice versa.
For instance:
class Enclosing
{
int n;
class Nested
{
int n;
int f (Enclosing& E)
{
return E.n; // OK
}
} ;
int f (Nested& N)
{
return N.n; // Error: Nested::n is private
}
} ;

Policy inheritance and inaccessible protected members

It seems that a protected member from a template policy class is inaccessible, even with a class hierarchy which seems correct.
For instance, with the following code snippet :
#include <iostream>
using namespace std;
template <class T>
class A {
protected:
T value;
T getValue() { return value; }
public:
A(T value) { this->value = value; }
};
template <class T, template <class U> class A>
class B : protected A<T> {
public:
B() : A<T>(0) { /* Fake value */ }
void print(A<T>& input) {
cout << input.getValue() << endl;
}
};
int main(int argc, char *argv[]) {
B<int, A> b;
A<int> a(42);
b.print(a);
}
The compiler (clang on OS X, but gcc returns the same type of error) returns the following error :
Untitled.cpp:18:21: error: 'getValue' is a protected member of 'A<int>'
cout << input.getValue() << endl;
^
Untitled.cpp:25:5: note: in instantiation of member function 'B<int, A>::print' requested here
b.print(a);
^
Untitled.cpp:8:7: note: can only access this member on an object of type 'B<int, A>'
T getValue() { return value; }
^
1 error generated.
The strange thing is that the last note from the compiler is totally correct but already applied since the b object is of type 'B<int, A>'. Is that a compiler bug or is there a problem in the code ?
Thanks
You have misunderstood the meaning of protected access.
Protected members are callable by derived classes. But only on the base object contained inside the class itself.
For example, if i simplify the problem, using :
class A {
protected:
void getValue(){}
};
class B : protected A
{
public:
void print(A& input)
{
input.getValue(); //Invallid
}
};
getValue cannot be called on a "A" object other than the "A" object inside the class itself.
This for example is valid.
void print()
{
getValue(); //Valid, calling the base class getValue()
}
As pointed out by Dan Nissenbaum and shakurov. This is however also valid:
void print(B& input)
{
input.getValue();
}
This is because we explicitly say that input is a object of B. And the compiler know that all that objects of B has protected access to getValue. In the case when we pass a A&, the object might as-well be a type of C, wich could be derrived from A with private access.
Let's forget for a minute about the template and look at this:
class A {
protected:
int value;
int getValue() { return value; }
public:
A(int value) { this->value = value; }
};
class B : protected A {
public:
B() : A(0) { /* Fake value */ }
void print(A& input) {
cout << input.getValue() << endl;
}
};
The print() method's implementation is wrong because you can't access non-public member of A inside B. And here's why: from within B, you can only access non-public members of B. Those members may be either inherited or not — it doesn't matter.
On the other hand, A& input may not be a reference to an instance of B. It may be a reference to another subclass (which may well have getValue() inaccessible).
Member functions of a derived class have access to protected base class members within any object of its type that is passed as an argument so long as the explicitly declared class of the object passed as an argument is that of the the derived class (or a further derived class).
Objects explicitly passed as the base class type cannot have their protected members accessed within the derived class's member functions.
In other words, if we have:
class A
{
protected:
int x;
}
class B : public A
{
void foo(B b)
{
b.x; // allowed because 'b' is explicitly declared as an object of class B
}
void goo(A a)
{
a.x; // error because 'a' is explicitly declared as having *base* class type
}
};
...then the line a.x is not allowed because the explicit type of the argument is A, but the rule for protected access only applies to objects explicitly defined as the same class as the class attempting to access the member. (...Or a class derived from it; i.e., if class Cderives from B, then passing an object explicitly declared as an object of class C will also have x accessible within B member functions.)
The reason for this is given by shakurov when he writes (paraphrasing)
A& input might not be a reference to an instance of B. It may be a
reference to another subclass (which may well have getValue()
inaccessible)
An excellent explication of this answer is also given here: accessing a protected member of a base class in another subclass.
As a matter of interest, I believe that this comes from the C++ standard here:
11.4 Protected member access [class.protected] 1 An additional access check beyond those described earlier in Clause 11 is applied when a
non-static data member or non-static member function is a protected
member of its naming class (11.2)115 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 denote 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.
Don't get distracted by the template. It has nothing to do with the error. The line in main that the compiler is complaining about creates an object of type B<int, a> and tries to access a protected member. That's not legal, regardless of the type. You can only use protected members from inside a member function or friend function. For example:
struct S {
protected:
void f();
};
int main() {
S s;
s.f(); // error: attempts to call a protected member function
}

C++ inheritance: scoping and visibility of members

Can you explain why this is not allowed,
#include <stdio.h>
class B {
private:
int a;
public:
int a;
};
int main() {
return 0;
}
while this is?
#include <stdio.h>
class A {
public:
int a;
};
class B : public A{
private:
int a;
};
int main() {
return 0;
}
In both the cases, we have one public and one private variable named a in class B.
edited now!
In both the cases, we have one public
and one private variable named a in
class B.
No, thats not true.
In the first case, you can't have two identifiers with the same name in the same scope. While in the second case, B::a hides A::a, and to access A::a you have to fully qualify the name:
b.a = 10; // Error. You can't access a private member.
b.A::a = 10; // OK.
Because B::a hides A::a in the second example. You can still access it, but it needs explicit qualification for the compiler to figure out you are asking for the member of parent class with the same hame.
In the first example both a's are in the same scope, while in the second example the scopes are different.
Class B in the first example is not valid because C++ cannot distinguish members by their access specifiers (public/private/protected). However, namespaces are a way for C++ to distinguish members. In class B in the second code you don't have a "public a" and a "private a", you have B::a and A::a.
Even if declaring members of the same name/signature with different access specifiers was allowed, there would be no way to address the correct member.
The first isn't allowed because it leads to ambiguous definitions. In the 2nd, although you do have both a public and a private a integer variable, you've hidden A::a inside your B class. The compiler knows implicitly what you want because there is a way to explicitly access a hidden variables.
I also believe that it boils down to name mangaling: storage specifiers don't end up as part of the actual name. I could be wrong on this however.
The easiest way to illustrate why one is allowed and why the other isn't is to look at how the compiler would compile a member function that uses each variable.
Inside your class b:
class b {
int a;
public:
int a;
void myMethod()
{
a = 10; //what a should the compiler use? Ambiguous, so the compiler sez BZZT.
}
}
For the 2nd example:
class A
{
public:
int a;
}
class B: public A
{
private:
int a;
void someMethod()
{
a = 10; //implied that you are using B::a (which may be a programmer error)
}
}