views:

138

answers:

4

Hi all,

My initial suspicion was that there was a circular dependency in my code and went through http://stackoverflow.com/questions/625799/resolve-circular-dependencies-in-c. But this hasn't resolved my compilation errors. Here is the code with 3 classes - A, G & N.

//A.h

#ifndef A_H_
#define A_H_

class com::xxxx::test::G;

namespace com { namespace xxxx { namespace test {

class A {

public:
 A();
 ~A();
 void method1(void);

private:
 G* g;
};

} } }

#endif /* A_H_ */


//A.cpp

#include "A.h"
#include "G.h"

namespace com { namespace xxxx { namespace test {

A::A() {
 g = new com::xxxx::test::G();
}

A::~A() {
 delete g;
}

void A::method1() {
 g->method2(*this);
}

} } }


//G.h

#ifndef G_H_
#define G_H_

class com::xxxx::test::A;

namespace com { namespace xxxx { namespace test {

class G {
public:
 void method2(const A&);
};

} } }

#endif /* G_H_ */


//G.cpp

#include "N.h"

namespace com { namespace xxxx { namespace test {

void G::method2(const A& a) {
 N n(a, *this);
}

} } }


//N.h

#ifndef N_H_
#define N_H_

#include "A.h"
#include "G.h"

namespace com { namespace xxxx { namespace test {

class N {
public:
 N(const A& obj1, const G& obj2) : a(obj1), g(obj2) {}
 void method3(void);

private:
 A a;
 G g;
};

} } }

#endif /* N_H_ */

I am getting about 10 compilation errors in A.h and A.cpp I am listing the compilation errors below:

./src/A.h:11: error: 'com' has not been declared
../src/A.h:25: error: ISO C++ forbids declaration of 'G' with no type
../src/A.h:25: error: invalid use of '::'
../src/A.h:25: error: expected ';' before '*' token
../src/A.cpp: In constructor 'com::xxxx::test::A::A()':
../src/A.cpp:16: error: 'g' was not declared in this scope
../src/A.cpp: In destructor 'com::xxxx::test::A::~A()':
../src/A.cpp:20: error: 'g' was not declared in this scope
../src/A.cpp: In member function 'void com::xxxx::test::A::method1()':
../src/A.cpp:24: error: 'g' was not declared in this scope

What could be the mistake in the above code?

Thank you in advance,
Regards,
Raghava.

+9  A: 

The forward declaration

 class com::xxxx::test::G;

is illegal. Members of a namespace must be declared within it.

namespace com { namespace xxxx { namespace test {
    class G;

Also, as Kenny says, namespaces aren't used like this in C++. Unless your project is distributed as a library or is of reasonably large size (dozens of files minimum), you probably don't need your own namespace.

Potatoswatter
@Potatoswatter: What's that critique about namespaces about? I don't get it.
sbi
@sbi: it encourages you to just put `using namespace` everywhere, and then you end up with everything in the same namespace. A simple, flat structure (like the entire std lib being in namespace `std`) actually means that people will *respect* the namespace, rather than just try to get rid of it, like you do in .NET or Java where you have deep, verbose heirarchies.
jalf
@jalf: So the critique is about so many nested namespaces? Well, i can somewhat relate to that, although [I firmly believe in explicitly spelling out all namespaces](http://stackoverflow.com/questions/2879555/c-stl-how-to-write-wrappers-for-cout-cerr-cin-and-endl/2880136#2880136) and think that this only seems a problem for so many developers because all books and articles omit this.
sbi
@sbi: Yup. I'm not sure of the ins and outs of creating a namespace for the non-modular part of a program, but `main` can't be in one.
Potatoswatter
@Potatoswatter: That solved the issue. Thank you. I do come from Java world and started working on this C++ project last month. However, I did not understand whether having hierarchical namespaces is bad or having them at all? I try to follow the best practices as much as possible and namespaces I thought were supposed to be a good practice to avoid naming conflicts - for big or small projects. Also, I do understand the reason for explicitly putting in entire namespace while referencing a class and I follow that.
Raghava
@Raghava: Hierarchical namespaces are useful, and it's customary to hide implementation details in a nested namespace named `detail`. But namespaces don't serve a purpose besides preventing conflicts. Java, by contrast, has a kind of unified system for naming source trees and identifying software vendors in class names.
Potatoswatter
@Potatoswatter: aah, so are saying that in C++ it is not a practice to identify vendors. If I add something to the boost library while working for my organization then those classes would still have boost namespace instead of the organization is it? But even if that is the case, people have come up with the organization naming convention to ensure unique names isn't it.
Raghava
@Raghava: You cannot add anything to the Boost namespace. Any external library's namespace should be considered reserved. It's reasonable to have a top-level namespace for your organization, particularly if it distributes multiple proprietary libraries, like Adobe. (Edit: do they use nested spaces or just flat?) But code which is not a library should generally not be in a namespace. And what does the toplevel namespace `com` really achieve?
Potatoswatter
@Raghava: Um, Potatoswatter's last comment might have been misleading. You _can_ add something to boost's namespace. Namespaces are open, and can be added to. However, that doesn't mean you _should_. The boost libraries are a set of very thoroughly peer-reviewed, to-class libraries. Anything being in namespace `boost` lives off that shine. If your code didn't undergo the strict review process, you shouldn't use their namespace.
sbi
@Potatoswatter: I have been in companies where they had a company's top-level namespace and then further sub-namespaces for different libraries, projects and applications. I see nothing wrong with that. I'd be surprised if a company as big as Adobe had all their stuff in the same namespace. With company code standard in place, that would be a sure recipe for many name clashes.
sbi
Raghava
+2  A: 

Is class com::xxxx::test::G; legal in C++ ? I would have written:

namespace com {
   namespace xxxx {
       namespace test {
          class G;
       }
   }
}
tibur
+4  A: 

When the compiler tries to compile a.cop, the first thing it encounters (included from a.h) is this:

class com::xxxx::test::G;

At this point there is nothing to tell the compiler what exactly com, xxxx and test are. Each of these can be either a namespace or a class. This also means that G is unclear, which leads to all other errors.

Franci Penov
@Franci: Thank you, that was a good explanation
Raghava
+2  A: 

As others have pointed out, using class com::xxxx::test::G; is illegal.

The simpler conversion is (preserving inline-ness):

namespace com { namespace xxxx { namespace test { class G; } } }

I prefer this way of forward declaring because "grepping" does not show scope, whereas this syntax immediately lay it out for all to see.

Matthieu M.