How can you access nested classes - c++

If I have something along the following lines
namespace mynamespace
{
class A
{
public:
class B{};
class C{};
};
int foo(B bObject, C cObject); //error
}
When compiled, B and C do not name types. Is there a way so that I can define functions in the namespace that use public nested classes (B and C) defined in Class A?

Use the scope resolution operator. B and C are declared in the scope of class A.
int foo(A::B bObject, A::C cObject);

Related

Acces private static member variable in namespace from another class C++

I have a problem. In the following example, there is a static private member variable called private_b of class A inside namespace a. And then I'm trying to access that variable from class B, which I have declared to be a friend of class A, but it doesn't work, with a compile error from GCC:
error: ‘B* a::A::private_b’ is private within this context
class B;
namespace a {
class A {
private:
static B* private_b;
friend class B;
};
B* A::private_b = nullptr;
}
class B {
public:
void foo() {
B* foo = a::A::private_b; // Error here
}
};
I don't understand why I can't access it, and how to get around this problem. I really want class A to be inside that namespace, and class B doesn't make sense to be inside that namespace. I searched for this on the internet, but couldn't find this exact case, or couldn't find a solution for this case.
friend class B; declared friendship with B in the same namespace a. You may want friend class ::B;.
Note, friend class B; does not refer to the global forward declaration class B, it has own forward declaration class B after the keyword friend.

Use friend class in gcc

I have this class that compiles in VC14, but when I try to compile in gcc 4.8.5, it doesn't work, I get "error: C was not declared in this scope".
class A
{
};
class B : public A
{
friend class C;
friend class D;
private:
class BB
{
std::list<C> c;
std::list<D> d;
};
};
class C : public B::BB
{
};
class D : public B::BB
{
};
I tried to forward declare "class C" before the definition of class B, but it gives me an error because it doesn't have the same definition as "class C : public B::BB", and I can't put that definition because BB is private... I'm not sure what to do.
Thanks
Forward declarations that use friend are different from other forward declarations. Writing friend class C; within the definition of B declares that there is a class called C in the enclosing namespace (i.e., the global namespace) but does not actually introduce the name C into that scope. Therefore, you can't write something like List<C> because the name C cannot be found. You should do this:
class C;
class D;
class B : public A
{
friend class C;
friend class D;
private:
class BB
{
List<C> c;
List<D> d;
}
}
The namespace-scope declarations actually introduce the names C and D into the global scope. Then, the friend declarations make those classes friends of B.
At the time you do
List<C> c;
List<D> d;
the compiler has no idea what C and D are--you haven't declared/implemented them yet!
You don't have to completely implement them, but you'll need to at least tell the compiler they're class that'll be implemented at some point. You can do that with:
class C;
class D;
Full working example (with some minor fixes like adding semicolons to make it compile): ideone

Private inheritance along class hierarchy, why friend is needed all along the hierarchy

Consider the following code:
#include <iostream>
class A{
friend class C;
int a{42};
};
class B: private A{
friend class C;
};
class C: private B {
public:
void print() {std::cout << a << '\n';}
};
int main() {
C c;
c.print();
}
According to this answer, the member variable A::a is "present" in all classes, but its visibility differ, i.e. is not visible in B or C unless we make B or C a friend of A. My question is why do I need to make C a friend of both A and B? I would've though the friend declaration in A would suffice. If I remove the friend class C; declaration from either A or B, the code fails to compile.
My question is why do I need to make C a friend of both A and B?
Without B declaring C has a friend, C wouldn't see B as inheriting A. Even though C would see A::a, it would not see B::a.
Indeed:
C inherits B, so anything public in B is accessible from C.
But B inherits privately from A. C being a friend of B makes C see this inheritance.
The access of A::a is private, so even though C sees A as its ancestor, it needs to be a friend of A to see A::a.

How to create an instance of a nested class that is defined outside of the enclosing one?

If I define a nested class and then create an instance like this:
class A
{
class B
{
...
};
B b;
};
everything is ok. But if I just declare B inside of A and define it outside, I can't create an instance of B, probably because the compiler don't know how much space the instance of B will need. But code is not much readable when you define a class inside another. Is there a way to make this work?
class A
{
class B;
B b;
};
class A::B
{
...
};
Simple, just define class B, then define an instance of it in A.
class B
{
}
class A
{
B memberB;
}
Or you can forward declare it:
class B;
class A
{
B memberB;
}
class B
{
}
Truly nested classes are rarely needed and not very useful at all.
When you use a class type as a member, the concrete class needs to be known. That's why your second case doesn't work. A work around is to use pointer to B:
#include <memory>
class A
{
class B;
std::unique_ptr<B> b;
};
class A::B
{
};

Befriending a class

I am trying to befriend a class in order for it to be able to reach a private constructor of it.
In some_file.h
class B;
namespace some_name {
class A {
public:
A() {}
private:
A (int x) {}
friend class ::B;
};
}
In other_file.h
#include "some_file"
namespace {
class B {
protected:
A* get_a(int x) { return new A(x); }
};
}
When compiling this code, I get -
error: 'some_name::A::A(int)' is private.
I now, it is private, this is why I befriended B.
What am I doing wrong here?
Can't you befriend your constructor?
Is there a namespace issue?
Thanks
Doing this:
namespace {
class B {
protected:
A* get_a(int x) { return new A(x) };
}
}
You're not putting B in the root (global) namespace but in an anonymous one.
So B can't be reached by ::B.
If you want B to be in the root (global) namespace, just don't enclose it with namespace at all. This should do the trick.
You only forward declared and friended a class B in the global namespace. Not a class B in a namespace whatever. You need to fully qualify the name of B.
Edit: Thanks ereOn.
I made a slight mistake. It's true that the reason that you've got a problem is because you've mis-declared and mis-referred-to B, but my original statement wasn't quite true. You need to take B out of the anonymous namespace - it's pointless being in a header anyway.
The problem is that you refer to B as ::B instead of B. Meaning, you're telling the compiler that B is a global name, but in fact it isn't: it's inside an anonymous namespace. You don't have to remove the anonymous namespace, it's just that it may not do what you expect it to do. Because the anonymous namespace is in a header it means what's inside that namespace is linked statically to any implementation file that includes the header. That's not very useful, because you hide nothing. You might as well remove that anonymous namespace.
Can't you befriend your constructor?
You can as shown below
struct B{
B();
void f();
};
struct A{
friend B::B();
private:
A(){}
};
B::B(){A a;} // fine
void B::f(){A a;} // error
int main(){
}