Link to home
Start Free TrialLog in
Avatar of LuckyLucks
LuckyLucks

asked on

getting undeclared identifier when a friend class tries to access a protected variable

Hi

I  am getting "t: undeclared identifier" when a friend class B tries to access it's friend A's protected variable ,t, from within B's  function.

I have a class A.h:

class A{

 public:
   //blah blah

protected:
    T* t;

private:
  //blah blah

friend class B;
};


In another file, class B.cpp (note that doSomething is a protected function):

void B::doSomething(){

   cout<<  t->isRaining <<endl;

}

In another file, T.h:
class T{

    public:
        T();

    protected:
        char isRaining;
}
   


By adding friend class B to the definition of A, aren't all members functions in B able to access all the private and protected members of class A, and hence accessing t should be legit?

 I have left out showing what T.cpp and B.h look like since they will not contribute to understanding the problem. Instead, they will just add visual clutter .But they do exist.

what am i doing incorrectly here?
Avatar of jkr
jkr
Flag of Germany image

All you need is a forward declaration of 'B', i.e.

class B; // <--- this is the fwd. decl. that is required

class A{

 public:
   //blah blah

protected:
    T* t;

private:
  //blah blah

friend class B;
};

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of phoffric
phoffric

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
if B is not derived from A you need an A object to access member t:

void B::doSomething(A a){

   cout<<  a.t->isRaining <<endl;

}

Open in new window


Sara
Avatar of LuckyLucks
LuckyLucks

ASKER

class T;
class B;


class A{

 public:
   //blah blah

protected:
    T* t;

private:
  //blah blah

friend class B;
};


Note: I have updated what A.h looked like - Both class B and T are forward referencces in class A.h

I still get "t:undeclared variable". I had T as a forward reference earlier when i first posted. I added class B as a forward refs as per someone's suggestion.

@Sara: I am not sure why  I need an A object to access member t? Isn't the point of making B a friend is so that B can access protected members of A. Otherwise I could just make a public function return t and I could create an A object that would call the public function.
>> cout<<  a.t->isRaining <<endl;
but isRaining is protected.

Without seeing your code (e.g., header files, ordering, blah blah), hard to see what is in your program. Just get a listing by compiling your single .cpp file setting option to get a preprocessor listing (no compilation).
   http://msdn.microsoft.com/en-us/library/8z9z0bx6.aspx

Unless blah blah has something like B* dataMember; then no forward of B is needed.
I am not sure why  I need an A object to access member t? Isn't the point of making B a friend is so that B can access protected members of A.


principally, a member variable belongs to an object - an instance - of the class. so you need an object of class A to access t member variable.

A a;  // constructor creates pointer t-
a.t->raining = false;

Open in new window


in member functions of A or member functions of classes derived from A the 'this' object can be used. then
t->raining = false;

Open in new window

and
this->t->raining = false;

Open in new window

are equivalent but only because in a member function the 'this' object is a default.

if a class B is declared friend class in A but is not derived from A, the 'this' object of the current B object is different from A. hence, you need to create an A object or get it as argument before you can access any member data or member functions of A.

the only exception to that rule is a static member which belongs to the class A and where therefore is only one instance of the member. but even for the latter case you cannot use 't' member but need to say A::t to tell the compiler where the 't' comes from and how it is defined.

Sara
the question was why the compiler complains when a member function of class B used the statement

t->raining = false;

Open in new window

where t is a protected member of class A which has declared class B as "friend class".

The comment of jkr http:#a39511717 suggested to use a forward declaration of class B in A. A friend declaration doesn't need a forward declaration and forward declarations only have effects for declarations in the header (files) but not for implementation code.

The comment of phoffric http:#a39511982 stated 'but A does not have access to isRaining' what obviously is a typo. Member functions of A have access to all members regardless whether they were private, protected, or public.

My comment http:#a39514309 tells, that member t cannot be used by member functions of class B if B is not derived by A without an instance of object A. This comment tells the reason for the compiler error 't: undeclared identifier'.

The Author's comment  http:#a39516741 told that forward declarations didn't help and asked me why B needs an object of class A although B was declared as friend in class A.

The comment of phoffric http:#a39516784 used sample code from my comment with a.t->israining (where the 'a' was the needed object). The comment asks for more information and told that a forward declaration was not needed by the code posted so far.

My comment http:#a39517541 answered the question LuckyLucks has directed to me. It explains that a member variable of a class A only can accessed by another class if the other class has access to an instance of class A. Only if the class B is derived from A it can use members of a base class without object. The friend relation on its own, doesn't provide an object of A.

The last comment rightly was the accepted solution. The grade should be at least a 'B' grade.

Sara
LuckyLucks, you might want to consider contemplating the nature of questions. Your initial question was solved by my first comment. Then you started asking followups. These were answered by others. So, what gives?
>>  'but A does not have access to isRaining' what obviously is a typo. Member functions of A have access to all members regardless whether they were private, protected, or public.
   What is the typo?

