10

Please see my first attempt at answering this . I neglected to tell the whole story before in an attempt to simplify things. Turns out my example works! Sorry.

The whole story is that this is a library the contains a class in one file and the main in another file, all linked into my library. The library is providing the basis for a Process Framework, which is why the main is in the library and not the process.

Below is a stripped down version of what I have.

pf.hpp

using namespace std;

namespace MyNamespace
{
  class ProcessManager
  {
  public:
    friend int main(int argc, char** argv);
  private:
    void test();
  };
};

pf.cpp

#include "pf.h"

namespace MyNamespace
{
  ProcessManager::test()
  {
    cout << "My friend has accessed my member" << endl;
  }
};

pfmain.cpp

#include "pf.hpp"

int main(int argc, char** argv)
{
   ProcessManager pm;

   pm.test();
}

Note that this fails on the compilation of the library

What I have tried is:

  • Moving the friend all over the place
  • Making the friend reference to main use global scope (e.g. ::main)
  • Making friend and main declarations use global scope

What am I missing?

Thanks!

Community
  • 1
  • 1
Jaime
  • 1,182
  • 2
  • 12
  • 29

4 Answers4

12

Just declare the main outside the MyNamespace and specify global namespace :: in friend statement

//in header file of ProcessManager
//your pf.h

int main(int argc, char** argv);

namespace MyNamespace
{
  class ProcessManager
  {
  public:
    friend int ::main(int argc, char** argv);
  private:
    void test();
  };
};
parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85
  • I don't see why the compiler wouldn't see the main from pfmain.cpp in my case, but this works. Thanks! – Jaime Dec 23 '11 at 18:29
  • Previous attempts would show the error "error: 'int main(int, char**)' should have been declared inside '::'" which should have been telling enough, but I would never have expected the compiler not to check the other .o files for the symbol considering how the headers are setup.. – Jaime Dec 23 '11 at 18:33
  • @Jaime in C++ main() must be declared in the global namespace. The name however is not reserved and may be used for member functions and in namespaces among other places. – Captain Obvlious Dec 23 '11 at 19:23
2

@parapura provided a solution, but doesn't explain why you first have to declare main in the global scope.

§7.3.1.2 [namespace.memdef] p3

[...] 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. [...]

So with that in mind, your code would look somewhat like this:

namespace MyNamespace
{ // MyNamespace is the innermost enclosing namespace
  // 'main' from the friend declaration is treated
  // as if it was a member of 'MyNamespace'
  int main(int argc, char** argv);

  class ProcessManager
  {
  public:
    friend int main(int argc, char** argv);
  private:
    void test();
  };
};

Now it should be clear why the global main function wasn't your friend.

Xeo
  • 129,499
  • 52
  • 291
  • 397
0

A common answer might be to provide an "application" singleton class, like e.g. QApplication in Qt, an reduce your main to something like

int main (int argc, char** argv) {
    YourApplication app (argc, argv);
    return app.execute();
}

Then you reduce your friendness concern to class YourApplication vs your other classes, and you know how to do that.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • The class is actually already a singleton, I just didn't show that part. Having a singleton doesn't resolve the issue though.. – Jaime Dec 23 '11 at 18:30
0

I don't think you actually want to do what you are doing. This really seems like a hack and a design problem. If you really want to expose the internals of your class in some specialized circumstance, you could make an accessor class which is also defined inside your library.

Something like this might work (may need appropriate forward declarations, etc. -- this is just a starting point):

class ProcessManagerAccessor
{
public:
    ProcessManagerAccessor(ProcessManager & pm) : pm_(pm) { }

    // add public methods to expose internals
    void test() { pm_.test(); }

private:
    ProcessManager & pm_;
};

class ProcessManager
{
public:
    friend class ProcessManagerAccessor;

    // ...
};

// ...

ProcessManager pm;
ProcessManagerAccessor pma(pm);
pma.test();
bobbymcr
  • 23,769
  • 3
  • 56
  • 67
  • "In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out." – bobbymcr Dec 23 '11 at 18:38
  • I don't see this as any different than giving main access. The issue is that my class is a Singleton, instantiated without params, but I need to set some state in the main before I give control over to the derived class of ProcessManager. I don't want these methods to be accessible by the derived class. – Jaime Dec 23 '11 at 18:38
  • the "test" method is just an example... its not actually used for testing – Jaime Dec 23 '11 at 18:40
  • Giving `main` access sounds like a sledgehammer solution -- that means for any main function all your privates become public. There are many (self-imposed?) design issues here. If you have untestable code, the best solution is to just make it testable by design. A full discussion of this is likely beyond the scope of this stackoverflow question but it would be well worth exploring the standard techniques for getting some testability in place. Feathers wrote a whole book on this -- a small summary is here: http://www.objectmentor.com/resources/articles/WorkingEffectivelyWithLegacyCode.pdf – bobbymcr Dec 23 '11 at 18:44
  • Main is created by me and controlled by me in the library, not by the deriver of ProcessManager, which is where the process is located. Granted you could trick the compiler into picking your own main and may be able to get it to give your main escalated privileges, but I'm not going for that level of integrity at this moment. – Jaime Dec 23 '11 at 18:47
  • Believe me that I would prefer to say that main, or even the accessor only has access to these 3 or 4 protected members. But as far as I know there is no way to do that in C++. – Jaime Dec 23 '11 at 18:51
  • What you can do is have a publicly defined interface for the "internal" portion of your class and create an inner private implementation class for the default implementation (no one outside the class would be able to see it). You can then allow overriding this default implementation with another interface by allowing the caller to pass it in (and the default constructor could simply pass the private impl by default). This allows writing code which can override the functionality if needed without excessive exposure (e.g. unit tests could "sense" the internal function calls within the class). – bobbymcr Dec 23 '11 at 19:10
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/6094/discussion-between-bobbymcr-and-jaime) – bobbymcr Dec 23 '11 at 19:11
  • I agree with bobbymcr here; main seems like putting too strong a force on the class; it's too specifically placed in the ecosystem of an application and consequently too uncertain a presence to directly friend. Best to friend something of a buffer around the boundaries. – Mihai Danila May 05 '14 at 15:14