the following code will help me illustate my question to you directly:
#include<iostream>
class foo {
public:
class bar {
public:
bar(int a) : m_a(a) {}
void say() { std::cout << m_a << std::endl;}
private:
int m_a;
};
};
int main()
{
foo::bar b(3);
b.say();
}
as you see, to declare a object of class bar, we use the quite namespace like syntax "foo::bar", although actually bar is just an embebed class type in class foo. my question
is does the scope of a class itself is a namespace in c++?
No, a class is not a namespace. A class does form a declarative region, though.
You use the same syntax (the :: operator) to refer to names declared at class scope as you do to refer to names declared at namespace scope.
The class is not a namespace, it is a scope. You already used this term yourself. Namespace is a scope. Class is a scope as well. The :: operator is a scope resolution operator. Scope, not namespace, is the fundamental term that can act as a "common denominator" in this case. Scope is the reason why you can use the :: operator with both classes and namespaces on the left-hand side.
Another interesting distinction between classes and namespaces is that a namespace can be declared over multiple files and in multiple parts, but a class cannot. For example, you could do:
File a.hpp:
namespace Foo {
int memberA;
}
File b.hpp:
namespace Foo {
int memberB;
}
...
namespace Foo {
int memberC;
}
The scope of a class is not the same as the scope of a namespace. Classes can be templated, which affects the definitions in its scope. Classes can also have definitions that are only able to be used within that scope (private and protected).
The class name itself is not a namespace, although the scoping operator treats it as such, or almost as such anyways.
Related
I've two question about this code bellow:
namespace A { class window; }
void f(A::window);
namespace A
{
class window
{
private:
int a;
friend void ::f(window);
};
}
void f(A::window rhs)
{
std::cout << rhs.a << std::endl;
}
1) why do I need to qualify the member function f inside window class to be global by doing ::f(window) ?
2) why do I need to predeclare the function f(A::window) in this particular case, whereas when the class is not defined inside a namespace it's ok for the function to be declared after the function is declared a friend.
When you declare f() as a friend it's actually done in the enclosing namespace of the containing class (A in this case) if a forward declaration is not already present.
So this...
namespace A
{
class window
{
private:
friend void ::f(window);
};
}
essentially becomes this...
namespace A
{
class window;
void f(window);
class window
{
private:
friend void f(window);
};
}
Edit: Here is a snippet from the C++ standard that explicltly talks about this scenario:
Standard 7.3.1.2 / 3 :
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship).
As for 1), your function is not in the namespace, so you must use :: to tell the compiler to search it outside the namespace.
Otherwise, it will only look for function inside the namespace (that's why they exist). Koenig lookup doesn't apply here, as window class is inside the namespace.
not too sure about 2) though, but i bet it is related to 1).
1) because function f is declared and defined outside of the current namespace. If you moved the definition of your class into the same namespace as the function whether global or otherwise you wouldn't need to.
2) you always need to declare a function before it is referenced. Your class references the function with the friend statement.
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.
What does this symbol mean?
AirlineTicket::AirlineTicket()
:: is the scope resolution operator - used to qualify names. In this case it is used to separate the class AirlineTicket from the constructor AirlineTicket(), forming the qualified name AirlineTicket::AirlineTicket()
You use this whenever you need to be explicit with regards to what you're referring to. Some samples:
namespace foo {
class bar;
}
class bar;
using namespace foo;
Now you have to use the scope resolution operator to refer to a specific bar.
::foo::bar is a fully qualified name.
::bar is another fully qualified name. (:: first means "global namespace")
struct Base {
void foo();
};
struct Derived : Base {
void foo();
void bar() {
Derived::foo();
Base::foo();
}
};
This uses scope resolution to select specific versions of foo.
In C++ the :: is called the Scope Resolution Operator. It makes it clear to which namespace or class a symbol belongs.
It declares a namespace. So in AirlineTicket:: you can call all public functions of the AirlineTicket class and AirlineTicket() is the function in that namespace (in this case the constructor).
AirlineTicket is like a namespace for your class. You have to use it in the implementation of the constructor.
In a previous Q&A (How do I define friends in global namespace within another C++ namespace?), the solution was given for making a friend function definition within a namespace that refers to a function in the global namespace.
I have the same question for classes.
class CBaseSD;
namespace cb {
class CBase
{
friend class ::CBaseSD; // <-- this does not work!?
private:
int m_type;
public:
CBase(int t) : m_type(t) {};
};
}; // namespace cb
class CBaseSD
{
private:
cb::CBase* m_base;
public:
CBaseSD(cb::CBase* base) : m_base(base) {};
int* getTypePtr()
{ return &(m_base->m_type); };
};
If I put CBaseSD into a namespace, it works; e.g.,
friend class SD::CBaseSD;
but I have not found an incantation that works for the global namespace.
I am compiling with g++ 4.1.2.
As stated in some of the comments below the question, the code in the question appears to work with me (Linux-Ubuntu-16.04, gcc version 5.4.0), provided that the friend class was forward-declared.
In pursuit of an answer, I came across this post that both explains proper technique for making friend class of a global namespace and answers why it needs to be declared the way it does. It is a nice thread because it references the standard.
As stated earlier, the class of a global namespace must be forward declared before it can be used as a friend class to a class within a namespace.
add the forward declaration like below
namespace {
// anonymous namespace declaration
class CBaseSD;
}
then your normal
friend class CBaseSD;// no need of ::
works in CBase
Is there a more succinct way to define a class in a namespace than this:
namespace ns { class A {}; }
I was hoping something like class ns::A {}; would work, but alas not.
You're close, you can forward declare the class in the namespace and then define it outside if you want:
namespace ns {
class A; // just tell the compiler to expect a class def
}
class ns::A {
// define here
};
What you cannot do is define the class in the namespace without members and then define the class again outside of the namespace. That violates the One Definition Rule (or somesuch nonsense).
You can do that, but it's not really more succint.
namespace ns {
class A;
}
class ns::A {
};
Or
namespace ns {
class B;
}
using ns::B;
class B {
};
The section you should be reading is this:
7.3.1.2 Namespace member definitions
3 Every name first declared in a namespace is a member of that namespace.[...]
Note the term -- declaration so D.Shawley (and his example) is correct.
No you can't. To quote the C++ standard, section 3.3.5:
A name declared outside all named or
unnamed namespaces (7.3), blocks
(6.3), fun (8.3.5), function
definitions (8.4) and classes (clause
9) has global namespace scope
So the declaration must be inside a namespace block - the definition can of course be outside it.