>> The comment of phoffric http:#a39516784 used sample code from my comment with a.t->israining (where the 'a' was the needed object).
   My comment was that isRaining is protected, meaning that B also does not have access to isRaining. Making B a friend of T would solve that problem.
'but A does not have access to isRaining' what obviously is a typo.  

What is the typo?
i assumed the 'not' is a typo. class A members may have restricted access to class T members but that is not part of the question. the error "t:undeclared variable" points to the real issue that the 't' cannot be used in B without an A object.


void B::doSomething(){

   cout<<  t->isRaining <<endl;

}

Open in new window

that is the sample code the author posted in the initial question.

obviously, the error "t:undeclared variable" coming up with the cout statement cannot be solved by using forward declarations for class B and class T in class A as claimed by jkr.

forward declarations have the purpose to allow the declaration of pointer variables and reference variables in a class (header) or in a declaration of a function. classes declared forward cannot be used in a statement as it was with above sample code, cause a forward declaration doesn't give the compiler sufficient information of how to use the type. in the sample code the 't' accesses member variable 'isRaining'. the compiler doesn't know from the member nor does it know which type the 'isRaining' if it has only a forward declaration of T.

Sara
@sara,
If leaving out the "not" as you suggest, my statement would read:
B as a friend of A should have access to t, but A does have access to isRaining, so you should get an error on the line of code that has t->isRaining.
which is incorrect since A does not have access to isRaining because isRaining is a protected member of T.

Your post 39514309 has the problem in that it suggests that an instance of class B has access to T's protected member, isRaining. I tried to point that out in my post 39516784 so that you could clarify this, but you did not do so.

The problem is that B does not have access to T's protected members; but this can be remedied by making B a friend of T:
class T{
    friend class B;

The forward class declaration suggested in the first post is not required to build the program.
@phoffric,

i actually, didn't assume your statement was about the protected status of T member 'isRaining' but was about A member 't'. the T actually was not considered by me as a problem cause the author excludes it in their initial post:

I have left out showing what T.cpp and B.h look like since they will not contribute to understanding the problem.

My post http:#a39514309 tries to give an explanation why the code the author has posted, gave issues. i didn't understand your comment as an add-on to mine but as a different solution.


the original code of the author has four elements:


(1) class definition of class A (with protected member t and friend class declaration of B).
(2) class definition of class B (was not derived from A).
(3) B member function 'doSomething' tries to access t->isRaining  (without defining a t).
(4) class header of T (where isRaining is a protected member).

with the first three elements the author asserted that it should be possible to access "member" t of class A by means of the friend declaration only. in my comment
http:#a39514309 i explained that it was necessary to have an instance of class A before a member could be accessed. in a later comment the author confirms that they were unaware that a friend relation not automatically would provide such an instance. the code sample was adapted from the author's code and it solved the initial question "getting undeclared identifier when a friend class tries to access a protected variable". the "protected" variable of the error was not T::isRaining but A::t.

my comment does not "suggest" to access the protected 'isRaining' but simply overtook that part from the original code snippet  (without recognizing an issue).

with the 4th element there was a new issue that neither A nor B member functions can access the 'isRaining' member of T as it was protected and A und B were not friends of T. i have to admit that i missed to see  the issue in the first case and later cause it couldn't be the cause for the error reported. while it is true that it is some more issue, the error message of the compiler would have been a clear message like 'cannot access protected member T::isRaining'.  

phoffric, i thank you for answering again and so helped me to clarify where we had misunderstandings. i hope, you also can accept my final analysis.

Sara
Ok, I see the misunderstandings. I will try to be more complete in the future.

>> in my comment http:#a39514309 i explained that it was necessary to have an instance of class A before a member could be accessed.

The problem with your posting that I was trying to help you with was that the posting would not compile given the OPs snippets. The fact that T.cpp wasn't posted is not a factor; T.h was posted in the OP, and that is where we can see that B does not have access to T's protected members; and that is why your posting should not compile.

I don't think we should post code solutions that cannot compile without some qualifying statement especially where the reason for not being able to compile is related in general to issues of friends and classes not being able to access other classes non-public members.
I like  phoffric's answers . Forgive my lack of clarity (if there is some) in my post but the main issue I was trying to solve was being able to access a protected variable through a friend class (B was trying to get at A's protected variable).

by: phoffricPosted on 2013-11-11 at 12:39:59ID: 39639324
i think my analysis in http:#a39639642 is true.

then, http:#a39514309 should be the accepted answer cause it solves the error described in the initial question by accessing a member variable of A without an object of A.

however, the answer would create another error that class B cann not access a protected member of T.

it is phoffric's credit to have seen that and as the author tells that they 'like his answers', the currently accepted answer http:#a39511982 should get the points.

Sara
I think a split is in order between http:#a39639324 and http:#a39514309