0

That's my header:

#ifndef MYCLASSES_H_
#define MYCLASSES_H_

#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))

namespace mynamespace {

class A
{
    class B
    {
        class C
        {
            void doStuff(B *pB);
        }

        static const C SOME_ARRAY[];
        static const int SOME_ARRAY_COUNT;
    }
}

} //namespace mynamespace
#endif /* MYCLASSES_H_ */

And that's the CPP:

#include "myclasses.h"

namespace mynamespace {

void A::B::C::doStuff(A::B *pB)
{
    /* ... */
}

const A::B::C A::B::SOME_ARRAY[] = {
    /*...*/
};

const A::B::SOME_ARRAY_COUNT = ARRAY_SIZE(

} //namespace mynamespace

What shall I do to make the definitions in the .CPP file have shorter names? It's incredibly cumbersome.

Albus Dumbledore
  • 12,368
  • 23
  • 64
  • 105
  • Do you really need 3 inner classes? It is not better just to use inheritance? – Pih Jan 31 '12 at 09:50
  • 2
    Man walks into a doctor. He says "Doctor, my head hurts when I bang it against the wall". Doctor says: "Don't bang your head on the wall and your head will stop hurting". Since B and C are in a private section of class A the world can not see them. So no need to nest them inside A just make them non visable to the outside world. The easy way to do this is to put them in an anonymous namespace inside the source file. – Martin York Jan 31 '12 at 09:52
  • @LokiAstari I was about to write that. btw where is the "convert a comment to an answer" button? ;) – BЈовић Jan 31 '12 at 09:55
  • 1
    You should not really use that array size macro, it will fail when x is a pointer (or will suddently decay into one). Use a ` template size_t array_size(T(&) [N] ) { return N; }` which will error out when not passed an actual array. – PlasmaHH Jan 31 '12 at 09:55
  • You shouldn't use reserved names for include guards, or [this](http://stackoverflow.com/questions/3345159/) might happen. – Mike Seymour Jan 31 '12 at 09:57
  • @MikeSeymour My mistake, sry. – Albus Dumbledore Jan 31 '12 at 10:05
  • @PlasmaHH, Thanks, I'll remember that. I'm generally cautious not to use it on decayed arrays, but didn't know about your solution. :-) – Albus Dumbledore Jan 31 '12 at 10:07
  • @LokiAstari, would you elaborate on your suggestion. Thanks! – Albus Dumbledore Jan 31 '12 at 10:08
  • @AlbusDumbledore: Unless it uses # or ## there are seldom cases where a value producing function style macro can not be replaced by a template, and it is often worth searching for a solution. – PlasmaHH Jan 31 '12 at 10:12

7 Answers7

3

Man walks into a doctor. He says "Doctor, my head hurts when I bang it against the wall". Doctor says: "Don't bang your head on the wall and your head will stop hurting".

Since B and C are in a private section of class A the world can not see them.

So there is no need to nest them inside A just make them non visible to the outside world.
The easy way to do this is to put them in an anonymous namespace inside the source file.

#ifndef MYCLASSES_H_
#define MYCLASSES_H_

#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))

namespace mynamespace {

class A
{
}

} //namespace mynamespace
#endif /* MYCLASSES_H_ */

And that's the CPP:

#include "myclasses.h"


namespace
{
    // This is an anonymouse namespace
    // It does not export it symbols outside the compilation unit.
    // So only A should be able to see them
    class B
    {
            static const C SOME_ARRAY[];
            static const int SOME_ARRAY_COUNT;
    };
    class C
    {
            void doStuff(B *pB);
    };
}
void C::doStuff(B *pB)
{
    /* ... */
}

const C B::SOME_ARRAY[] = {
    /*...*/
};

const B::SOME_ARRAY_COUNT = ARRAY_SIZE(
Martin York
  • 257,169
  • 86
  • 333
  • 562
2

May be try to use a using declaration:

using A::B;
Dmitriy
  • 5,357
  • 8
  • 45
  • 57
2

typedefs let you shorten naming:

#include "MYCLASSES.h"

namespace mynamespace {

typedef A::B b;
typedef b::C c;

void c::doStuff(b *pB)
{
    /* ... */
}

const c b::SOME_ARRAY[100] = {
    /*...*/
};

const int b::SOME_ARRAY_COUNT = ARRAY_SIZE(SOME_ARRAY);

} //namespace mynamespace
CapelliC
  • 59,646
  • 5
  • 47
  • 90
0

Unfortunately, you cannot. This is just a syntactic property of C++.

As a consequence, you should prefer flat nesting hierarchies in C++: don’t nest classes endlessly, put them into the same upper-level namespace. In other languages that’s a big no-no since it leaks implementation details to the public interface.1

Not so in C++, since here you have distinct compilation units to enforce encapsulation and information hiding. So flat hierarchies are actually fine for the most part.


1 But even in other languages three nested classes is pushing the envelope.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
0

There's no clean way to do it. If it were nested namespaces, you could use using or namespace aliasing.

Since it's classes, the best I can think of is:

#define B A::B
#define C B::C

but it's definetely not clean. I wouldn't do it.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

There is no real way of doing this other than something like:

    #define AB mynamespace::A::B;

To allow this:

    mynamespace::A::B::C myobj;

Note that many programmers (myself included) think that this is bad practice because it is not obvious what AB is.

To become:

    AB::C myobj;

You cannot use 'using' for classes, only namespaces. So in a cpp file you can do:

    using mynamespace;
    A::B::C myobj;

But not:

    using mynamespace::A::B;
    C myobj;

Generally though, many people agree that best practice is to fully qualify names.

0

Alternatively you can write the implementations in the header files. It's a really bad practice, though.

Alexander
  • 8,117
  • 1
  • 35
  • 46