Friending/Using a class in a different namespace - c++

If the class G is in the namespace GSpace and it needs to be friends with the class M in the global namespace what do you have to do? I thought this would work:
/////////////////////M.h//////////////////////
#include "GFile.h"
class M
{
public:
friend class GSpace::G; // doesn't work, throws error
}
After researching on StackOverflow a bit, I found this answer https://stackoverflow.com/a/3843743/1797424
/////////////////////M.h//////////////////////
namespace GSpace
{
class G;
}
class M
{
public:
friend class GSpace::G; // works, no error
private:
GSpace::G gClassMember; // errors: "M uses undefined class GSpace::G"
};
// Note that G.h includes M.h so I do not include it here,
// instead I have it included in M.cpp
That does work for getting the class friended. However, it creates an issue when I actually declare a class member using that type, because the class is not defined. GFile.h
Am I misunderstanding how #include and forward declaration behaves, or is it some kind of implementation issue on the side of the compiler (not likely, I'm assuming)?

Because your member is not a pointer or reference, the compiler needs to know the size of G. You can't use a forward declaration.
As noted in the comment, you need to qualify G with the namespace.
Here is code which compiles for me:
namespace GSpace
{
class G
{
};
}
class M
{
public:
friend class GSpace::G;
private:
GSpace::G gClassMember;
};
int main() {return 0;}

Try the following
namespace GSpace
{
class G;
}
class M
{
public:
friend class GSpace::G;
}
namespace GSpace
{
class G { /* definition of the class */ };
}

Related

Friend classes across different namespaces not working and namespace is not recognized

I am having trouble with the use of friend class in C++
I am forward declaring the friend class and using the appropriate namespaces, so I don't know what is going on.
Inside class MeshNamespace::Mesh , ReferenceElementNamespace::ReferenceElement 's members are still unable to access private members of the former. Besides in ReferenceElement.hpp, MeshNamespace identifier is not recognized.
If I forward-declare it as class Mesh; without the namespace it doesn't complain , but still doesn't work just as if there were no forward declaration at all;
//file ReferenceElement.hpp
namespace ReferenceElementNamespace {
class MeshNamespace::Mesh; // ReferenceElement.hpp:27:9: error: use of undeclared identifier 'MeshNamespace'
class ReferenceElement : public IReferenceElement
{
private:
vector<Polygon> _referenceElementPolygons; //(**)
friend class MeshNameSpace::Mesh; //ReferenceElement.hpp:45:20: error: use of undeclared identifier 'MeshNameSpace'
};
}
//file Mesh.hpp
#include "Mesh.hpp"
using namespace ReferenceElementNamespace;
namespace MeshNamespace {
class Mesh : public IMesh{
someFunction(ReferenceElement& referenceElement)
{
ReferenceElement ref;
Polygon &polygon = ref._referenceElementPolygons[0]; //Mesh.cpp:216:32: error: '_referenceElementPolygons' is a private member of 'ReferenceElementNamespace::ReferenceElement'
ReferenceElement.hpp:34:23: note: declared private here // in line (**)
}
};
}
Edit: By the way, I realized that forward-declaring class Mesh; instead of class MeshNamespace::Mesh; gets accepted because it like declaring a new class in namespace ReferenceElementNamespace, but then I am getting ambiguity in another file where I use MeshNamespace and ReferenceElementNamespace with using. Still this doesn't solve anything
What I know:
Forward declarations in (other) namespaces are supported.
Forward declarations of nested classes are not supported.
OP wrote:
class MeshNamespace::Mesh;
class OtherClass {
friend class MeshNamespace::Mesh;
};
to forward declare a class Mesh in a namespace MeshNamespace.
It could be as well a class MeshNamespace { class Mesh { } } but this is a forward declaration of a nested class (which is not supported).
I'm not sure how to distinguish it, and it seems the compiler cannot as well. However, the fix is simple:
namespace MeshNamespace {
class Mesh;
}
class OtherClass {
friend class MeshNamespace::Mesh;
};
Demo on coliru
Note:
Since C++17, nested namespace definitions are allowed:
namespace X::Y { } is considered equal to namespace X { namespace Y { } }.
This seems to be true for class definitions as well. So, adding a definition
class MeshNamespace::Mesh { };
after the namespace MeshNamespace has been defined once is fine.
(However, this is an error as well before the namespace MeshNamespace has been defined at least once.)
Demo on coliru

