i.e. if I define operators == and + in my class in a private section, can they be accessible from main?
It works in MSVS 2008 and 2010 but for me it seems to be a bug in a compiler. Is it so?
Functions or members declared under private access specifier will not be accessible outside the class member functions.
There are 3 access specifiers for a class/struct/Union in C++. These access specifiers define how the members of the class can be accessed. Of course, any member of a class is accessible within that class(Inside any member function of that same class). Moving ahead to type of access specifiers, they are:
Public - The members declared as Public are accessible from outside the Class through an object of the class.
Protected - The members declared as Protected are accessible from outside the class BUT only in a class derived from it.
Private - These members are only accessible from within the class. No outside Access is allowed.
Friends to the rescue!
Declaring a function as friend inside another class allows that function to access all the member functions inside the class irrespective of the access specifier rules. friend It is a way to bypass the access specifier rules laid out in C++. Similary, a class declared as friend inside another class will allow the class being declared as friend to have access to all the members of the class. Note that the friend declaration can be given under any access specifer and it will have the same effect.
An source code example:
class MyClass
{
public:
int a;
protected:
int b;
private:
int c;
friend void doSomething(MyClass obj);
};
void doSomething(MyClass obj)
{
obj.a = 10; //Allowed
obj.b = 20; //Allowed,
obj.c = 30; //Allowed,
}
int main()
{
MyClass obj;
obj.a = 10; //Allowed
obj.b = 20; //Not Allowed, gives compiler error
obj.c = 30; //Not Allowed, gives compiler error
}
So in your usage if you are using friend then you can have access to the private members of the class or else your compiler is buggy you should consider changing it!
You will have to show the code to get a sensible explanation of why the compiler is accepting it. My guess is that you are implementing them as friend free functions. At any rate, for the sake of argument, assume you have:
class bar {
friend bool operator==( bar const &, bar const & ) {
return true;
}
bar operator+( bar const & ) {
return *this;
}
};
int main() {
bar a, b;
a == b; // ok
//a + b; // nok: operator+ is private from this context
}
And now the explanation. In the example, operator+ is declared as a member function inside a private section, as such, access specifiers apply and unless main is a friend of the class it will not have access to it. On the other hand operator== is implemented as a free function (even if the definition is provided inside the class braces) and access specifiers do not apply there.
The code is almost equivalent (there is a small difference when it comes to lookup) to:
class bar {
friend bool operator==( bar const &, bar const & ); // just declare as friend
//...
};
bool operator==( bar const &, bar const & ) {
return true;
}
Where it is much simpler to reason about accessibility of operator== from the main function.
Yes, it is a bug. They are accessible only by friend functions and friend classes. All other shouldn't have access to private section.
The first answer is : No. If its accessible from outside then what is the point of being it private?
However, there is a twist.
If you make main() friend of the class, then its accessible only from main(). So the second answer is : it actually depends: Only member functions and friends can access the private member of a class.
class A
{
int data; //private
friend int main(); //make main() friend of A
};
int main()
{
A a;
a.data = 100; //okay - main() is a friend of class A
}
void f()
{
A a;
a.data = 100; //error - f() is not a friend of class A
}
That means, I infer that operator== and operator+ must be friends of the class in your code.
If you haven't added a friend declaration for main (don't know if that is even possible), the answer is no, so you apparently have found a compiler bug.
Related
I'm starting to work with friends of classes.
Here I have two functions called setMaxSickDays and getMaxSickDays.
I made a variable called maxSickDays in setMaxSickDays that I'd like to access from getMaxSickDays.
class timeOff
{
public:
void setMaxSickDays(numDays &friendlyObject) {
int maxSickDays;
friendlyObject.hours = 240;
maxSickDays = friendlyObject.hours;
}
void getMaxSickDays(numDays &friendlyObject) {
cout << maxSickDays;
}
};
The error: 'maxSickDays' was not declared in this scope
This may seem silly but I'm a beginner. Thanks!
You make maxSickDays a data member of your class.
class timeOff
{
public:
void setMaxSickDays(int days);
int getMaxSickDays();
private:
int maxSickDays;
};
You can't access another function's local variable, even as friend. friend is used to granted to access members (i.e. member variables or functions) of the class.
See friend declaration
The friend declaration appears in a class body and grants a function or another class access to private and protected members of the class where the friend declaration appears.
Basically I have 2 classes under a namspace, and I want to give one of the methods of one class (call it B::fun) access to the private member of the other class (call it class A). However, I can't seem to get it to work. Here is a simple example that illustrates the problem:
namespace ABC // this could be global too
{
class A;
class B
{
public:
int fun(A member);
};
class A
{
public:
friend int B::fun(A member);
private:
int aint;
};
int B::fun(A member)
{
return member.aint; // error: member ABC::A::aint is inaccessible
}
}
Why do I get this error?
NOTE: Seems to be a compiler issue (using VC++ 11).
Actually, with both G++ 4.8.1 and CLang++ 3.3 I'm getting an error in the friend line:
g++: error: 'int ABC::B::fun(ABC::A)' is private
clang++: error: friend function 'fun' is a private member of 'ABC::B'
That is, the error is that ABC::B::fun() is private, so the friend declaration fails, and then the line you signaled fails as a consequence.
This happens because simply you cannot make a friend that you cannot access.
The solution is to make ABC::B::fun() public, or make friend the whole B, or something similar.
By the way, the namespace has nothing to do with your error, but IMO it would be clearer if your friend declaration were simply:
friend int B::fun(A member);
as you are already inside namespace ABC.
Change your friend declaration inside A
class A {
friend class B;
int aint;
};
Alternatively, to only friend the single method, you need to make A a friend of B since the method you're friending is private. Or you could make fun(A) public.
namespace ABC
{
class A;
class B
{
friend class A;
int fun(A member);
};
class A
{
friend int B::fun(A);
int aint;
};
int B::fun(A member)
{
return member.aint;
}
}
Can i put definition of friend function / class inside another class? I mean something like this:
class Foo
{
friend void foo() {} // 1
friend class Bar {}; // 2
};
gcc compiles friend function, but can't compile friend class.
You can define a friend function in the friend declaration, and it has interesting behavior that cannot be obtained any other way (in the case of the enclosing type being a template).
You cannot define a friend class in the friend declaration, and there is no need for that. If you want to create a new type inline with full access, you can just create a nested type. Being a member it will have full access to the enclosing type. The only difference is that the type will not be found at namespace level, but you can add a typedef if needed (or alternatively, define the class at namespace level and just declare the friendship inside the class).
class Outer {
int x;
class Inner {
static void f( Outer& o ) { o.x = 5; } // fine
};
};
n3337 11.3/2
A class shall not be defined in a friend declaration. [ Example:
class A {
friend class B { }; // error: cannot define class in friend declaration
};
—end example ]
But you can use something like
class Foo
{
friend void foo() {} // 1
class Bar { };
friend class Bar; // 2
};
You can make a nested class which, according to defect report 45, has access to the private members of the class. Is this what you meant?
"A nested class is a member and as such has the same access rights as any other member."
This may not work in all compilers because prior to this C++ standards defect report, nested classes were given no special access.
Change the code to:-
class Foo
{
friend void foo() {} // 1
friend class Bar ; // 2
};
For a code like this:
class foo {
protected:
int a;
public:
class bar {
public:
int getA() {return a;} // ERROR
};
foo()
: a (p->param)
};
I get this error:
invalid use of non-static data member 'foo::a'
currently the variable a is initialized in the constructor of foo.
if I make it static, then it says:
error: 'int foo::a' is a static data member; it can only be initialized at its definition
However I want to pass a value to a in the constructor.
What is the solution then?
In C++, unlike (say) Java, an instance of a nested class doesn't intrinsically belong to any instance of the enclosing class. So bar::getA doesn't have any specific instance of foo whose a it can be returning. I'm guessing that what you want is something like:
class bar {
private:
foo * const owner;
public:
bar(foo & owner) : owner(&owner) { }
int getA() {return owner->a;}
};
But even for this you may have to make some changes, because in versions of C++ before C++11, unlike (again, say) Java, a nested class has no special access to its enclosing class, so it can't see the protected member a. This will depend on your compiler version. (Hat-tip to Ken Wayne VanderLinde for pointing out that C++11 has changed this.)
In C++, nested classes are not connected to any instance of the outer class. If you want bar to access non-static members of foo, then bar needs to have access to an instance of foo. Maybe something like:
class bar {
public:
int getA(foo & f ) {return foo.a;}
};
Or maybe
class bar {
private:
foo & f;
public:
bar(foo & g)
: f(g)
{
}
int getA() { return f.a; }
};
In any case, you need to explicitly make sure you have access to an instance of foo.
The nested class doesn't know about the outer class, and protected doesn't help. You'll have to pass some actual reference to objects of the nested class type. You could store a foo*, but perhaps a reference to the integer is enough:
class Outer
{
int n;
public:
class Inner
{
int & a;
public:
Inner(int & b) : a(b) { }
int & get() { return a; }
};
// ... for example:
Inner inn;
Outer() : inn(n) { }
};
Now you can instantiate inner classes like Inner i(n); and call i.get().
You try to access private member of one class from another. The fact that bar-class is declared within foo-class means that bar in visible only inside foo class, but that is still other class.
And what is p->param?
Actually, it isn't clear what do you want to do
Your Question is not clear but there is use case when you will get this issue .
Invalid use of non-static data member.
When you are using "non-static data member in another class try to not use with scope resolution operator
Example::className::memberData = assignivalue ;
instead of above try to use object of className class;
Example:: m_pClassName->memberData=assignValue;*
I am finding trouble accessing a private member of a class from a friend class.
The class that holds the private member I want to change and the class where the change is made are in different namespaces.
The friend class is defined after the class holding the data, so I've tried to forward declare the friend class outside the namespace.
g++ says that I can't modify the member because it's private, visual studio seems to think it's fine.
Am I doing some weird non-standard thing here? Why can't I change the member? Here is a simplified snippet that represents my problem:
struct S;
namespace N
{
class A
{
int m;
public:
A():m(5){};
friend struct S;
};
}
using namespace N;
struct S
{
A& a;
S(A& a):a(a) {}
void changeA(){ a.m = 9; }
};
int main()
{
A a;
S s(a);
s.changeA();
}
friend struct ::S;
what you are really doing with
friend struct S;
is declaring as friend the class N::S (which is defined nowhere).
Edit: To back up my idea that gcc behavior is correct and VC++ has a bug.
7.3.1.2/3
If a friend declaration in a non-local class first declares a class or
function the friend class or function is a member of the innermost
enclosing namespace. [...] When looking for a prior declaration of a
class or function introduced by a friend declaration, scopes outside the
innermost enclosing namespace scope are not considered.
Because friend struct S; declares N::S class but you need ::S class.
Try writing out friend struct ::S;.
At the moment, the non-existent N::S is assumed. This fix specifies the global namespace, a bit like how the leading / on a Linux path specifies the filesystem root.