Member Function as Friend: Is the book Lippman 5th wrong?

Lippman 5th
ISBN-13: 978-0321714114
Page 280-281, it says:
Making A Member Function a Friend
Rather than making the entire Window_mgr class a friend, Screen can
instead specify that only the clear member is allowed access. When we
declare a member function to be a friend, we must specify the class of
which that function is a member:
class Screen {
// Window_mgr::clear must have been declared before class Screen
friend void Window_mgr::clear(ScreenIndex);
// ... rest of the Screen class
};
Making a member function a friend requires careful structuring of our
programs to accommodate interdependencies among the declarations and
definitions. In this example, we must order our program as follows:
First, define the Window_mgr class, which declares, but cannot define, clear. Screen must be declared before clear can use the
members of Screen.
Next, define class Screen, including a friend declaration for clear.
Finally, define clear, which can now refer to the members in Screen.
The problem is: class Window_mgr has a data member that depends of class
Screen definition. See:
class Window_mgr {
public:
// location ID for each screen on the window
using ScreenIndex = std::vector<Screen>::size_type;
// reset the Screen at the given position to all blanks
void clear(ScreenIndex);
private:
std::vector<Screen> screens{Screen(24, 80, ' ')};
};
So it is impossible firstly define Window_mgr without defining Screen
previously!
And at the same time, it is impossible define Screen without we have
defined Window_mgr!!!
How can this problem be solved???
Is the book wrong?
I will paste here a code so that you can repeat the problem using a
minimal code:
#include <iostream>
#include <string>
#include <vector>
class A
{
friend void B::hello();
public:
A(int i) : number{i} {}
private:
void f() {
std::cout << "hello" << std::endl;
}
int number;
};
class B {
private:
std::vector<A> x{A(10)};
public:
void hello()
{
for(A &elem : x)
{
elem.f();
}
}
};
int main()
{
A x;
return 0;
}
If I compile this code, the result is:
error: use of undeclared identifier 'B'
friend void B::hello();
And if I invert the position (A <--> B), I have:
error: use of undeclared identifier 'A'
std::vector x{A(10)};
Is there a correct way to do that??
Thank you!
EDIT:
Thank you, Craig Young
Solution:
#include <iostream>
#include <string>
#include <vector>
class A;
class B {
private:
std::vector<A> x;
public:
B();
void hello();
};
class A
{
friend void B::hello();
public:
A(int i) : number{i} {}
private:
void f() {
std::cout << "hello" << std::endl;
}
int number;
};
B::B() : x{A(10)}
{
}
void B::hello()
{
for(A &elem : x)
{
elem.f();
}
}
int main()
{
return 0;
}
Conclusion:
the book is incomplete in that it doesn't expose the necessity of doing the forward declaration of class A firstly and the impossibility to do in-class initialization in this case.
I didn't notice that the problem was the A(10), not the vector! That is, we can use incomplete type A (only declaration, without definition) when we are using it as Template argument to vector (because it doesn't create A object itself) but we can not use incomplete type A when defining a object, for example: A(10);
For a start
Well, you're not following the guidance correctly.
First, define the Window_mgr class, which declares, but cannot define, clear. Screen must be declared before clear can use the members of Screen.
You must declare B before A.
Next, define class Screen, including a friend declaration for clear.
Now declare A with B::hello() as a friend.
Finally, define clear, which can now refer to the members in Screen.
B:hello() can use the private members of A.
This has been covered before here: C++ Forward declaration , friend function problem
You've added complications
Furthermore you want declarations of B to reference A. To achieve this you need to forward declare A so that B knows of its existence.
And it's important to be aware that you have only "partial" access to A. You cannot 'fully use' A in the declaration of B. So the following line in B is wrong.
//You're trying to create A when you only know it exists.
//You don't have a full definition of A yet.
std::vector<A> x{A(10)};
//Replace the above with...
std::vector<A> x;
Of course you'll have to find another way to initialise x.
Sample code
#include <iostream>
#include <vector>
class A;
class B
{
private:
std::vector<A> x;
public:
void hello();
};
class A
{
friend void B::hello();
public:
A(int i): number(i) {}
private:
void f() { std::cout << "hello" << std::endl; }
int number;
};
void B::hello()
{
for(A &elem : x)
{
elem.f();
}
}
int main()
{
A a{5};
return 0;
}
You have to have an earlier declaration, but not an earlier definition.
Adding
class A;
class B;
at the front tells the compiler that “A” and “B” refer to classes. That should be enough for it to reason out the rest.

Friendship and Interfaces

I'm having a compilation error using Apple's Clang 7.0 with the following friendship code, using C++11 standard. I wonder what's really wrong with it since it seems to be valid for me. I'm describing the setting and the error I'm having:
MyInterface
namespace namespace1
{
class MyInterface
{
friend class MyClass;
public:
virtual void some_method(void) = 0;
...
private:
type some_attribute;
...
}
}
MyClass::MyMethod Implementation
namespace namespace2
{
void MyClass::MyMethod(MyInterface* MyConcrete)
{
...
// MyConcrete implements MyInterface
if(MyConcrete->some_attribute == some_value) // Error*
{
...
}
...
}
}
Error
error: 'some_attribute' is a private member of 'namespace1::MyInterface'
I really expected that MyClass would have access to some_attribute in MyConcrete (which implemented MyInterface) regardless of the class access modifier. Any clues why this error is happening? Any suggestions?
Thank you!
MyClass is in namespace2. So you need to use:
friend class namespace2::MyClass;
You may also need to use forward decleration of MyClass before you define MyInterface.
Here's an example that compiles:
// forward decleration
namespace namespace2
{
class MyClass;
}
namespace namespace1
{
class MyInterface
{
friend class namespace2::MyClass; // added missing namespace
public:
virtual void some_method(void) = 0;
private:
int some_attribute;
};
}
namespace namespace2
{
class MyClass
{
void MyMethod(namespace1::MyInterface* MyConcrete)
{
if(MyConcrete->some_attribute == 1)
{
}
}
};
}
int main()
{
}
You can run it here.
friend class MyClass; in the context of ::namespace1::MyInterface refers to the class ::namespace1::MyClass, which is a different class from ::namespace2::MyClass. (That's the whole point of namespaces, right?)
Change the friend declaration to read like this:
friend class ::namespace2::MyClass;
Note that this requires that the type ::namespace2::MyClass has already been declared, so you either need to forward-declare it (namespace namespace2 { class MyClass; }) or you need to make sure that the definition is included prior to the definition of ::namespace1::MyInterface.
(See this demo.)

C++ friend class of the same name in different levels of a nested namespace

Not sure if this is possible, but I have two classes of the same name in different levels of a nested namespace and I'd like to make the more shallow class a friend of the deeper class. Example:
In File1.h:
namespace A
{
class Foo
{
//stuff
};
}
In File2.h:
namespace A
{
namespace B
{
class Foo
{
friend class A::Foo; //Visual Studio says "Error: 'Foo' is not a member of 'A'"
};
}
}
Is this possible? If so, what is the proper syntax?
This code compiles ok when placed in one file (except that a ; is necessary after A::B::Foo class): IdeOne example.
So, the issue is in the code not included in the question text. Probably #include "File1.h" was forgotten in File2.h.
If you want to avoid including large header files into others, you need to at least forward declare your classes before using them:
namespace A
{
class Foo;
namespace B
{
class Foo
{
friend class A::Foo;
}
}
}

How to use forward declaration in the following scenario

I currently have the following two classes
class TOrder
{
public:
private:
.......
};
Now my other class is :
#include "TOrder.h"
namespace namespaceA
{
namespace namespaceB
{
class OrderDis
{
private:
TOrder* frmPointer;
.....
};
}
}
The above works fine the problem starts when I use an object of OrderDis in TOrder as such
#include <QMainWindow>
#include "OrderDis" //Added - Creates Problem
class TimedOrder
{
public:
.......
};
Any suggestion on how I could use forward declaration to resolve my issue ?
You could forward OrderDispatcher in TimeOrder.h
namespaceA
{
namespaceB
{
class OrderDispatcher;
}
}
class TimedOrder
{
//...
};
The forward declaration can be written as:
namespace A{ namespace B{ class OrderDispatcher; } }
As you only use a pointer to TimedOrder in the OrderDispatcher class, it can be solved by simply not including TimedOrder.h in the OrderDispatch.h file. Instead just declare the TimedOrder class:
class TimedOrder;
No need to muck about with namespaces and such then.
Note: You can't declare it in any of the namespaces, declare it instead where you now do your #include.